summaryrefslogtreecommitdiffstats
path: root/tools/lint/test-manifest-toml/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lint/test-manifest-toml/__init__.py')
-rw-r--r--tools/lint/test-manifest-toml/__init__.py135
1 files changed, 135 insertions, 0 deletions
diff --git a/tools/lint/test-manifest-toml/__init__.py b/tools/lint/test-manifest-toml/__init__.py
new file mode 100644
index 0000000000..08f0e4ed93
--- /dev/null
+++ b/tools/lint/test-manifest-toml/__init__.py
@@ -0,0 +1,135 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import io
+import os
+import re
+
+from manifestparser import TestManifest
+from manifestparser.toml import DEFAULT_SECTION, alphabetize_toml_str, sort_paths
+from mozlint import result
+from mozlint.pathutils import expand_exclusions
+from mozpack import path as mozpath
+from tomlkit.items import Array, Table
+
+SECTION_REGEX = r"^\[.*\]$"
+DISABLE_REGEX = r"^[ \t]*#[ \t]*\[.*\]"
+
+
+def make_result(path, message, is_error=False):
+ if is_error:
+ level = "error"
+ else:
+ level = "warning"
+ result = {
+ "path": path,
+ "lineno": 0, # tomlkit does not report lineno/column
+ "column": 0,
+ "message": message,
+ "level": level,
+ }
+ return result
+
+
+def lint(paths, config, fix=None, **lintargs):
+ results = []
+ fixed = 0
+ topsrcdir = lintargs["root"]
+ file_names = list(expand_exclusions(paths, config, topsrcdir))
+ file_names = [os.path.normpath(f) for f in file_names]
+ section_rx = re.compile(SECTION_REGEX, flags=re.M)
+ disable_rx = re.compile(DISABLE_REGEX, flags=re.M)
+
+ for file_name in file_names:
+ path = mozpath.relpath(file_name, topsrcdir)
+ os.path.basename(file_name)
+ parser = TestManifest(use_toml=True, document=True)
+
+ try:
+ parser.read(file_name)
+ except Exception:
+ r = make_result(path, "The manifest is not valid TOML.", True)
+ results.append(result.from_config(config, **r))
+ continue
+
+ manifest = parser.source_documents[file_name]
+ manifest_str = io.open(file_name, "r", encoding="utf-8").read()
+
+ if not DEFAULT_SECTION in manifest:
+ r = make_result(
+ path, f"The manifest does not start with a [{DEFAULT_SECTION}] section."
+ )
+ if fix:
+ fixed += 1
+ results.append(result.from_config(config, **r))
+
+ sections = [k for k in manifest.keys() if k != DEFAULT_SECTION]
+ sorted_sections = sort_paths(sections)
+ if sections != sorted_sections:
+ r = make_result(
+ path, "The manifest sections are not in alphabetical order."
+ )
+ if fix:
+ fixed += 1
+ results.append(result.from_config(config, **r))
+
+ m = section_rx.findall(manifest_str)
+ if len(m) > 0:
+ for section_match in m:
+ section = section_match[1:-1]
+ if section == DEFAULT_SECTION:
+ continue
+ if not section.startswith('"'):
+ r = make_result(
+ path, f"The section name must be double quoted: [{section}]"
+ )
+ if fix:
+ fixed += 1
+ results.append(result.from_config(config, **r))
+
+ m = disable_rx.findall(manifest_str)
+ if len(m) > 0:
+ for disabled_section in m:
+ r = make_result(
+ path,
+ f"Use 'disabled = \"<reason>\"' to disable a test instead of a comment: {disabled_section}",
+ True,
+ )
+ results.append(result.from_config(config, **r))
+
+ for section, keyvals in manifest.body:
+ if section is None:
+ continue
+ if not isinstance(keyvals, Table):
+ r = make_result(
+ path, f"Bad assignment in preamble: {section} = {keyvals}", True
+ )
+ results.append(result.from_config(config, **r))
+ else:
+ for k, v in keyvals.items():
+ if k.endswith("-if"):
+ if not isinstance(v, Array):
+ r = make_result(
+ path,
+ f'Value for conditional must be an array: {k} = "{v}"',
+ True,
+ )
+ results.append(result.from_config(config, **r))
+ else:
+ for e in v:
+ if e.find("||") > 0 and e.find("&&") < 0:
+ r = make_result(
+ path,
+ f'Value for conditional must not include explicit ||, instead put on multiple lines: {k} = [ ... "{e}" ... ]',
+ True,
+ )
+ results.append(result.from_config(config, **r))
+
+ if fix:
+ manifest_str = alphabetize_toml_str(manifest)
+ fp = io.open(file_name, "w", encoding="utf-8", newline="\n")
+ fp.write(manifest_str)
+ fp.close()
+
+ return {"results": results, "fixed": fixed}