From 8d2a4b55744150f151448a361f46e4c928db458b Mon Sep 17 00:00:00 2001 From: William Deegan Date: Mon, 5 Jun 2023 10:21:59 -0700 Subject: Added test for --debug=json. Implemented DebugOptions(json). Create containing directory, and issue UserError if the directory is not creatable.. --- CHANGES.txt | 2 +- SCons/Script/Main.py | 24 ++++++++++++++---- SCons/Script/__init__.py | 1 + SCons/Util/stats.py | 5 +++- test/option/debug-json.py | 39 ++++++++++++++++++++---------- test/option/fixture/SConstruct_debug_count | 4 +++ 6 files changed, 55 insertions(+), 20 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index b9f0c49..edac6d2 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -13,7 +13,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - The --debug flag now has a 'json' option which will write information generated by --debug={count, memory, time, action-timestamps} and about the build. - + From Mats Wichmann - C scanner's dictifyCPPDEFINES routine did not understand the possible combinations of CPPDEFINES - not aware of a "name=value" string either diff --git a/SCons/Script/Main.py b/SCons/Script/Main.py index 73070b2..d4b83b0 100644 --- a/SCons/Script/Main.py +++ b/SCons/Script/Main.py @@ -59,7 +59,7 @@ import SCons.Taskmaster import SCons.Util import SCons.Warnings import SCons.Script.Interactive -from SCons.Util.stats import COUNT_STATS, MEMORY_STATS, TIME_STATS, ENABLE_JSON, WriteJsonFile +from SCons.Util.stats import COUNT_STATS, MEMORY_STATS, TIME_STATS, ENABLE_JSON, WriteJsonFile, JSON_OUTPUT_FILE from SCons import __version__ as SConsVersion @@ -519,6 +519,24 @@ def GetOption(name): def SetOption(name, value): return OptionsParser.values.set_option(name, value) +def DebugOptions(json=None): + """ + API to allow specifying options to SCons debug logic + Currently only json is supported which changes the + json file written by --debug=json from the default + """ + if json is not None: + json_node = SCons.Defaults.DefaultEnvironment().arg2nodes(json) + SCons.Util.stats.JSON_OUTPUT_FILE = json_node[0].get_abspath() + # Check if parent dir to JSON_OUTPUT_FILE exists + json_dir = os.path.dirname(SCons.Util.stats.JSON_OUTPUT_FILE) + try: + if not os.path.isdir(json_dir): + os.makedirs(json_dir, exist_ok=True) + except (FileNotFoundError, OSError) as e: + raise SCons.Errors.UserError(f"Unable to create directory for JSON debug output file: {SCons.Util.stats.JSON_OUTPUT_FILE}") + + def ValidateOptions(throw_exception: bool=False) -> None: """Validate options passed to SCons on the command line. @@ -1507,10 +1525,6 @@ def main() -> None: if SCons.Util.stats.ENABLE_JSON: WriteJsonFile() - - if SCons.Util.stats.ENABLE_JSON: - WriteJsonFile() - sys.exit(exit_status) # Local Variables: diff --git a/SCons/Script/__init__.py b/SCons/Script/__init__.py index c8666c4..e398ecf 100644 --- a/SCons/Script/__init__.py +++ b/SCons/Script/__init__.py @@ -110,6 +110,7 @@ SetOption = Main.SetOption ValidateOptions = Main.ValidateOptions Progress = Main.Progress GetBuildFailures = Main.GetBuildFailures +DebugOptions = Main.DebugOptions #keep_going_on_error = Main.keep_going_on_error #print_dtree = Main.print_dtree diff --git a/SCons/Util/stats.py b/SCons/Util/stats.py index c407871..911910b 100644 --- a/SCons/Util/stats.py +++ b/SCons/Util/stats.py @@ -151,6 +151,7 @@ MEMORY_STATS = MemStats() TIME_STATS = TimeStats() + def WriteJsonFile(): """ Actually write the JSON file with debug information. @@ -159,7 +160,7 @@ def WriteJsonFile(): from SCons.Script import BUILD_TARGETS, COMMAND_LINE_TARGETS, ARGUMENTS, ARGLIST - # print("DUMPING JSON FILE") + print(f"DUMPING JSON FILE: {JSON_OUTPUT_FILE}") json_structure = {} if COUNT_STATS.enabled: json_structure['Object counts'] = {} @@ -199,6 +200,8 @@ def WriteJsonFile(): } } + + with open(JSON_OUTPUT_FILE, 'w') as sf: sf.write(json.dumps(json_structure, indent=4)) diff --git a/test/option/debug-json.py b/test/option/debug-json.py index 283b67d..f3e6e0f 100644 --- a/test/option/debug-json.py +++ b/test/option/debug-json.py @@ -46,6 +46,22 @@ def find_object_count(s, stdout): re_string = r'\d+ +\d+ %s' % re.escape(s) return re.search(re_string, stdout) +def check_json_file(filename): + with open(filename,'r') as jf: + stats_info = json.load(jf) + if 'Build_Info' not in stats_info: + test.fail_test(message='No Build_Info in json') + if 'Object counts' not in stats_info: + test.fail_test(message='No "Object counts" in json') + + for o in objects: + if o not in stats_info['Object counts']: + test.fail_test(message=f"Object counts missing {o}") + + if stats_info['Build_Info']['PYTHON_VERSION'][ + 'major'] != sys.version_info.major: + test.fail_test(message=f"Build Info PYTHON_VERSION incorrect") + objects = [ 'Action.CommandAction', @@ -59,19 +75,16 @@ objects = [ test.run(arguments='--debug=count,json') test.must_exist('scons_stats.json') -with open('scons_stats.json') as jf: - stats_info = json.load(jf) - if 'Build_Info' not in stats_info: - test.fail_test(message='No Build_Info in json') - if 'Object counts' not in stats_info: - test.fail_test(message='No "Object counts" in json') - - for o in objects: - if o not in stats_info['Object counts']: - test.fail_test(message=f"Object counts missing {o}") - - if stats_info['Build_Info']['PYTHON_VERSION']['major'] != sys.version_info.major: - test.fail_test(message=f"Build Info PYTHON_VERSION incorrect") +check_json_file('scons_stats.json') + +test.run(arguments='--debug=count,json JSON=build/output/stats.json') +test.must_exist('build/output/stats.json') +check_json_file('build/output/stats.json') + +test.run(arguments='--debug=count,json JSON=/cant/write/here/dumb.json', status=2, stderr=None) +test.must_not_exist('/cant/write/here/dumb.json') +test.pass_test('scons: *** Unable to create directory for JSON debug output file:' in test.stderr()) + test.pass_test() diff --git a/test/option/fixture/SConstruct_debug_count b/test/option/fixture/SConstruct_debug_count index be55d35..332815b 100644 --- a/test/option/fixture/SConstruct_debug_count +++ b/test/option/fixture/SConstruct_debug_count @@ -1,3 +1,7 @@ +if ARGUMENTS.get('JSON',False): + DebugOptions(json=ARGUMENTS.get('JSON')) + + DefaultEnvironment(tools=[]) def cat(target, source, env): with open(str(target[0]), 'wb') as f, open(str(source[0]), 'rb') as infp: -- cgit v0.12