Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignoring file that is a broken symbolic link produces "[Errno 2] No such file or directory" #399

Closed
thomasdstewart opened this issue Aug 5, 2021 · 11 comments · Fixed by #654 · May be fixed by #646
Closed

Ignoring file that is a broken symbolic link produces "[Errno 2] No such file or directory" #399

thomasdstewart opened this issue Aug 5, 2021 · 11 comments · Fixed by #654 · May be fixed by #646

Comments

@thomasdstewart
Copy link

Hi,

When running yamllint on a directory of files if a file is a broken symbolic link it produces "[Errno 2] No such file or directory" even if the file is set to be ignored. I was able to reproduce using latest yamllint[0] along with a small test environment[1] and by running "yamllint ." to show the error[2].

Kind Regards
Tom

[0]

$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install yamllint
$ yamllint --version
yamllint 1.26.2
$

[1]

$ mkdir test; cd test
$ ln -s not_there ignore_file.yaml
$ ls -l ignore_file.yaml 
lrwxrwxrwx 1 thomas thomas 9 Aug  5 10:45 ignore_file.yaml -> not_there
$ cat .yamllint 
---
extends: default

ignore: |
  ignore_file.yaml
$

[2]

$ yamllint .
[Errno 2] No such file or directory: './ignore_file.yaml'
$
@adrienverge
Copy link
Owner

Hello @thomasdstewart, thanks for the report.

I can confirm the problem. Any clean contribution to fix this (and include non-regression tests) would be welcome!

Out of curiosity: do you have a use-case where you have broken .yaml symlinks, and want to keep them?

@thomasdstewart
Copy link
Author

Hi @adrienverge,

Indeed filing an issue is a bit strong wording for what is more like a feature request from some random on the Internet and by far not a demand for you to fix. :)

Apologies, yes some context would have been useful. I've got a public git repo with a set of Ansible playbooks, roles, templates, vars, vaults, etc. The vault files are in the standard locations but are symlinks to the real files in a private repo, eg separating the public and private data. eg:

$ file group_vars/all/vault.yml
group_vars/all/vault.yml: symbolic link to ../../safe/group_vars/all/vault.yml
$ file safe/group_vars/all/vault.yml
safe/group_vars/all/vault.yml: ASCII text
$

To side step this, in my CI I just swapped out "yamllint ." with: find . -type f ( -name ".yml" -o -name ".yaml" ) ! -name 'vault.yml' | xargs yamllint

Kind Regards
Tom

@thomasdstewart
Copy link
Author

What I didn't really funny understand is that that it is an exit(-1) exception at cli.py:207. It's not skipping over the file, it's completely stopping and so further files are not scanned. I was thinking it probably best for is_file_ignored() to be called before io.open() is called, as that is where the exception occurs rather than currently that is called as part of linter.run()? Further more FileNotFoundError should probably produce a warning about it as well? eg

diff --git a/yamllint/cli.py b/yamllint/cli.py
index cb87350..788cd3b 100644
--- a/yamllint/cli.py
+++ b/yamllint/cli.py
@@ -204,6 +204,8 @@ def run(argv=None):
         try:
             with io.open(file, newline='') as f:
                 problems = linter.run(f, conf, filepath)
+        except FileNotFoundError as e:
+            print(e, file=sys.stderr)
         except EnvironmentError as e:
             print(e, file=sys.stderr)
             sys.exit(-1)

Produces:

$ python3 -m yamllint yamllint/t
yamllint/t/vault.yaml
  2:2       warning  missing starting space in comment  (comments)

[Errno 2] No such file or directory: 'yamllint/t/nonexistant.yml'
yamllint/t/valid.yaml
  3:2       warning  missing starting space in comment  (comments)

Rather than:

$ yamllint t
t/vault.yaml
  2:2       warning  missing starting space in comment  (comments)

[Errno 2] No such file or directory: 't/nonexistant.yml'

@noonedeadpunk
Copy link

noonedeadpunk commented Dec 2, 2022

Out of curiosity: do you have a use-case where you have broken .yaml symlinks, and want to keep them?

My usecase are git submodules as symlink is aimed to be pointed to the content inside submodule but I don't really want to test what's in that another included repo, since it has it's own testing.

So basically implementing option not to follow symlinks at all would be great.

@tom0010
Copy link

tom0010 commented Apr 14, 2023

Out of curiosity: do you have a use-case where you have broken .yaml symlinks, and want to keep them?

My usecase are git submodules as symlink is aimed to be pointed to the content inside submodule but I don't really want to test what's in that another included repo, since it has it's own testing.

So basically implementing option not to follow symlinks at all would be great.

We have exactly this too, I ended up pulling down the submodules for now, but would be great to see this implemented.

@TomyLobo
Copy link

TomyLobo commented Jul 13, 2023

I have another use case:
To indicate that a file is being modified by another instance, Midnight Commander's editor creates symlinks named ".#<filename>", targetted at "<user>@<FQDN>.<PID>".
I'd like to exclude those as well.

@james-powis
Copy link

For what it is worth, its a simple fix... Submitted a PR #646

@benformosa
Copy link

benformosa commented Jan 17, 2024

I'm also having this issue.
My repo has a symlink to a file in a submodule, which isn't present when I run yamllint in CI.

I've added an ignore rule for the symlink, and use this command: yamllint --list-files . | xargs yamllint

@james-powis
Copy link

james-powis commented Jan 17, 2024

I think it is worth arguing that yamllint traversing symlinks, in general, should be configurable... In one use case the same few yaml files are symlinked into thousands of directories, due to being named the same as the source file, i cannot exclude, and the result is yamllint runs against each and every symlink, effectively linting the same file thousands of times.

Where the broken symlink becomes problematic is when a specific directory is no longer needed, it is preserved by moving it into a different directory with a different relative depth but still within scope of the root of the target when running yamllint. As a result, we hit this bug. I have monkeypatched yamllint with the changes in PR #646 however i also had to extend it further to skip over symllinks.

I have created #647 to demonstrate how complex it can be to handle symlinks well, in a dry manner. Ultimately my though is to entirely exclude symlinks and if so desired individually target the target file instead of the symlink.

@adrienverge
Copy link
Owner

I've added an ignore rule for the symlink, and use this command: yamllint --list-files . | xargs yamllint

Nice trick 👍 (while waiting for a proper fix)

Where the broken symlink becomes problematic is when a specific directory is no longer needed, it is preserved by moving it into a different directory with a different relative depth but still within scope of the root of the target when running yamllint. As a result, we hit this bug.

I agree this should be fixed. Thanks for your pull request.

@MrMegaNova
Copy link

Thanks for the PR, I hope #646 gonna be merged ASAP

adrienverge added a commit that referenced this issue Feb 6, 2024
Before this commit, yamllint would output "[Errno 2] No such file or
directory" when running on a directory which contained a broken symbolic
link, even if the file is set to be ignored in yamllint configuration.

This commit fixes that, and adds corresponding tests.

As a side effect this changes `yamllint.linter.run(stream, config)`, so
tools that would use this API need to filter ignored files beforehand.

Fixes #399
adrienverge added a commit that referenced this issue Feb 15, 2024
Before this commit, yamllint would output "[Errno 2] No such file or
directory" when running on a directory which contained a broken symbolic
link, even if the file is set to be ignored in yamllint configuration.

This commit fixes that, and adds corresponding tests.

As a side effect this changes `yamllint.linter.run(stream, config)`, so
tools that would use this API need to filter ignored files beforehand.

Fixes #399
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
8 participants