@@ -116,8 +116,6 @@ def log(level: int, msg: str, prefix: str) -> None:
116116 else :
117117 log_prefix = ''
118118
119- msg = textwrap .indent (msg , prefix = log_prefix )
120-
121119 if LOG_FILE :
122120 try :
123121 log_msg = textwrap .indent (msg , prefix = f'{ prefix } ' )
@@ -131,6 +129,8 @@ def log(level: int, msg: str, prefix: str) -> None:
131129 if level > LOG_LEVEL :
132130 return
133131
132+ msg = textwrap .indent (msg , prefix = log_prefix )
133+
134134 if not LOG_COLORS or level not in (LOG_FATAL , LOG_ERROR , LOG_WARNING ):
135135 print (msg , file = sys .stderr )
136136 sys .stderr .flush ()
@@ -257,11 +257,8 @@ def diff_dirs(dir1: Path, dir2: Path) -> None:
257257 dbg (line .strip ())
258258
259259
260- def redact_files (dir1 : Path , dir2 : Path ) -> None :
260+ def redact_files (dir1 : Path , dir2 : Path , purge : list ) -> None :
261261 """Show differences in files between two directories."""
262- purge_path = Path (__file__ ).parent / 'diag' / 'purge.yml'
263- with open (purge_path , 'r' ) as f :
264- purge = yaml .safe_load (f .read ())
265262
266263 regexes : List = []
267264 for entry in purge :
@@ -488,6 +485,47 @@ def validate_recipe(recipe: Dict) -> None:
488485 raise RuntimeError (f'Unknown command "{ cmd } " in step "{ step_name } "' )
489486
490487
488+ def validate_purge (purge : Any ) -> None :
489+ """Validate the loaded purge file. This is done manually to avoid any
490+ dependencies and to provide more informative error messages.
491+ """
492+
493+ if type (purge ) is not list :
494+ raise RuntimeError (f'Purge is not of type "list"' )
495+
496+ regex_keys = ['regex' , 'repl' ]
497+
498+ for entry in purge :
499+ if type (entry ) is not dict :
500+ raise RuntimeError (f'Purge entry "{ entry } " is not of type "dict"' )
501+
502+ if 'regex' in entry :
503+ for key in entry :
504+ if key not in regex_keys :
505+ raise RuntimeError ((f'Unknown purge key "{ key } " in "{ entry } ", '
506+ f'expecting "{ regex_keys } "' ))
507+
508+ regex = entry .get ('regex' )
509+ repl = entry .get ('repl' )
510+
511+ # Required arguments
512+ if type (regex ) is not str :
513+ raise RuntimeError (f'Argument "regex" for purge entry "{ entry } " is not of type "str"' )
514+ try :
515+ re .compile (regex )
516+ except re .error as e :
517+ raise RuntimeError ((f'Argument "regex" for purge entry "{ entry } " is not '
518+ f'a valid regular expression: { e } ' ))
519+
520+ if not repl :
521+ raise RuntimeError (f'Purge entry "{ entry } " is missing "repl" argument' )
522+ if type (repl ) is not str :
523+ raise RuntimeError (f'Argument "repl" for purge entry "{ entry } " is not of type "str"' )
524+
525+ else :
526+ raise RuntimeError (f'Unknown purge entry "{ entry } "' )
527+
528+
491529def get_output_path (src : Optional [str ],
492530 dst : Optional [str ],
493531 step : Dict ,
@@ -934,6 +972,7 @@ def create(action: str,
934972 check_recipes : bool ,
935973 cmdl_recipes : Tuple ,
936974 cmdl_tags : Tuple ,
975+ purge_file : str ,
937976 append : bool ,
938977 output : Optional [str ]) -> None :
939978
@@ -1032,11 +1071,25 @@ def create(action: str,
10321071 except Exception :
10331072 die (f'File "{ recipe_file } " is not a valid diagnostic file' )
10341073
1074+ # Load purge file
1075+ dbg (f'Purge file: { purge_file } ' )
1076+ try :
1077+ with open (purge_file , 'r' ) as f :
1078+ purge = yaml .safe_load (f .read ())
1079+ except Exception :
1080+ die (f'Cannot load purge file "{ purge_file } "' )
1081+
1082+ # Validate purge file
1083+ try :
1084+ validate_purge (purge )
1085+ except Exception :
1086+ die (f'File "{ purge_file } " is not a valid purge file' )
1087+
10351088 # Cook recipes
10361089 try :
10371090 for recipe_file , recipe in recipes .items ():
10381091 desc = recipe .get ('description' )
1039- dbg (f'Processing recipe "{ desc } " file "{ recipe_file } "' )
1092+ dbg (f'Processing recipe "{ desc } " file "{ recipe_file } "' )
10401093 print (f'{ desc } ' )
10411094 process_recipe (recipe )
10421095 except Exception :
@@ -1050,9 +1103,9 @@ def create(action: str,
10501103 LOG_FILE = None
10511104
10521105 try :
1053- redact_files (TMP_DIR_REPORT_PATH , TMP_DIR_REPORT_REDACTED_PATH )
1106+ redact_files (TMP_DIR_REPORT_PATH , TMP_DIR_REPORT_REDACTED_PATH , purge )
10541107 except Exception :
1055- err (f'The redaction was unsuccessful. ' )
1108+ err (f'The redaction was unsuccessful' )
10561109
10571110 try :
10581111 shutil .move (TMP_DIR_REPORT_REDACTED_PATH , output_dir_path )
@@ -1142,6 +1195,15 @@ def action_extensions(base_actions: Dict, project_path: str) -> Any:
11421195 'and the report directory specified with the --zip option with a zip '
11431196 'extension is used for the zip file archive.' )
11441197 },
1198+ {
1199+ 'names' : ['-p' , '--purge' , 'purge_file' ],
1200+ 'metavar' : 'PATH' ,
1201+ 'type' : str ,
1202+ 'default' : str (Path (__file__ ).parent / 'diag' / 'purge' / 'purge.yml' ),
1203+ 'help' : ('Purge file PATH containing a description of what information '
1204+ 'should be redacted from the resulting report. '
1205+ 'Default is "tools/idf_py_actions/diag/purge/purge.yml"' )
1206+ },
11451207 ],
11461208 },
11471209 },
0 commit comments