Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / tools / lint / test-manifest-toml / __init__.py
blob08f0e4ed93665792b45dfcf1b266c9c50aee0262
1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 import io
6 import os
7 import re
9 from manifestparser import TestManifest
10 from manifestparser.toml import DEFAULT_SECTION, alphabetize_toml_str, sort_paths
11 from mozlint import result
12 from mozlint.pathutils import expand_exclusions
13 from mozpack import path as mozpath
14 from tomlkit.items import Array, Table
16 SECTION_REGEX = r"^\[.*\]$"
17 DISABLE_REGEX = r"^[ \t]*#[ \t]*\[.*\]"
20 def make_result(path, message, is_error=False):
21 if is_error:
22 level = "error"
23 else:
24 level = "warning"
25 result = {
26 "path": path,
27 "lineno": 0, # tomlkit does not report lineno/column
28 "column": 0,
29 "message": message,
30 "level": level,
32 return result
35 def lint(paths, config, fix=None, **lintargs):
36 results = []
37 fixed = 0
38 topsrcdir = lintargs["root"]
39 file_names = list(expand_exclusions(paths, config, topsrcdir))
40 file_names = [os.path.normpath(f) for f in file_names]
41 section_rx = re.compile(SECTION_REGEX, flags=re.M)
42 disable_rx = re.compile(DISABLE_REGEX, flags=re.M)
44 for file_name in file_names:
45 path = mozpath.relpath(file_name, topsrcdir)
46 os.path.basename(file_name)
47 parser = TestManifest(use_toml=True, document=True)
49 try:
50 parser.read(file_name)
51 except Exception:
52 r = make_result(path, "The manifest is not valid TOML.", True)
53 results.append(result.from_config(config, **r))
54 continue
56 manifest = parser.source_documents[file_name]
57 manifest_str = io.open(file_name, "r", encoding="utf-8").read()
59 if not DEFAULT_SECTION in manifest:
60 r = make_result(
61 path, f"The manifest does not start with a [{DEFAULT_SECTION}] section."
63 if fix:
64 fixed += 1
65 results.append(result.from_config(config, **r))
67 sections = [k for k in manifest.keys() if k != DEFAULT_SECTION]
68 sorted_sections = sort_paths(sections)
69 if sections != sorted_sections:
70 r = make_result(
71 path, "The manifest sections are not in alphabetical order."
73 if fix:
74 fixed += 1
75 results.append(result.from_config(config, **r))
77 m = section_rx.findall(manifest_str)
78 if len(m) > 0:
79 for section_match in m:
80 section = section_match[1:-1]
81 if section == DEFAULT_SECTION:
82 continue
83 if not section.startswith('"'):
84 r = make_result(
85 path, f"The section name must be double quoted: [{section}]"
87 if fix:
88 fixed += 1
89 results.append(result.from_config(config, **r))
91 m = disable_rx.findall(manifest_str)
92 if len(m) > 0:
93 for disabled_section in m:
94 r = make_result(
95 path,
96 f"Use 'disabled = \"<reason>\"' to disable a test instead of a comment: {disabled_section}",
97 True,
99 results.append(result.from_config(config, **r))
101 for section, keyvals in manifest.body:
102 if section is None:
103 continue
104 if not isinstance(keyvals, Table):
105 r = make_result(
106 path, f"Bad assignment in preamble: {section} = {keyvals}", True
108 results.append(result.from_config(config, **r))
109 else:
110 for k, v in keyvals.items():
111 if k.endswith("-if"):
112 if not isinstance(v, Array):
113 r = make_result(
114 path,
115 f'Value for conditional must be an array: {k} = "{v}"',
116 True,
118 results.append(result.from_config(config, **r))
119 else:
120 for e in v:
121 if e.find("||") > 0 and e.find("&&") < 0:
122 r = make_result(
123 path,
124 f'Value for conditional must not include explicit ||, instead put on multiple lines: {k} = [ ... "{e}" ... ]',
125 True,
127 results.append(result.from_config(config, **r))
129 if fix:
130 manifest_str = alphabetize_toml_str(manifest)
131 fp = io.open(file_name, "w", encoding="utf-8", newline="\n")
132 fp.write(manifest_str)
133 fp.close()
135 return {"results": results, "fixed": fixed}