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/.
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):
27 "lineno": 0, # tomlkit does not report lineno/column
35 def lint(paths
, config
, fix
=None, **lintargs
):
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)
50 parser
.read(file_name
)
52 r
= make_result(path
, "The manifest is not valid TOML.", True)
53 results
.append(result
.from_config(config
, **r
))
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
:
61 path
, f
"The manifest does not start with a [{DEFAULT_SECTION}] section."
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
:
71 path
, "The manifest sections are not in alphabetical order."
75 results
.append(result
.from_config(config
, **r
))
77 m
= section_rx
.findall(manifest_str
)
79 for section_match
in m
:
80 section
= section_match
[1:-1]
81 if section
== DEFAULT_SECTION
:
83 if not section
.startswith('"'):
85 path
, f
"The section name must be double quoted: [{section}]"
89 results
.append(result
.from_config(config
, **r
))
91 m
= disable_rx
.findall(manifest_str
)
93 for disabled_section
in m
:
96 f
"Use 'disabled = \"<reason>\"' to disable a test instead of a comment: {disabled_section}",
99 results
.append(result
.from_config(config
, **r
))
101 for section
, keyvals
in manifest
.body
:
104 if not isinstance(keyvals
, Table
):
106 path
, f
"Bad assignment in preamble: {section} = {keyvals}", True
108 results
.append(result
.from_config(config
, **r
))
110 for k
, v
in keyvals
.items():
111 if k
.endswith("-if"):
112 if not isinstance(v
, Array
):
115 f
'Value for conditional must be an array: {k} = "{v}"',
118 results
.append(result
.from_config(config
, **r
))
121 if e
.find("||") > 0 and e
.find("&&") < 0:
124 f
'Value for conditional must not include explicit ||, instead put on multiple lines: {k} = [ ... "{e}" ... ]',
127 results
.append(result
.from_config(config
, **r
))
130 manifest_str
= alphabetize_toml_str(manifest
)
131 fp
= io
.open(file_name
, "w", encoding
="utf-8", newline
="\n")
132 fp
.write(manifest_str
)
135 return {"results": results
, "fixed": fixed
}