Merge ~jslarraz/review-tools:use-logging-module into review-tools:master

Proposed by Jorge Sancho Larraz
Status: Merged
Merged at revision: f2c630c4f9025a91435ee9a60d93b382756c13e4
Proposed branch: ~jslarraz/review-tools:use-logging-module
Merge into: review-tools:master
Diff against target: 1149 lines (+150/-212)
17 files modified
bin/create-snap-declaration (+3/-3)
bin/dump-tool (+9/-9)
bin/rock-check-notices (+6/-7)
bin/rock-updates-available (+7/-7)
bin/snap-check-notices (+6/-7)
bin/snap-review (+8/-18)
bin/snap-updates-available (+10/-10)
bin/snap-verify-declaration (+8/-11)
bin/store-query (+11/-9)
reviewtools/__init__.py (+16/-0)
reviewtools/available.py (+5/-7)
reviewtools/common.py (+17/-58)
reviewtools/sr_declaration.py (+4/-3)
reviewtools/store.py (+26/-27)
tests/test-dump-tool.sh.expected (+8/-8)
tests/test-snap-verify-declaration.sh.expected (+3/-25)
tests/test-updates-available.sh.expected (+3/-3)
Reviewer Review Type Date Requested Status
Alex Murray Approve
Review via email: mp+466961@code.launchpad.net

Commit message

Use python logging module instead of custom error, warn, msg and debug functions defined in reviewtools.common

To post a comment you must log in.
Revision history for this message
Jorge Sancho Larraz (jslarraz) wrote :

This MR slighly changes the output format under certain circumstances. It removes the ability to return json formatted errors for errors generated by the cli script caused during the cli arguments validation/processing. This behaviour looks desirable to me anyway tbh

See inline comments!

Revision history for this message
Jorge Sancho Larraz (jslarraz) :
Revision history for this message
Alex Murray (alexmurray) wrote :

Thanks for the very extensive comments to help walk-through this MR - it was very valuable. I really like this cleanup and it makes the code more pythonic by using the standard logging module, plus I actually like the CLI printing the errors directly rather than including them in the json output. LGTM!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/bin/create-snap-declaration b/bin/create-snap-declaration
2index 4666a65..a924e93 100755
3--- a/bin/create-snap-declaration
4+++ b/bin/create-snap-declaration
5@@ -5,6 +5,7 @@ import json
6 import re
7 import sys
8
9+from reviewtools import logger
10 from reviewtools.common import read_snapd_base_declaration
11
12 decl = {}
13@@ -158,9 +159,8 @@ def add_missing():
14
15 cstr_s = "allow-%s" % cstr
16 if in_base and cstr_s not in decl[side][iface]:
17- print(
18- "WARN: adding missing '%s' for '%s' from base decl"
19- % (cstr, iface)
20+ logger.warning(
21+ "adding missing '%s' for '%s' from base decl" % (cstr, iface)
22 )
23 decl[side][iface][cstr_b] = bool2str(base_decl[side][iface][cstr_b])
24 if isinstance(decl[side][iface][cstr_b], dict):
25diff --git a/bin/dump-tool b/bin/dump-tool
26index 1361328..4a9658b 100755
27--- a/bin/dump-tool
28+++ b/bin/dump-tool
29@@ -57,7 +57,7 @@ import textwrap
30 import yaml
31
32 import reviewtools.common as common
33-from reviewtools.common import error, warn, msg, debug
34+from reviewtools import logger
35
36 # TODO:
37 # - --file read in one at a time and flush to disk (either --output or
38@@ -72,11 +72,11 @@ def _read_store_dump(input, warn_if_empty=False, progress=False, merge=None):
39 """
40
41 def _add_entry(db, id, rev, y):
42- debug("adding: id=%s,rev=%s,yaml=\n%s" % (id, rev, y))
43+ logger.debug("adding: id=%s,rev=%s,yaml=\n%s" % (id, rev, y))
44 try:
45 snap_yaml = yaml.load(y, Loader=yaml.SafeLoader)
46 except Exception as e:
47- warn("Skipping %s|%s: %s" % (cId, cRev, e))
48+ logger.warning("Skipping %s|%s: %s" % (cId, cRev, e))
49 return
50
51 # skipping existing entries
52@@ -115,7 +115,7 @@ def _read_store_dump(input, warn_if_empty=False, progress=False, merge=None):
53 (cId, cRev, cYaml) = line.split("|")
54 if cYaml == "\n": # id|rev|
55 if warn_if_empty and not progress:
56- warn("Skipping %s|%s: empty" % (cId, cRev))
57+ logger.warning("Skipping %s|%s: empty" % (cId, cRev))
58 cId = None
59 elif cId is not None:
60 cYaml += "%s" % (line)
61@@ -139,7 +139,7 @@ def _write_json_db(db, fn, stdout=False):
62 return
63
64 if os.path.exists(fn):
65- error("%s exists. Aborting" % (fn))
66+ logger.error("%s exists. Aborting" % (fn))
67 with open(fn, "w") as fh:
68 json.dump(db, fh, sort_keys=True, indent=2)
69 fh.write("\n")
70@@ -183,21 +183,21 @@ def main():
71
72 # Arg validation
73 if not (args.file) and not (args.db_file):
74- error("Must specify either --file or --db-file")
75+ logger.error("Must specify either --file or --db-file")
76 elif (args.file) and (args.db_file):
77 if not os.path.exists(args.file) or not os.path.exists(args.db_file):
78- error("Both --file and --db-file must exist when used together")
79+ logger.error("Both --file and --db-file must exist when used together")
80 if not args.force_merge:
81 ans = input("Merge '%s' into '%s' (y|N)? " % (args.file, args.db_file))
82 if ans.strip().lower() not in ["y", "yes"]:
83- msg("Aborting")
84+ logger.info("Aborting")
85 sys.exit(0)
86
87 if args.db_file: # read the existing db
88 try:
89 db = common.read_file_as_json_dict(args.db_file)
90 except json.decoder.JSONDecodeError as e:
91- error("Could not read '%s': %s" % (args.db_file, e))
92+ logger.error("Could not read '%s': %s" % (args.db_file, e))
93
94 if args.file and args.db_file:
95 db = _read_store_dump(
96diff --git a/bin/rock-check-notices b/bin/rock-check-notices
97index e2e0271..2b7303c 100755
98--- a/bin/rock-check-notices
99+++ b/bin/rock-check-notices
100@@ -18,12 +18,11 @@ import argparse
101 import json
102 import os
103 import sys
104+from reviewtools import logger
105
106 import reviewtools.common as common
107 from reviewtools.common import (
108 cmd,
109- debug,
110- warn,
111 fetch_usn_db,
112 get_debug_info_from_environment,
113 initialize_environment_variables,
114@@ -67,10 +66,10 @@ def main():
115 available = "%s/bin/rock-updates-available" % os.path.abspath(
116 os.environ["SNAP"]
117 )
118- debug("Running " + available)
119+ logger.debug("Running " + available)
120 else:
121 available = "review-tools.rock-updates-available"
122- debug("SNAP not set. Defaulting to 'review-tools.*'")
123+ logger.debug("SNAP not set. Defaulting to 'review-tools.*'")
124
125 reports = dict()
126 had_debug = get_debug_info_from_environment()
127@@ -78,7 +77,7 @@ def main():
128 for pkg in argv:
129 valid_rock, warn_msg = is_rock_valid(pkg)
130 if not valid_rock:
131- warn(warn_msg)
132+ logger.warning(warn_msg)
133 continue
134
135 # The expected rock name for this initial implementation is:
136@@ -89,7 +88,7 @@ def main():
137 rev = os.path.splitext(os.path.basename(pkg))[0].split("_")[1]
138
139 if rock in reports and rev in reports[rock]:
140- debug("Skipping %s with revision %s" % (rock, rev))
141+ logger.debug("Skipping %s with revision %s" % (rock, rev))
142 continue
143
144 usndb_fn = os.path.join(os.environ["SNAP_USER_COMMON"], usndb)
145@@ -112,7 +111,7 @@ def main():
146 os.environ["SNAP_DEBUG"] = had_debug
147
148 if rc != 0:
149- warn(out)
150+ logger.warning(out)
151 continue
152
153 if rock not in reports:
154diff --git a/bin/rock-updates-available b/bin/rock-updates-available
155index 77a8c42..a6f12bf 100755
156--- a/bin/rock-updates-available
157+++ b/bin/rock-updates-available
158@@ -44,7 +44,7 @@ import textwrap
159 import reviewtools.available as available
160
161 import reviewtools.common as common
162-from reviewtools.common import error
163+from reviewtools import logger
164
165
166 def main():
167@@ -80,13 +80,13 @@ def main():
168
169 # Arg validation
170 if args.rock and not args.usn_db:
171- error("Must specify --usn-db with --rock")
172+ logger.error("Must specify --usn-db with --rock")
173 elif args.rock and args.store_db:
174- error("Must not specify --store-db with --rock")
175+ logger.error("Must not specify --store-db with --rock")
176 elif not args.rock and not args.store_db:
177- error("Must specify --rock or --store-db")
178+ logger.error("Must specify --rock or --store-db")
179 elif args.with_cves and not args.rock:
180- error("--with-cves should only be used with --rock")
181+ logger.error("--with-cves should only be used with --rock")
182
183 ignore_pockets = [pocket.strip() for pocket in args.ignore_pockets.split(",")]
184
185@@ -97,7 +97,7 @@ def main():
186 args.usn_db, args.rock, args.with_cves, ignore_pockets
187 )
188 except ValueError as e:
189- error(e)
190+ logger.error(e)
191 elif args.store_db:
192 (_, errors) = available.scan_store(
193 args.usn_db,
194@@ -108,7 +108,7 @@ def main():
195 ignore_pockets,
196 )
197 if len(errors):
198- error("Errors encountered when scanning store entries")
199+ logger.error("Errors encountered when scanning store entries")
200
201 if report != "":
202 print(report)
203diff --git a/bin/snap-check-notices b/bin/snap-check-notices
204index e1b16c2..81f2bc0 100755
205--- a/bin/snap-check-notices
206+++ b/bin/snap-check-notices
207@@ -19,11 +19,10 @@ import json
208 import os
209 import sys
210
211+from reviewtools import logger
212 import reviewtools.common as common
213 from reviewtools.common import (
214 cmd,
215- debug,
216- warn,
217 fetch_usn_db,
218 initialize_environment_variables,
219 get_debug_info_from_environment,
220@@ -66,17 +65,17 @@ def main():
221 available = "%s/bin/snap-updates-available" % os.path.abspath(
222 os.environ["SNAP"]
223 )
224- debug("Running " + available)
225+ logger.debug("Running " + available)
226 else:
227 available = "review-tools.updates-available"
228- debug("SNAP not set. Defaulting to 'review-tools.*'")
229+ logger.debug("SNAP not set. Defaulting to 'review-tools.*'")
230
231 reports = dict()
232 had_debug = get_debug_info_from_environment()
233
234 for pkg in argv:
235 if not os.path.isfile(pkg):
236- warn("Skipping '%s', not a regular file" % pkg)
237+ logger.warning("Skipping '%s', not a regular file" % pkg)
238 continue
239
240 snap = os.path.basename(pkg).split("_")[0]
241@@ -85,7 +84,7 @@ def main():
242 rev = os.path.splitext(os.path.basename(pkg))[0].split("_")[1]
243
244 if snap in reports and rev in reports[snap]:
245- debug("Skipping %s with revision %s" % (snap, rev))
246+ logger.debug("Skipping %s with revision %s" % (snap, rev))
247 continue
248
249 usndb_fn = os.path.join(os.environ["SNAP_USER_COMMON"], usndb)
250@@ -111,7 +110,7 @@ def main():
251 os.environ["SNAP_DEBUG"] = had_debug
252
253 if rc != 0:
254- warn(out)
255+ logger.warning(out)
256 continue
257
258 if snap not in reports:
259diff --git a/bin/snap-review b/bin/snap-review
260index 8199929..fa891d9 100755
261--- a/bin/snap-review
262+++ b/bin/snap-review
263@@ -11,9 +11,9 @@ import tempfile
264 import textwrap
265 import logging
266
267+from reviewtools import logger
268 from reviewtools.common import (
269 MKDTEMP_PREFIX,
270- error,
271 init_override_state_input,
272 verify_override_state,
273 )
274@@ -72,14 +72,8 @@ def main():
275 parser.add_argument("--state-output", default=None, help="store state output blob")
276 args = parser.parse_args()
277
278- error_output_type = "console"
279- if args.json or args.sdk:
280- error_output_type = "json"
281-
282 if not os.path.exists(args.filename):
283- error(
284- "file '%s' does not exist." % args.filename, output_type=error_output_type
285- )
286+ logger.error("file '%s' does not exist." % args.filename)
287
288 modules = modules_mod.get_modules()
289 if not modules:
290@@ -93,14 +87,14 @@ def main():
291 overrides["snap_decl_plugs"] = json.loads(plugs_file.read())
292 validate_json(overrides["snap_decl_plugs"])
293 except Exception as e:
294- error("Failed to read plugs: %s" % e, output_type=error_output_type)
295+ logger.error("Failed to read plugs: %s" % e)
296 if args.slots:
297 try:
298 with open(args.slots, "r") as slots_file:
299 overrides["snap_decl_slots"] = json.loads(slots_file.read())
300 validate_json(overrides["snap_decl_slots"])
301 except Exception as e:
302- error("Failed to read slots: %s" % e, output_type=error_output_type)
303+ logger.error("Failed to read slots: %s" % e)
304 if args.allow_classic:
305 overrides["snap_allow_classic"] = args.allow_classic
306 if args.allow_gadget:
307@@ -112,27 +106,23 @@ def main():
308
309 # --state-input alone is unsupported
310 if args.state_input and not args.state_output:
311- error(
312+ logger.error(
313 "Must specify --state-output with --state-input",
314- output_type=error_output_type,
315 )
316
317 if args.state_output:
318 if args.state_input:
319 # --state-input --state-output indicates we have previous state
320 if not os.path.exists(args.state_input):
321- error(
322+ logger.error(
323 "file '%s' does not exist." % args.state_input,
324- output_type=error_output_type,
325 )
326 try:
327 with open(args.state_input, "rb") as in_f:
328 st = in_f.read().decode("utf-8")
329 overrides["state_input"] = json.loads(st)
330 except Exception as e:
331- error(
332- "Could not read state input: %s" % e, output_type=error_output_type
333- )
334+ logger.error("Could not read state input: %s" % e)
335 else:
336 # --state-output alone indicates we are bootstrapping
337 overrides["state_input"] = init_override_state_input()
338@@ -141,7 +131,7 @@ def main():
339 try:
340 verify_override_state(overrides["state_input"])
341 except Exception as e:
342- error("state-input failed to verify: %s" % e, output_type=error_output_type)
343+ logger.error("state-input failed to verify: %s" % e)
344
345 overrides["state_output"] = copy.deepcopy(overrides["state_input"])
346
347diff --git a/bin/snap-updates-available b/bin/snap-updates-available
348index 4db68f9..98e888a 100755
349--- a/bin/snap-updates-available
350+++ b/bin/snap-updates-available
351@@ -45,7 +45,7 @@ import textwrap
352 import reviewtools.available as available
353
354 import reviewtools.common as common
355-from reviewtools.common import error
356+from reviewtools import logger
357
358
359 def main():
360@@ -86,19 +86,19 @@ def main():
361
362 # Arg validation
363 if args.check_shared_publishers and args.snap:
364- error("--snap should not be used with --check-shared-publishers")
365+ logger.error("--snap should not be used with --check-shared-publishers")
366 elif args.check_shared_publishers and args.usn_db:
367- error("--usn-db should not be used with --check-shared-publishers")
368+ logger.error("--usn-db should not be used with --check-shared-publishers")
369 elif args.check_shared_publishers and not args.store_db:
370- error("Must specify --store-db with --check-shared-publishers")
371+ logger.error("Must specify --store-db with --check-shared-publishers")
372 elif args.snap and not args.usn_db:
373- error("Must specify --usn-db with --snap")
374+ logger.error("Must specify --usn-db with --snap")
375 elif args.snap and args.store_db:
376- error("Must not specify --store-db with --snap")
377+ logger.error("Must not specify --store-db with --snap")
378 elif not args.snap and not args.store_db:
379- error("Must specify --snap or --store-db")
380+ logger.error("Must specify --snap or --store-db")
381 elif args.with_cves and not args.snap:
382- error("--with-cves should only be used with --snap")
383+ logger.error("--with-cves should only be used with --snap")
384
385 ignore_pockets = [pocket.strip() for pocket in args.ignore_pockets.split(",")]
386
387@@ -111,7 +111,7 @@ def main():
388 args.usn_db, args.snap, args.with_cves, ignore_pockets
389 )
390 except ValueError as e:
391- error(e)
392+ logger.error(e)
393 elif args.store_db:
394 (_, errors) = available.scan_store(
395 args.usn_db,
396@@ -122,7 +122,7 @@ def main():
397 ignore_pockets,
398 )
399 if len(errors):
400- error("Errors encountered when scanning store entries")
401+ logger.error("Errors encountered when scanning store entries")
402
403 if report != "":
404 print(report)
405diff --git a/bin/snap-verify-declaration b/bin/snap-verify-declaration
406index 7d7ee40..cb97a90 100755
407--- a/bin/snap-verify-declaration
408+++ b/bin/snap-verify-declaration
409@@ -22,7 +22,7 @@ import json
410 import sys
411 import textwrap
412
413-from reviewtools.common import error
414+from reviewtools import logger
415 import reviewtools.sr_declaration as sr_declaration
416
417
418@@ -50,12 +50,12 @@ def main():
419 )
420 args = parser.parse_args()
421
422- error_output_type = "console"
423+ output_type = "console"
424 if args.json:
425- error_output_type = "json"
426+ output_type = "json"
427
428 if not args.plugs and not args.slots:
429- error("Must specify --plugs and/or --slots", output_type=error_output_type)
430+ logger.error("Must specify --plugs and/or --slots")
431
432 # Read in the snap declaration
433 snap_decl = {"plugs": {}, "slots": {}}
434@@ -65,25 +65,22 @@ def main():
435 snap_decl["plugs"] = json.loads(plugs_file.read())
436 sr_declaration.validate_json(snap_decl["plugs"])
437 except Exception as e:
438- error("Failed to read plugs: %s" % e, output_type=error_output_type)
439+ logger.error("Failed to read plugs: %s" % e)
440 if args.slots:
441 try:
442 with open(args.slots, "r") as slots_file:
443 snap_decl["slots"] = json.loads(slots_file.read())
444 sr_declaration.validate_json(snap_decl["slots"])
445 except Exception as e:
446- error("Failed to read slots: %s" % e, output_type=error_output_type)
447+ logger.error("Failed to read slots: %s" % e)
448
449 try:
450 review = sr_declaration.verify_snap_declaration(snap_decl)
451 except Exception as e:
452- error(
453- "verify_snap_declaration() raised exception for snap decl: %s" % e,
454- output_type=error_output_type,
455- )
456+ logger.error("verify_snap_declaration() raised exception for snap decl: %s" % e)
457
458 report = review.review_report
459- report.show_summary(error_output_type)
460+ report.show_summary(output_type)
461
462 rc = 0
463 if report.errors:
464diff --git a/bin/store-query b/bin/store-query
465index e6b22b8..420e81f 100755
466--- a/bin/store-query
467+++ b/bin/store-query
468@@ -35,7 +35,7 @@ import requests
469 import yaml
470
471 import reviewtools.common as common
472-from reviewtools.common import debug, error
473+from reviewtools import logger
474
475 from reviewtools.sr_common import SnapReview
476
477@@ -140,10 +140,10 @@ def _fetch(url, headers=None):
478
479 h = str(headers)
480 if url in responses and h in responses[url]:
481- debug("Cache: %s, headers=%s" % (url, headers))
482+ logger.debug("Cache: %s, headers=%s" % (url, headers))
483 return responses[url][h]
484
485- debug("Fetch: %s, headers=%s" % (url, headers))
486+ logger.debug("Fetch: %s, headers=%s" % (url, headers))
487 if headers is None:
488 r = requests.get(url)
489 else:
490@@ -152,7 +152,7 @@ def _fetch(url, headers=None):
491 if r.status_code != 200:
492 raise Exception("Status code: %s (%s)" % (r.status_code, r.headers))
493
494- debug("Response headers=%s" % r.headers)
495+ logger.debug("Response headers=%s" % r.headers)
496
497 if url not in responses:
498 responses[url] = {}
499@@ -264,7 +264,7 @@ def _get_snap_yaml(snap_name, channel=None, arch=None):
500 ):
501 return yaml.load(item["snap-yaml"], Loader=yaml.SafeLoader)
502
503- debug(format_resp(res, output_json=True))
504+ logger.debug(format_resp(res, output_json=True))
505 raise Exception(
506 "Could not find snap-yaml for (channel=%s, arch=%s)" % (channel, arch)
507 )
508@@ -360,10 +360,12 @@ def main():
509 args = parser.parse_args()
510
511 if args.name_or_id is None and args.snap_id is None:
512- error("Must specify a snap name or snap id. Aborting")
513+ logger.error("Must specify a snap name or snap id. Aborting")
514
515 if not args.snap_decl and not args.snap_info and not args.snap_yaml:
516- error("Must specify one of --snap-decl, --snap-info or --snap-yaml. Aborting")
517+ logger.error(
518+ "Must specify one of --snap-decl, --snap-info or --snap-yaml. Aborting"
519+ )
520
521 # Note snap names are lower case, with numbers and '-' but snap ids are
522 # alphanumerics of exactly 32. While possible that a snap-id and a name
523@@ -398,7 +400,7 @@ def main():
524 if mf < 0:
525 raise ValueError
526 except ValueError:
527- error("--max-format should be 'all' or integer >= 0")
528+ logger.error("--max-format should be 'all' or integer >= 0")
529
530 if args.max_format == "all":
531 snap_decl = _get_all_snap_declarations_by_id(snap_id)
532@@ -416,4 +418,4 @@ if __name__ == "__main__":
533 try:
534 main()
535 except KeyboardInterrupt:
536- error("Aborted.")
537+ logger.error("Aborted.")
538diff --git a/reviewtools/__init__.py b/reviewtools/__init__.py
539index e69de29..4ce6539 100644
540--- a/reviewtools/__init__.py
541+++ b/reviewtools/__init__.py
542@@ -0,0 +1,16 @@
543+import logging
544+
545+
546+class ShutdownHandler(logging.StreamHandler):
547+ def emit(self, record):
548+ super().emit(record)
549+ if record.levelno >= logging.ERROR:
550+ exit(1)
551+
552+
553+logger = logging.getLogger(__name__)
554+
555+handler = ShutdownHandler()
556+myFormatter = logging.Formatter("%(levelname)s: %(message)s")
557+handler.setFormatter(myFormatter)
558+logger.addHandler(handler)
559diff --git a/reviewtools/available.py b/reviewtools/available.py
560index 5b0dd3c..94bfbe1 100755
561--- a/reviewtools/available.py
562+++ b/reviewtools/available.py
563@@ -18,10 +18,8 @@ import os
564 import shutil
565 import tempfile
566
567+from reviewtools import logger
568 from reviewtools.common import (
569- error,
570- debug,
571- warn,
572 open_file_write,
573 read_file_as_json_dict,
574 MKDTEMP_PREFIX,
575@@ -356,7 +354,7 @@ def _email_report_for_pkg(pkg_db, seen_db):
576
577 email.send(email_to_addr, subj, body, bcc)
578
579- debug("Sent email for '%s'" % pkgname)
580+ logger.debug("Sent email for '%s'" % pkgname)
581 return (email_to_addr, subj, body)
582
583
584@@ -469,7 +467,7 @@ def scan_store(
585 continue
586
587 if body is None: # pragma: nocover
588- debug("Skipped email for '%s': up to date" % pkg_db["name"])
589+ logger.debug("Skipped email for '%s': up to date" % pkg_db["name"])
590
591 if seen_db_fn:
592 _update_seen(seen_db_fn, seen_db, pkg_db)
593@@ -477,7 +475,7 @@ def scan_store(
594 if len(errors) > 0:
595 for p in errors:
596 for e in errors[p]:
597- warn("%s: %s" % (p, e))
598+ logger.warning("%s: %s" % (p, e))
599
600 return sent, errors
601
602@@ -489,7 +487,7 @@ def scan_snap(secnot_db_fn, snap_fn, with_cves=False, ignore_pockets=list()):
603 snap = SnapContainer(snap_fn)
604 (man, dpkg) = snap.get_snap_manifest()
605 except ContainerException as e:
606- error(str(e))
607+ logger.error(str(e))
608 man = get_faked_build_and_stage_packages(man)
609
610 # Use dpkg.list when the snap ships it in a spot we honor. This is limited
611diff --git a/reviewtools/common.py b/reviewtools/common.py
612index eaaadee..2b8472e 100644
613--- a/reviewtools/common.py
614+++ b/reviewtools/common.py
615@@ -20,6 +20,7 @@ import copy
616 from enum import Enum
617 import inspect
618 import json
619+from reviewtools import logger
620 import os
621 from pkg_resources import resource_filename
622 import re
623@@ -229,51 +230,9 @@ class ReviewBase(object):
624 #
625
626
627-def error(out, exit_code=1, do_exit=True, output_type=None):
628- """Print error message and exit"""
629- global REPORT_OUTPUT
630- if output_type is None:
631- output_type = REPORT_OUTPUT
632-
633- if output_type == "json":
634- report = Report()
635- report.add_result("runtime-errors", "error", "msg", out, manual_review=True)
636- report.show_results(output_type)
637- else:
638- print("ERROR: %s" % (out), file=sys.stderr)
639-
640- if do_exit:
641- sys.exit(exit_code)
642-
643-
644-def warn(out):
645- """Print warning message"""
646- try:
647- print("WARN: %s" % (out), file=sys.stderr)
648- except IOError:
649- pass
650-
651-
652-def msg(out, output=sys.stdout):
653- """Print message"""
654- try:
655- print("%s" % (out), file=output)
656- except IOError:
657- pass
658-
659-
660-def debug(out):
661- """Print debug message"""
662- if "SNAP_DEBUG" in os.environ:
663- try:
664- print("DEBUG: %s" % (out), file=sys.stderr)
665- except IOError:
666- pass
667-
668-
669 def cmd(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT):
670 """Try to execute the given command."""
671- debug(" ".join(command))
672+ logger.debug(" ".join(command))
673 try:
674 sp = subprocess.Popen(command, stdout=stdout, stderr=stderr)
675 except OSError as ex:
676@@ -595,14 +554,14 @@ def _unpack_rock_tar(rock_pkg, dest):
677 # https://docs.python.org/3/library/tarfile.html#tarfile.TarFile.extractall
678 for name in tar.getnames():
679 if name.startswith("..") or name.startswith("/"):
680- error(
681+ logger.error(
682 "Bad path %s while extracting archive at %s"
683 % (name, rock_pkg)
684 )
685
686 tar.extractall(path=d)
687 except Exception as e:
688- error("Unexpected exception while unpacking rock %s" % e)
689+ logger.error("Unexpected exception while unpacking rock %s" % e)
690 if os.path.isdir(d):
691 recursive_rm(d)
692
693@@ -615,17 +574,17 @@ def _unpack_rock_tar(rock_pkg, dest):
694
695 return dest
696 else:
697- error(error_msg)
698+ logger.error(error_msg)
699
700
701 def check_dir(dest):
702 if dest is not None and os.path.exists(dest):
703- error("'%s' exists. Aborting." % dest)
704+ logger.error("'%s' exists. Aborting." % dest)
705
706
707 def check_fn(fn):
708 if not os.path.isfile(fn):
709- error("Could not find '%s'" % fn)
710+ logger.error("Could not find '%s'" % fn)
711 pkg = fn
712 if not pkg.startswith("/"):
713 pkg = os.path.abspath(pkg)
714@@ -636,7 +595,7 @@ def check_max_pkg_size(pkg):
715 size = os.stat(pkg)[stat.ST_SIZE]
716 max = MAX_COMPRESSED_SIZE * 1024 * 1024 * 1024
717 if size > max:
718- error(
719+ logger.error(
720 "compressed file is too large (%dM > %dM)"
721 % (size / 1024 / 1024, max / 1024 / 1024)
722 )
723@@ -654,7 +613,7 @@ def unpack_rock(fn, dest=None):
724 if tarfile.is_tarfile(pkg):
725 return _unpack_rock_tar(fn, dest)
726
727- error("Unsupported package format (not tar)")
728+ logger.error("Unsupported package format (not tar)")
729
730
731 def open_file_read(path):
732@@ -895,7 +854,7 @@ def check_results(
733 def read_file_as_json_dict(fn):
734 """Read in filename as json dict"""
735 # XXX: consider reading in as stream
736- debug("Loading: %s" % fn)
737+ logger.debug("Loading: %s" % fn)
738 raw = {}
739 with open_file_read(fn) as fd:
740 try:
741@@ -965,7 +924,7 @@ def build_manifest_from_rock_tar(man_fn, unpack_tmp_dir):
742
743 if not dpkg_query:
744 recursive_rm(unpack_tmp_dir)
745- error("%s not in %s" % (man_fn, unpack_tmp_dir))
746+ logger.error("%s not in %s" % (man_fn, unpack_tmp_dir))
747
748 return build_man_from_dpkg_query_file_content(dpkg_query)
749
750@@ -1037,7 +996,7 @@ def extract_dpkg_query_file_from_rock(dpkg_query, unpack_tmp_dir):
751 if dpkg_query:
752 return dpkg_query
753 except Exception as e:
754- error("Could not extract manifest %s" % e)
755+ logger.error("Could not extract manifest %s" % e)
756 recursive_rm(unpack_tmp_dir)
757
758 return dpkg_query
759@@ -1061,7 +1020,7 @@ def read_snapd_base_declaration():
760 if not os.path.exists(bd_fn):
761 bd_fn = resource_filename(__name__, "data/snapd-base-declaration.yaml")
762 if not os.path.exists(bd_fn):
763- error("could not find '%s'" % bd_fn)
764+ logger.error("could not find '%s'" % bd_fn)
765 fd = open_file_read(bd_fn)
766 contents = fd.read()
767 fd.close()
768@@ -1128,12 +1087,12 @@ def initialize_environment_variables():
769 os.environ["SNAP_USER_COMMON"] = (
770 "%s/snap/review-tools/common" % os.environ["HOME"]
771 )
772- debug(
773+ logger.debug(
774 "SNAP_USER_COMMON not set. Defaulting to %s"
775 % os.environ["SNAP_USER_COMMON"]
776 )
777 if not os.path.exists(os.environ["SNAP_USER_COMMON"]):
778- error(
779+ logger.error(
780 "SNAP_USER_COMMON not set and %s does not exist"
781 % os.environ["SNAP_USER_COMMON"]
782 )
783@@ -1162,9 +1121,9 @@ def fetch_usn_db(args):
784 ):
785 rc, out = cmd([fetchdb, "%s.bz2" % usndb])
786 if rc != 0:
787- error(out)
788+ logger.error(out)
789 else:
790- debug("Reusing %s" % usndb)
791+ logger.debug("Reusing %s" % usndb)
792 os.chdir(curdir)
793 return usndb
794
795diff --git a/reviewtools/sr_declaration.py b/reviewtools/sr_declaration.py
796index edfe023..e4df23b 100644
797--- a/reviewtools/sr_declaration.py
798+++ b/reviewtools/sr_declaration.py
799@@ -15,8 +15,9 @@
800 # along with this program. If not, see <http://www.gnu.org/licenses/>.
801
802 from __future__ import print_function
803+from reviewtools import logger
804 from reviewtools.sr_common import SnapReview, SnapReviewException
805-from reviewtools.common import error, ReviewBase, read_snapd_base_declaration
806+from reviewtools.common import ReviewBase, read_snapd_base_declaration
807 from reviewtools.overrides import sec_iface_ref_overrides
808 from reviewtools.schemas.schema_validator import load_schema
809 import copy
810@@ -1521,7 +1522,7 @@ def verify_snap_declaration(snap_decl, base_decl=None):
811 try:
812 SnapReviewDeclaration._verify_declaration(review, base_decl, base=True)
813 except Exception as e: # pragma: nocover
814- error("_verify_declaration() raised exception for base decl: %s" % e)
815+ logger.error("_verify_declaration() raised exception for base decl: %s" % e)
816
817 # First make sure that the interfaces in the snap declaration are known to
818 # the base declaration
819@@ -1543,6 +1544,6 @@ def verify_snap_declaration(snap_decl, base_decl=None):
820 try:
821 SnapReviewDeclaration._verify_declaration(review, snap_decl, base=False)
822 except Exception as e: # pragma: nocover
823- error("_verify_declaration() raised exception for snap decl: %s" % e)
824+ logger.error("_verify_declaration() raised exception for snap decl: %s" % e)
825
826 return review
827diff --git a/reviewtools/store.py b/reviewtools/store.py
828index e84cd00..2d0a3ac 100644
829--- a/reviewtools/store.py
830+++ b/reviewtools/store.py
831@@ -19,9 +19,8 @@ import yaml
832
833 import reviewtools.debversion as debversion
834
835+from reviewtools import logger
836 from reviewtools.common import (
837- debug,
838- warn,
839 get_os_codename,
840 assign_type_to_dict_values,
841 _add_error, # make a class
842@@ -233,7 +232,7 @@ def get_pkg_revisions(item, secnot_db, errors, pkg_type="snap", ignore_pockets=l
843 continue
844
845 r = str(rev["revision"]) # ensure yaml and json agree on type
846- debug("Checking %s r%s" % (item["name"], r))
847+ logger.debug("Checking %s r%s" % (item["name"], r))
848
849 if "manifest_yaml" not in rev:
850 _add_error(
851@@ -359,11 +358,11 @@ def get_staged_and_build_packages_from_manifest(m):
852 If not, obtain it from stage-packages for various parts instead
853 """
854 if "parts" not in m:
855- debug("Could not find 'parts' in manifest")
856+ logger.debug("Could not find 'parts' in manifest")
857 return None
858
859 if not m["parts"]:
860- debug("'parts' exists in manifest but it is empty")
861+ logger.debug("'parts' exists in manifest but it is empty")
862 return None
863
864 d = {}
865@@ -407,18 +406,18 @@ def get_staged_and_build_packages_from_manifest(m):
866 if len(d) == 0:
867 return None
868
869- debug("\n" + pprint.pformat(d))
870+ logger.debug("\n" + pprint.pformat(d))
871 return d
872
873
874 def get_staged_packages_from_rock_manifest(m):
875 """Obtain list of packages in stage-packages if section is present."""
876 if "stage-packages" not in m:
877- debug("Could not find 'stage-packages' in manifest")
878+ logger.debug("Could not find 'stage-packages' in manifest")
879 return None
880
881 if not m["stage-packages"]:
882- debug("'stage-packages' exists in manifest but it is empty")
883+ logger.debug("'stage-packages' exists in manifest but it is empty")
884 return None
885
886 d = {}
887@@ -426,7 +425,7 @@ def get_staged_packages_from_rock_manifest(m):
888 if len(d) == 0:
889 return None
890
891- debug("\n" + pprint.pformat(d))
892+ logger.debug("\n" + pprint.pformat(d))
893 return d
894
895
896@@ -440,11 +439,11 @@ def get_packages_from_manifest_section(d, manifest_section, package_type):
897 """
898 for entry in manifest_section:
899 if "=" not in entry:
900- warn("'%s' not properly formatted. Skipping" % entry)
901+ logger.warning("'%s' not properly formatted. Skipping" % entry)
902 continue
903 pkg, ver = entry.split("=")
904 if pkg in update_binaries_ignore:
905- debug("Skipping ignored binary: '%s'" % pkg)
906+ logger.debug("Skipping ignored binary: '%s'" % pkg)
907 continue
908 if package_type not in d:
909 d[package_type] = {}
910@@ -467,7 +466,7 @@ def get_packages_from_rock_manifest_section(d, manifest_section, package_type):
911 # rock manifest v1 stage-packages section is a list of
912 # "<binpkg1>=<version>,<srcpkg1>=<src version>"
913 if "=" not in entry or "," not in entry:
914- warn("'%s' not properly formatted. Skipping" % entry)
915+ logger.warning("'%s' not properly formatted. Skipping" % entry)
916 continue
917 pkg_info = entry.split(",")
918 if len(pkg_info) == 2:
919@@ -485,7 +484,7 @@ def get_packages_from_rock_manifest_section(d, manifest_section, package_type):
920 binary_pkg_name = arch_qualifier_parts[0]
921 ver = binary_pkg[1]
922 if binary_pkg_name in update_binaries_ignore:
923- debug("Skipping ignored binary: '%s'" % binary_pkg_name)
924+ logger.debug("Skipping ignored binary: '%s'" % binary_pkg_name)
925 continue
926 if package_type not in d:
927 d[package_type] = {}
928@@ -494,10 +493,10 @@ def get_packages_from_rock_manifest_section(d, manifest_section, package_type):
929 if ver not in d[package_type][binary_pkg_name]:
930 d[package_type][binary_pkg_name].append(ver)
931 else:
932- warn("'%s' not properly formatted. Skipping" % pkg_info)
933+ logger.warning("'%s' not properly formatted. Skipping" % pkg_info)
934 continue
935 else:
936- warn("'%s' not properly formatted. Skipping" % pkg_info)
937+ logger.warning("'%s' not properly formatted. Skipping" % pkg_info)
938 continue
939
940
941@@ -544,7 +543,7 @@ def get_secnots_for_manifest(
942 ignore_pockets=list(),
943 ):
944 """Find new security notifications for packages in the manifest"""
945- debug(manifest_type + "/manifest.yaml:\n" + pprint.pformat(manifest))
946+ logger.debug(manifest_type + "/manifest.yaml:\n" + pprint.pformat(manifest))
947 stage_and_build_pkgs = None
948 rel = get_ubuntu_release_from_manifest(
949 manifest, manifest_type
950@@ -561,7 +560,7 @@ def get_secnots_for_manifest(
951
952 pending_secnots = {}
953 if stage_and_build_pkgs is None:
954- debug("no stage-packages found")
955+ logger.debug("no stage-packages found")
956 return pending_secnots
957 # Since stage_and_build_pkgs can have stage-packages and build-packages
958 # keys, adding secnots into each group
959@@ -594,7 +593,7 @@ def get_secnots_for_manifest(
960 if key in manifest["parts"][part]:
961 for entry in manifest["parts"][part][key]:
962 if "=" not in entry:
963- warn(
964+ logger.warning(
965 "'%s' not properly "
966 "formatted. Skipping" % entry
967 )
968@@ -616,7 +615,7 @@ def get_secnots_for_manifest(
969 secnotversion = secnot_db[rel][pkg][secnot]["version"]
970
971 if debversion.compare(pkgversion, secnotversion) < 0:
972- debug(
973+ logger.debug(
974 "adding %s: %s (pkg:%s < secnot:%s)"
975 % (
976 pkg,
977@@ -641,7 +640,7 @@ def get_secnots_for_manifest(
978 else:
979 pending_secnots[pkg_type][pkg].append(secnot)
980 else:
981- debug(
982+ logger.debug(
983 "skipping %s: %s (pkg:%s >= secnot:%s)"
984 % (
985 pkg,
986@@ -675,7 +674,7 @@ def get_ubuntu_release_from_manifest_snap(m):
987 if "installed-snaps" in m["parts"][part]:
988 for entry in m["parts"][part]["installed-snaps"]:
989 if "=" not in entry:
990- warn("'%s' not properly formatted. Skipping" % entry)
991+ logger.warning("'%s' not properly formatted. Skipping" % entry)
992 continue
993 pkg = entry.split("=")[0] # we don't care about the version
994
995@@ -689,7 +688,7 @@ def get_ubuntu_release_from_manifest_snap(m):
996 ubuntu_release = get_os_codename(
997 m["snapcraft-os-release-id"], m["snapcraft-os-release-version-id"]
998 )
999- debug("Ubuntu release=%s" % ubuntu_release)
1000+ logger.debug("Ubuntu release=%s" % ubuntu_release)
1001 return ubuntu_release
1002 except ValueError:
1003 pass
1004@@ -720,7 +719,7 @@ def get_ubuntu_release_from_manifest_snap(m):
1005 ubuntu_release = get_os_codename(
1006 "ubuntu", m["snapcraft-os-release-version-id"]
1007 )
1008- debug(
1009+ logger.debug(
1010 "Could not determine Ubuntu release (non-core base)."
1011 "Guessing based on snapcraft-os-release-version-id: %s"
1012 % (m["snapcraft-os-release-version-id"])
1013@@ -731,7 +730,7 @@ def get_ubuntu_release_from_manifest_snap(m):
1014 if ubuntu_release is None:
1015 # no installed snaps, use default
1016 if len(installed_snaps) == 0:
1017- debug(
1018+ logger.debug(
1019 "Could not determine Ubuntu release (non-core base with "
1020 "no "
1021 "installed snaps). Defaulting to '%s'" % default
1022@@ -757,7 +756,7 @@ def get_ubuntu_release_from_manifest_rock(m):
1023 ubuntu_release = get_os_codename(
1024 m["os-release-id"], str(m["os-release-version-id"])
1025 )
1026- debug("Ubuntu release=%s" % ubuntu_release)
1027+ logger.debug("Ubuntu release=%s" % ubuntu_release)
1028 except ValueError:
1029 pass
1030 else:
1031@@ -775,7 +774,7 @@ def get_ubuntu_release_from_manifest(m, m_type="snap"):
1032 ubuntu_release = get_ubuntu_release_from_manifest_rock(m)
1033 else:
1034 raise TypeError("Unsupported manifest type %s" % m_type)
1035- debug("Ubuntu release=%s" % ubuntu_release)
1036+ logger.debug("Ubuntu release=%s" % ubuntu_release)
1037
1038 return ubuntu_release
1039
1040@@ -789,5 +788,5 @@ def get_snapcraft_version_from_manifest(m):
1041 try:
1042 return debversion.DebVersion(m["snapcraft-version"])
1043 except ValueError as e:
1044- warn("Invalid Snapcraft version: %s" % e)
1045+ logger.warning("Invalid Snapcraft version: %s" % e)
1046 return None
1047diff --git a/tests/test-dump-tool.sh.expected b/tests/test-dump-tool.sh.expected
1048index 702666e..1cc4104 100644
1049--- a/tests/test-dump-tool.sh.expected
1050+++ b/tests/test-dump-tool.sh.expected
1051@@ -14,14 +14,14 @@ Done: 10 revisions read
1052
1053 = Test --file --warn-if-empty =
1054 Running: dump-tool --warn-if-empty --file ./tests/test-store-dump.1
1055-WARN: Skipping 4ZWSHtNHDBdBsoGCTVgKkk8F9MtvjZS1|1: empty
1056-WARN: Skipping 4ZWSHtNHDBdBsoGCTVgKkk8F9MtvjZS1|2: empty
1057-WARN: Skipping 4ZWSHtNHDBdBsoGCTVgKkk8F9MtvjZS1|3: empty
1058-WARN: Skipping 99T7MUlRhtI3U0QFgl5mXXESAiSwt776|1: empty
1059-WARN: Skipping UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH|1: empty
1060-WARN: Skipping UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH|2: empty
1061-WARN: Skipping UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH|3: empty
1062-WARN: Skipping UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH|4: empty
1063+WARNING: Skipping 4ZWSHtNHDBdBsoGCTVgKkk8F9MtvjZS1|1: empty
1064+WARNING: Skipping 4ZWSHtNHDBdBsoGCTVgKkk8F9MtvjZS1|2: empty
1065+WARNING: Skipping 4ZWSHtNHDBdBsoGCTVgKkk8F9MtvjZS1|3: empty
1066+WARNING: Skipping 99T7MUlRhtI3U0QFgl5mXXESAiSwt776|1: empty
1067+WARNING: Skipping UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH|1: empty
1068+WARNING: Skipping UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH|2: empty
1069+WARNING: Skipping UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH|3: empty
1070+WARNING: Skipping UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH|4: empty
1071
1072 = Test --db-file =
1073 Running: dump-tool --db-file ./tests/test-store-dump.1.json
1074diff --git a/tests/test-snap-verify-declaration.sh.expected b/tests/test-snap-verify-declaration.sh.expected
1075index 0149682..88f34ee 100644
1076--- a/tests/test-snap-verify-declaration.sh.expected
1077+++ b/tests/test-snap-verify-declaration.sh.expected
1078@@ -4,7 +4,7 @@ usage: snap-verify-declaration [-h] [--json] [--plugs PLUGS] [--slots SLOTS]
1079
1080 Check a snap declaration for errors
1081
1082-optional arguments:
1083+options:
1084 -h, --help show this help message and exit
1085 --json print json output
1086 --plugs PLUGS file specifying snap declaration for plugs
1087@@ -138,18 +138,7 @@ Running: snap-verify-declaration --plugs=./plugs
1088 ERROR: Failed to read plugs: Expecting property name enclosed in double quotes: line 2 column 1 (char 2)
1089
1090 Running: snap-verify-declaration --json --plugs=./plugs
1091-{
1092- "runtime-errors": {
1093- "error": {
1094- "msg": {
1095- "manual_review": true,
1096- "text": "Failed to read plugs: Expecting property name enclosed in double quotes: line 2 column 1 (char 2)"
1097- }
1098- },
1099- "info": {},
1100- "warn": {}
1101- }
1102-}
1103+ERROR: Failed to read plugs: Expecting property name enclosed in double quotes: line 2 column 1 (char 2)
1104
1105 Running: snap-verify-declaration --plugs=./plugs
1106 {'error': {'snap-declaration-verify_v2:valid_interface:nonexistent': {'manual_review': False,
1107@@ -208,16 +197,5 @@ Running: snap-verify-declaration --plugs=./plugs
1108 ERROR: Failed to read plugs: bare <class 'bool'> value True for 'mir:allow-auto-connection' is not allowed - this should be a string "true" instead
1109
1110 Running: snap-verify-declaration --json --plugs=./plugs
1111-{
1112- "runtime-errors": {
1113- "error": {
1114- "msg": {
1115- "manual_review": true,
1116- "text": "Failed to read plugs: bare <class 'bool'> value True for 'mir:allow-auto-connection' is not allowed - this should be a string \"true\" instead"
1117- }
1118- },
1119- "info": {},
1120- "warn": {}
1121- }
1122-}
1123+ERROR: Failed to read plugs: bare <class 'bool'> value True for 'mir:allow-auto-connection' is not allowed - this should be a string "true" instead
1124
1125diff --git a/tests/test-updates-available.sh.expected b/tests/test-updates-available.sh.expected
1126index f6957fe..47edb1c 100644
1127--- a/tests/test-updates-available.sh.expected
1128+++ b/tests/test-updates-available.sh.expected
1129@@ -1419,7 +1419,7 @@ Running: snap-updates-available --with-cves --usn-db='./tests/test-usn-unittest-
1130 }
1131
1132 Running: ./bin/snap-updates-available --usn-db='./tests/test-usn-unittest-1.db' --store-db='./tests/test-store-unittest-bad-1.db'
1133-WARN: 1ad: required field 'revisions' not found
1134+WARNING: 1ad: required field 'revisions' not found
1135 ERROR: Errors encountered when scanning store entries
1136 From: Snap Store <noreply+security-snap-review@canonical.com>
1137 To: olivier.tilloy@canonical.com
1138@@ -1655,10 +1655,10 @@ References:
1139
1140
1141 Running: ./bin/snap-updates-available --usn-db='./tests/test-usn-unittest-build-pkgs.db' --store-db='./tests/test-store-unittest-invalid-snapcraft-version.db'
1142-WARN: Invalid Snapcraft version: '4.4.3' not a valid Debian version
1143+WARNING: Invalid Snapcraft version: '4.4.3' not a valid Debian version
1144
1145 Running: ./bin/snap-updates-available --usn-db='./tests/test-usn-unittest-build-pkgs.db' --store-db='./tests/test-store-kernel-invalid-snapcraft-version.db'
1146-WARN: Invalid Snapcraft version: '2.3' not a valid Debian version
1147+WARNING: Invalid Snapcraft version: '2.3' not a valid Debian version
1148
1149 Running: snap-updates-available --usn-db='./tests/test-usn-unittest-lp1841848.db' --snap='./tests/test-check-notices_0.1_amd64.snap'
1150

Subscribers

People subscribed via source and target branches