From c7d04ad7e74e1a06221618f0934db4e7902d50d8 Mon Sep 17 00:00:00 2001 From: sedrubal Date: Sun, 28 May 2017 22:50:02 +0200 Subject: [PATCH] Add support for exclusion patterns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add argument -e/--e PATTERN to exclude files or directories when walking through a file system tree and searching for yaml files. E.g. ``` yamllint -e s . ``` in this tree: ``` . ├── a.yaml ├── empty-dir ├── empty.yml ├── non-ascii │   └── utf-8 ├── no-yaml.json ├── s │   └── s │   └── s │   └── s │   └── s │   └── s │   └── s │   └── s │   └── s │   └── s │   └── s │   └── s │   └── s │   └── s │   └── s │   └── file.yaml ├── sub │   └── ok.yaml └── warn.yaml ``` ignores the directory `./s/`. And `yamllint -e warn.yaml -e non-ascii/utf-8 .` ignores both, `warn.yaml` and `non-ascii/utf-8`. --- yamllint/cli.py | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/yamllint/cli.py b/yamllint/cli.py index 1a22f73..cc89830 100644 --- a/yamllint/cli.py +++ b/yamllint/cli.py @@ -17,6 +17,7 @@ from __future__ import print_function import os.path import sys +from fnmatch import fnmatch import argparse @@ -26,14 +27,35 @@ from yamllint.linter import PROBLEM_LEVELS from yamllint import linter -def find_files_recursively(items): +def find_files_recursively(items, exclude_patterns): + exclude_patterns = { + os.path.normpath(os.path.expanduser(pattern)) + for pattern in exclude_patterns or () + } + def is_excluded(path, exclude_patterns): + """Return True if any pattern in exclude_patterns matches path.""" + path = os.path.normpath(path) + return any((fnmatch(path, pattern) for pattern in exclude_patterns)) + for item in items: - if os.path.isdir(item): - for root, dirnames, filenames in os.walk(item): - for filename in [f for f in filenames - if f.endswith(('.yml', '.yaml'))]: - yield os.path.join(root, filename) + if is_excluded(os.path.expanduser(item), exclude_patterns): + # excluded file or directory + continue + elif os.path.isdir(item): + # not excluded directory + for root, dirnames, filenames in os.walk(item, topdown=True): + for dirname in dirnames: + if is_excluded( + os.path.join(root, dirname), exclude_patterns): + dirnames.remove(dirname) # won't be visited later + for filename in (f for f in filenames + if f.endswith(('.yml', '.yaml'))): + yaml_file = os.path.join(root, filename) + if not is_excluded(yaml_file, exclude_patterns): + yield yaml_file + else: + # not excluded file yield item @@ -90,6 +112,9 @@ def run(argv=None): action='store_true', help='return non-zero exit code on warnings ' 'as well as errors') + parser.add_argument('-e', '--exclude', metavar='FILE_OR_DIR', + action="append", + help="exclude files or directories") parser.add_argument('-v', '--version', action='version', version='%s %s' % (APP_NAME, APP_VERSION)) @@ -128,7 +153,7 @@ def run(argv=None): max_level = 0 - for file in find_files_recursively(args.files): + for file in find_files_recursively(args.files, args.exclude): try: first = True with open(file) as f: