Skip to content

Commit d32f3d6

Browse files
Reduce output from copyright checker (#198)
* Reduce output from copyright checker Remove a lot of the duplicate output from the copyright checker to make it obvious which files have a problem. Also report cases where no files are found or all files are ignored as non-fatal warnings. Improve usability by making it possible to specify the location of the template directory on the command line. Previously, the script either used the contents of CYLC_TASK_WORK_PATH or the current directory. Catch the case where no templates have been found and Exit with an error. Previous behaviour was to continue and to flag up all files as having invalid copyrights. * Fix misspelling of warning * Improve template availability checking * Shuffle option definitions for clarity --------- Co-authored-by: Cameron Bateman <cameron.bateman@metoffice.gov.uk>
1 parent 714bc9f commit d32f3d6

1 file changed

Lines changed: 64 additions & 27 deletions

File tree

script_copyright_checker/bin/copyright_checker.py

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,16 @@ def banner_print(message, maxwidth=_OUTPUT_LINE_WIDTH, char="%"):
3737

3838

3939
# ------------------------------------------------------------------------------
40-
def load_templates(filter_pattern):
40+
def load_templates(filter_pattern, template_path):
4141
"""
4242
Attempt load allowed copyright templates
4343
"""
4444

4545
loaded_templates = []
4646

47-
template_path = "."
48-
if "CYLC_TASK_WORK_PATH" in os.environ:
49-
template_path = os.path.join(os.environ["CYLC_TASK_WORK_PATH"], "file", "")
50-
51-
template_files = files_to_process(template_path, [], filter_pattern=filter_pattern)
47+
template_files, _ = files_to_process(
48+
template_path, [], filter_pattern=filter_pattern
49+
)
5250

5351
for filename in template_files:
5452
with open(filename) as file:
@@ -100,81 +98,106 @@ def files_to_process(filepath, ignore_list, filter_pattern=_FILENAME_FILTER):
10098
the patterns in the ignore list
10199
"""
102100
files = []
101+
ignored = 0
103102
for root, _, filenames in os.walk(filepath):
104103
for filename in filenames:
105104
if filter_pattern.match(filename):
106105
path_to_file = os.path.join(root, filename)
107106
if any([ignore in path_to_file for ignore in ignore_list]):
108-
print(f"WARNING: Ignoring file: {path_to_file}")
107+
ignored += 1
109108
continue
110109
files.append(path_to_file)
111110

112-
return files
111+
return files, ignored
113112

114113

115114
# ------------------------------------------------------------------------------
116-
def main(inputs, ignore_list):
115+
def main(inputs, ignore_list, template_path):
117116
"""main program block"""
118117

119118
templates = []
120119
regex_templates_raw = []
121120
regex_templates = []
122121

123-
banner_print("Running copyright checker")
124-
125122
filter_tmp = re.compile(r".*\.template$")
126-
templates.extend(load_templates(filter_pattern=filter_tmp))
123+
templates.extend(load_templates(filter_tmp, template_path))
127124

128125
filter_tmp = re.compile(r".*\.regex_template$")
129-
regex_templates_raw.extend(load_templates(filter_pattern=filter_tmp))
126+
regex_templates_raw.extend(load_templates(filter_tmp, template_path))
127+
128+
if not (templates or regex_templates_raw):
129+
raise SystemExit("[ERROR] no templates or regex templates found")
130130

131131
for filename, template_lines in regex_templates_raw:
132132
regex_templates.append((filename, re.compile(r"\n".join(template_lines))))
133133

134134
files_to_check = []
135+
ignored_count = 0
135136
for file_input in inputs:
136137
if os.path.isfile(file_input):
137138
if any([ignore in file_input for ignore in ignore_list]):
138-
print(f"WARNING: Ignoring file: {file_input}")
139+
ignored_count += 1
139140
continue
140141
else:
141-
print(f"Source (file): {file_input}")
142142
files_to_check.append(file_input)
143143
elif os.path.isdir(file_input):
144-
print(f"Source (dir) : {file_input}")
145-
files_to_check.extend(files_to_process(file_input, ignore_list))
144+
files_found, files_ignored = files_to_process(file_input, ignore_list)
145+
files_to_check.extend(files_found)
146+
ignored_count += files_ignored
146147
else:
147148
raise SystemExit(
148149
"[ERROR] Input sources must be files/directories"
149150
+ "\n : "
150151
+ f'"{file_input}" is neither'
151152
)
152153

153-
print(f"\nFound {len(files_to_check)} files to check")
154-
155154
failed_files = []
156155
for item in files_to_check:
157-
print(f"file : {item}")
158156
file_pass = check_file_compliance(item, templates, regex_templates)
159157
if not file_pass:
160158
failed_files.append(item)
161159

162160
fail_count = len(failed_files)
161+
checked_count = len(files_to_check)
163162
plural = "s" if fail_count != 1 else ""
164-
banner_print(f"Checks completed with {fail_count} failure{plural}\n")
165163

166164
if fail_count > 0:
167-
print(f": Failed file{plural} :")
165+
banner_print(
166+
f"Checked {checked_count}, ignored {ignored_count}, "
167+
f"with {fail_count} failure{plural}\n"
168+
)
168169
for filename in failed_files:
169-
full_fname = os.path.realpath(filename)
170-
banner_print(full_fname, maxwidth=(len(full_fname) + 10), char="#")
171-
print("")
172-
print("")
170+
print(os.path.realpath(filename))
171+
print()
173172
plural2 = "have" if fail_count != 1 else "is"
174173
raise SystemExit(
175174
f"[ERROR] {fail_count} file{plural} "
176175
+ f"{plural2} missing copyright notice{plural}"
177176
)
177+
elif not files_to_check:
178+
message = "[WARNING] "
179+
if ignored_count == 1:
180+
message += "only possible file ignored"
181+
elif ignored_count > 1:
182+
message += f"all {ignored_count} possible file{plural} ignored"
183+
else:
184+
message += "no files found"
185+
print(message)
186+
187+
else:
188+
if checked_count != 1:
189+
plural = "s"
190+
plural2 = "have"
191+
else:
192+
plural = ""
193+
plural2 = "has a"
194+
message = (
195+
f"[SUCCESS] {checked_count} file{plural} {plural2} valid copyright{plural}"
196+
)
197+
if ignored_count > 0:
198+
plural = "s" if ignored_count != 1 else ""
199+
message += f" with {ignored_count} file{plural} ignored"
200+
print(message)
178201

179202

180203
# ------------------------------------------------------------------------------
@@ -189,22 +212,36 @@ def parse_options():
189212
"individual files will be scanned, and all files within "
190213
"directories and their sub-directories will be scanned."
191214
)
215+
if "CYLC_TASK_WORK_PATH" in os.environ:
216+
template_path = os.path.join(os.environ["CYLC_TASK_WORK_PATH"], "file", "")
217+
else:
218+
template_path = "."
192219
parser = argparse.ArgumentParser(usage=usage, description=description)
193220
excl_group = parser.add_mutually_exclusive_group()
194221
parser.add_argument(
195222
"--ignore",
196223
action="store",
197224
dest="ignore",
225+
metavar="LIST",
198226
default=None,
199227
help=("ignore filename/s containing (comma separated list of patterns)"),
200228
)
201229
parser.add_argument(
202230
"--base_path",
203231
action="store",
204232
dest="base_path",
233+
metavar="DIR",
205234
default=None,
206235
help="Override the base path to find the actual file.",
207236
)
237+
parser.add_argument(
238+
"--templates",
239+
action="store",
240+
dest="templates",
241+
metavar="DIR",
242+
default=template_path,
243+
help="path to the templates (default: %(default)s)",
244+
)
208245
excl_group.add_argument(
209246
"--full_trunk",
210247
action="store_true",
@@ -235,4 +272,4 @@ def parse_options():
235272
if len(OPTS.ignore) == 1 and OPTS.ignore[0] == "":
236273
OPTS.ignore = []
237274

238-
main(OPTS.files, OPTS.ignore)
275+
main(OPTS.files, OPTS.ignore, OPTS.templates)

0 commit comments

Comments
 (0)