Skip to content

Commit 7216d11

Browse files
committed
feat(tools): enable passing the purge file as an argument to diag
At present, the diag tool uses its default purge file. However, users may find it beneficial to specify and reuse their own purge file. A new command line option, --purge, has been introduced to allow users to provide their own purge file to diag. When this option is used, the default purge file is ignored. Signed-off-by: Frantisek Hrbata <[email protected]>
1 parent dfcc0b2 commit 7216d11

File tree

3 files changed

+87
-9
lines changed

3 files changed

+87
-9
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Purge format description for idf.py diag
2+
3+
Once diagnostic information is collected, the purge file is utilized to remove
4+
any sensitive data from the gathered files. By default, the purge file located
5+
at `tools/idf_py_actions/diag/purge/purge.yml` is used unless it is specified
6+
with the --purge argument, in which case the default file is not used.
7+
8+
## Overview of Purge Structure
9+
10+
It is a straightforward YAML file that includes a list of regular expressions
11+
and the corresponding strings that should replace any matches.
12+
13+
- regex: regular expression to look for
14+
repl: substitute string for match
15+
16+
The `regex.sub` function from Python is used internally.
File renamed without changes.

tools/idf_py_actions/diag_ext.py

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
491529
def 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

Comments
 (0)