Skip to content

Commit b86226c

Browse files
authored
Merge pull request #60 from Pennycook/analysis-config
Replace YAML config files with TOML analysis files
2 parents 3da02ae + 0fdaab6 commit b86226c

File tree

7 files changed

+142
-8
lines changed

7 files changed

+142
-8
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
include codebasin/schema/analysis.schema
12
include codebasin/schema/compilation-database.schema
23
include codebasin/schema/config.schema
34
include codebasin/schema/coverage-0.1.0.schema

bin/codebasin

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ def main():
6464
"-c",
6565
"--config",
6666
dest="config_file",
67-
metavar="FILE",
67+
metavar="<config-file>",
6868
action="store",
69-
help="configuration file (default: <DIR>/config.yaml)",
69+
help="Configuration YAML file. " + "Defaults to config.yaml",
7070
)
7171
parser.add_argument(
7272
"-v",
@@ -131,6 +131,14 @@ def main():
131131
+ "May be specified multiple times. "
132132
+ "If not specified, all known platforms will be included.",
133133
)
134+
# The analysis-file argument is optional while we support the -c option.
135+
parser.add_argument(
136+
"analysis_file",
137+
metavar="<analysis-file>",
138+
nargs="?",
139+
help="TOML file describing the analysis to be performed,"
140+
+ "including the codebase and platform descriptions.",
141+
)
134142

135143
args = parser.parse_args()
136144

@@ -170,6 +178,11 @@ def main():
170178
rootpath = args.rootdir
171179
rootdir = os.path.realpath(rootpath)
172180

181+
if args.config_file and args.analysis_file:
182+
raise RuntimeError(
183+
"Cannot use --config (-c) with TOML analysis files.",
184+
)
185+
173186
# Process the -p flag first to infer wider context.
174187
filtered_platforms = []
175188
additional_platforms = []
@@ -189,9 +202,15 @@ def main():
189202
)
190203
filtered_platforms.append(p)
191204

192-
# If no additional platforms are specified, a config file is required.
205+
# A legacy config file is required if:
206+
# - No additional platforms are specified; and
207+
# - No TOML analysis file is specified
193208
config_file = args.config_file
194-
if len(additional_platforms) == 0 and config_file is None:
209+
config_required = (
210+
len(additional_platforms) == 0 and args.analysis_file is None
211+
)
212+
if config_file is None and config_required:
213+
warnings.warn("Implicitly defined configuration files are deprecated.")
195214
config_file = os.path.join(rootdir, "config.yaml")
196215
if not os.path.exists(config_file):
197216
raise RuntimeError(f"Could not find config file {config_file}")
@@ -208,6 +227,10 @@ def main():
208227

209228
# Load the configuration file if it exists, obeying any platform filter.
210229
if config_file is not None:
230+
warnings.warn(
231+
"YAML configuration files are deprecated. "
232+
+ "Use TOML analysis files instead.",
233+
)
211234
if not util.ensure_yaml(config_file):
212235
logging.getLogger("codebasin").error(
213236
"Configuration file does not have YAML file extension.",
@@ -220,6 +243,32 @@ def main():
220243
filtered_platforms=filtered_platforms,
221244
)
222245

246+
# Load the analysis file if it exists.
247+
if args.analysis_file is not None:
248+
path = os.path.realpath(args.analysis_file)
249+
if os.path.exists(path):
250+
if not os.path.splitext(path)[1] == ".toml":
251+
raise RuntimeError(f"Analysis file {p} must end in .toml.")
252+
253+
with util.safe_open_read_nofollow(path, "rb") as f:
254+
try:
255+
analysis_toml = util._load_toml(f, "analysis")
256+
except BaseException:
257+
raise ValueError("Analysis file failed validation")
258+
259+
if "exclude" in analysis_toml["codebase"]:
260+
excludes = analysis_toml["codebase"]["exclude"]
261+
codebase["exclude_patterns"] += excludes
262+
263+
for name in analysis_toml["platform"].keys():
264+
if filtered_platforms and name not in filtered_platforms:
265+
continue
266+
if "commands" not in analysis_toml["platform"][name]:
267+
raise ValueError(f"Missing 'commands' for platform {name}")
268+
p = analysis_toml["platform"][name]["commands"]
269+
db = config.load_database(p, rootdir)
270+
configuration.update({name: db})
271+
223272
# Extend configuration with any additional platforms.
224273
for p in additional_platforms:
225274
name = os.path.splitext(os.path.basename(p))[0]

codebasin/schema/analysis.schema

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://raw.githubusercontent.com/intel/code-base-investigator/main/codebasin/schema/analysis.schema",
4+
"title": "Code Base Investigator Analysis File",
5+
"description": "Analysis options for Code Base Investigator.",
6+
"type": "object",
7+
"properties": {
8+
"codebase": {
9+
"type": "object",
10+
"properties": {
11+
"exclude": {
12+
"type": "array",
13+
"items": {
14+
"type": "string"
15+
}
16+
}
17+
}
18+
},
19+
"platform": {
20+
"type": "object",
21+
"patternProperties": {
22+
".*": {
23+
"type": "object",
24+
"properties": {
25+
"commands": {
26+
"type": "string"
27+
}
28+
},
29+
"additionalProperties": false
30+
}
31+
}
32+
},
33+
"additionalProperties": false
34+
}
35+
}

codebasin/util.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def _validate_json(json_object: object, schema_name: str) -> bool:
123123
json_object : Object
124124
The JSON to validate.
125125
126-
schema_name : {'compiledb', 'config', 'coverage', 'cbiconfig'}
126+
schema_name : {'compiledb', 'config', 'coverage', 'cbiconfig', 'analysis'}
127127
The schema to validate against.
128128
129129
Returns
@@ -140,6 +140,7 @@ def _validate_json(json_object: object, schema_name: str) -> bool:
140140
If the schema file cannot be located.
141141
"""
142142
schema_paths = {
143+
"analysis": "schema/analysis.schema",
143144
"compiledb": "schema/compilation-database.schema",
144145
"config": "schema/config.schema",
145146
"coverage": "schema/coverage-0.1.0.schema",
@@ -270,18 +271,18 @@ def _load_toml(file_object: typing.TextIO, schema_name: str) -> object:
270271
file_object : typing.TextIO
271272
The file object to load from.
272273
273-
schema_name : {'cbiconfig'}
274+
schema_name : {'cbiconfig', 'analysis'}
274275
The schema to validate against.
275276
276277
Returns
277278
-------
278279
Object
279-
The loaded JSON.
280+
The loaded TOML.
280281
281282
Raises
282283
------
283284
ValueError
284-
If the JSON fails to validate, or the schema name is unrecognized.
285+
If the TOML fails to validate, or the schema name is unrecognized.
285286
286287
RuntimeError
287288
If the schema file cannot be located.

tests/schema/analysis.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[codebase]
2+
exclude = [
3+
"*.F90",
4+
"*.cu",
5+
]
6+
7+
[platform.one]
8+
commands = "one.json"
9+
10+
[platform.two]
11+
commands = "two.json"

tests/schema/invalid_analysis.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[codebase]
2+
exclude = [
3+
1,
4+
2,
5+
]
6+
7+
[platform.one]
8+
commands = "one.json"
9+
10+
[platform.two]
11+
commands = "two.json"

tests/schema/test_schema.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,32 @@ def test_cbiconfig_file(self):
5555
with self.assertRaises(ValueError):
5656
toml = util._load_toml(f, "cbiconfig")
5757

58+
def test_analysis_file(self):
59+
"""schema/analysis_file"""
60+
61+
path = "./tests/schema/analysis.toml"
62+
with open(path, "rb") as f:
63+
toml = util._load_toml(f, "analysis")
64+
expected = {
65+
"codebase": {
66+
"exclude": ["*.F90", "*.cu"],
67+
},
68+
"platform": {
69+
"one": {
70+
"commands": "one.json",
71+
},
72+
"two": {
73+
"commands": "two.json",
74+
},
75+
},
76+
}
77+
self.assertEqual(toml, expected)
78+
79+
path = "./tests/schema/invalid_analysis.toml"
80+
with open(path, "rb") as f:
81+
with self.assertRaises(ValueError):
82+
toml = util._load_toml(f, "analysis")
83+
5884

5985
if __name__ == '__main__':
6086
unittest.main()

0 commit comments

Comments
 (0)