diff options
Diffstat (limited to 'python/tidy/servo_tidy/tidy.py')
-rw-r--r-- | python/tidy/servo_tidy/tidy.py | 42 |
1 files changed, 39 insertions, 3 deletions
diff --git a/python/tidy/servo_tidy/tidy.py b/python/tidy/servo_tidy/tidy.py index 873af6ca22b..34eea7f882a 100644 --- a/python/tidy/servo_tidy/tidy.py +++ b/python/tidy/servo_tidy/tidy.py @@ -26,7 +26,7 @@ MAX_LICENSE_LINESPAN = max(len(license.splitlines()) for license in licenses) # File patterns to include in the non-WPT tidy check. FILE_PATTERNS_TO_CHECK = ["*.rs", "*.rc", "*.cpp", "*.c", - "*.h", "Cargo.lock", "*.py", + "*.h", "Cargo.lock", "*.py", "*.sh", "*.toml", "*.webidl", "*.json"] # File patterns that are ignored for all tidy and lint checks. @@ -43,6 +43,7 @@ IGNORED_FILES = [ os.path.join(".", "tests", "wpt", "metadata", "MANIFEST.json"), os.path.join(".", "tests", "wpt", "metadata-css", "MANIFEST.json"), os.path.join(".", "components", "script", "dom", "webidls", "ForceTouchEvent.webidl"), + os.path.join(".", "support", "android", "openssl.sh"), # FIXME(pcwalton, #11679): This is a workaround for a tidy error on the quoted string # `"__TEXT,_info_plist"` inside an attribute. os.path.join(".", "components", "servo", "platform", "macos", "mod.rs"), @@ -169,7 +170,11 @@ def check_modeline(file_name, lines): def check_length(file_name, idx, line): if file_name.endswith(".lock") or file_name.endswith(".json"): raise StopIteration - max_length = 120 + # Prefer shorter lines when shell scripting. + if file_name.endswith(".sh"): + max_length = 80 + else: + max_length = 120 if len(line.rstrip('\n')) > max_length: yield (idx + 1, "Line is longer than %d characters" % max_length) @@ -306,6 +311,36 @@ def check_toml(file_name, lines): yield (0, ".toml file should contain a valid license.") +def check_shell(file_name, lines): + if not file_name.endswith(".sh"): + raise StopIteration + + shebang = "#!/usr/bin/env bash" + required_options = {"set -o errexit", "set -o nounset", "set -o pipefail"} + + if len(lines) == 0: + yield (0, 'script is an empty file') + else: + if lines[0].rstrip() != shebang: + yield (1, 'script does not have shebang "{}"'.format(shebang)) + + for idx in range(1, len(lines)): + stripped = lines[idx].rstrip() + + # Comments or blank lines are ignored. (Trailing whitespace is caught with a separate linter.) + if lines[idx].startswith("#") or stripped == "": + continue + elif stripped in required_options: + required_options.remove(stripped) + else: + # The first non-comment, non-whitespace, non-option line is the first "real" line of the script. + # The shebang, options, etc. must come before this. + if len(required_options) != 0: + formatted = ['"{}"'.format(opt) for opt in required_options] + yield (idx + 1, "script is missing options {}".format(", ".join(formatted))) + break + + def check_rust(file_name, lines): if not file_name.endswith(".rs") or \ file_name.endswith(".mako.rs") or \ @@ -694,7 +729,8 @@ def scan(only_changed_files=False, progress=True): # standard checks files_to_check = filter_files('.', only_changed_files, progress) checking_functions = (check_flake8, check_lock, check_webidl_spec, check_json) - line_checking_functions = (check_license, check_by_line, check_toml, check_rust, check_spec, check_modeline) + line_checking_functions = (check_license, check_by_line, check_toml, check_shell, + check_rust, check_spec, check_modeline) errors = collect_errors_for_files(files_to_check, checking_functions, line_checking_functions) # check dependecy licenses dep_license_errors = check_dep_license_errors(get_dep_toml_files(only_changed_files), progress) |