# Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import llnl.util.tty as tty
import llnl.util.tty.color as cl
import spack.audit
import spack.repo
description = "audit configuration files, packages, etc."
section = "system"
level = "short"
[docs]def setup_parser(subparser):
# Top level flags, valid for every audit class
sp = subparser.add_subparsers(metavar="SUBCOMMAND", dest="subcommand")
# Audit configuration files
sp.add_parser("configs", help="audit configuration files")
# Https and other linting
https_parser = sp.add_parser("packages-https", help="check https in packages")
https_parser.add_argument(
"--all", action="store_true", default=False, dest="check_all", help="audit all packages"
)
# Audit package recipes
pkg_parser = sp.add_parser("packages", help="audit package recipes")
for group in [pkg_parser, https_parser]:
group.add_argument(
"name",
metavar="PKG",
nargs="*",
help="package to be analyzed (if none all packages will be processed)",
)
# List all checks
sp.add_parser("list", help="list available checks and exits")
[docs]def configs(parser, args):
reports = spack.audit.run_group(args.subcommand)
_process_reports(reports)
[docs]def packages(parser, args):
pkgs = args.name or spack.repo.path.all_package_names()
reports = spack.audit.run_group(args.subcommand, pkgs=pkgs)
_process_reports(reports)
[docs]def packages_https(parser, args):
# Since packages takes a long time, --all is required without name
if not args.check_all and not args.name:
tty.die("Please specify one or more packages to audit, or --all.")
pkgs = args.name or spack.repo.path.all_package_names()
reports = spack.audit.run_group(args.subcommand, pkgs=pkgs)
_process_reports(reports)
[docs]def list(parser, args):
for subcommand, check_tags in spack.audit.GROUPS.items():
print(cl.colorize("@*b{" + subcommand + "}:"))
for tag in check_tags:
audit_obj = spack.audit.CALLBACKS[tag]
print(" " + audit_obj.description)
if args.verbose:
for idx, fn in enumerate(audit_obj.callbacks):
print(" {0}. ".format(idx + 1) + fn.__doc__)
print()
print()
[docs]def audit(parser, args):
subcommands = {
"configs": configs,
"packages": packages,
"packages-https": packages_https,
"list": list,
}
subcommands[args.subcommand](parser, args)
def _process_reports(reports):
for check, errors in reports:
if errors:
msg = "{0}: {1} issue{2} found".format(
check, len(errors), "" if len(errors) == 1 else "s"
)
header = "@*b{" + msg + "}"
print(cl.colorize(header))
for idx, error in enumerate(errors):
print(str(idx + 1) + ". " + str(error))
raise SystemExit(1)
else:
msg = "{0}: 0 issues found.".format(check)
header = "@*b{" + msg + "}"
print(cl.colorize(header))