Broken Symbolic Links Cause FileNotFoundError
If a broken symbolic link exists only in one directory, diffoscope fails with a `FileNotFoundError`. ## Minimal Test Case for Reproduction Start from any empty directory and run the following to generate the minimal test case: ```shell mkdir my-dir-1 my-dir-2 (cd my-dir-1/ && ln -s /my-non-existent-absolute-path my-non-existent-absolute-path) ``` Now run diffoscope without any arguments, i.e. `diffoscope my-dir-1/ my-dir-2/`. Also attempted with `--exclude-directory-metadata yes`, appears to make no difference. ## Observed Behavior Diffoscope terminates with exit code 1 and displays the following stack trace: ``` Traceback (most recent call last):######################################| 100% ETA: 0:00:00 File "/usr/local/bin/diffoscope", line 8, in <module> sys.exit(main()) File "/usr/local/lib/python3.8/dist-packages/diffoscope/main.py", line 746, in main sys.exit(run_diffoscope(parsed_args)) File "/usr/local/lib/python3.8/dist-packages/diffoscope/main.py", line 700, in run_diffoscope difference = compare_root_paths(path1, path2) File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/utils/compare.py", line 63, in compare_root_paths return compare_directories(path1, path2) File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/directory.py", line 222, in compare_directories return FilesystemDirectory(path1).compare(FilesystemDirectory(path2)) File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/directory.py", line 285, in compare differences.extend(my_container.compare(other_container)) File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/utils/container.py", line 164, in comparisons for my_name, other_name, score in self.perform_fuzzy_matching( File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/utils/fuzzy.py", line 45, in perform_fuzzy_matching if file1.is_directory() or not file1.fuzzy_hash: File "/usr/local/lib/python3.8/dist-packages/diffoscope/comparators/utils/file.py", line 342, in fuzzy_hash if os.stat(self.path).st_size >= 512: FileNotFoundError: [Errno 2] No such file or directory: 'my-dir-1/my-non-existent-absolute-path' ``` ## Expected Behavior Diffoscope should terminate normally and show the missing (from the perspective of `my-dir-2`) symbolic link in the `file list`. This suggestion is based on the following observation: If we add an identical broken symbolic link to the second directory, i.e. by running `(cd my-dir-2/ && ln -s /my-non-existent-absolute-path my-non-existent-absolute-path)`, diffoscope will simply report the difference of the stat calls of the symbolic links. In other words, it does not attempt to deference the links and thus does not care that they are broken. ## Environment and Versions This error occurred for us with the latest diffoscope version (`177` as of writing), running python `3.8.10` on Ubuntu `20.04`
issue