blob: 758dace1a6820802f80cbed1ce0f30aca4034bf2 [file] [log] [blame]
# Copyright 2012 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generate an HTML file containing license info for all installed packages.
Documentation on this script is also available here:
https://dev.chromium.org/chromium-os/licensing/licensing-for-chromiumos-developers
End user (i.e. package owners) documentation is here:
https://dev.chromium.org/chromium-os/licensing/licensing-for-chromiumos-package-owners
The license bits for each package are automatically generated by
src/scripts/hooks/install/gen-package-licenses.sh which gets run
by emerge as part of a package build (by running this script with
--hook /path/to/tmp/portage/build/tree/for/that/package).
These license bits are stored in `$SYSROOT/var/db/pkg/$CATEGORY/$PACKAGE` as
the build continues.
license.py script will subsequently gather the license bits from there to
compose the final license file, unless this script is run with
`--generate-licenses`, in which case the script will regenerate the license
bits.
If license bits are missing, they are generated on the fly if you were running
with sudo. If you didn't use sudo, this on the fly late generation will fail
and act as a warning that your prebuilts were missing package build time
licenses.
You can check the licenses and/or generate a HTML file for a list of
packages using --package or -p:
(cr) licenses --package "dev-libs/libatomic_ops-7.2d" --package \
"net-misc/wget-1.14" --board $BOARD -o out.html
Note that you'll want to use --generate-licenses to force regeneration of the
licensing bits from a package source you may have just modified but not rebuilt.
If you want to check licensing against all ChromeOS packages, you should
run `cros build-packages --board=$BOARD` to build everything and then run this
script with --all-packages.
By default, when no package is specified, this script processes all
packages for $BOARD.
"""
import logging
import os
from chromite.lib import build_target_lib
from chromite.lib import commandline
from chromite.lib import cros_build_lib
from chromite.licensing import licenses_lib
def LoadPackageInfo(
sysroot, all_packages, generateMissing, packages, placeholder
):
"""Do the work when we're not called as a hook."""
logging.info("Processing sysroot %s", sysroot)
detect_packages = not packages
if detect_packages:
# If no packages were specified, we look up the full list.
if placeholder:
# A random set of names to generate the placeholder file.
packages = [
"sys-libs/placeholder-1-r3",
"chromeos-base/placeheld-1.0",
]
else:
packages = licenses_lib.ListInstalledPackages(sysroot, all_packages)
assert packages, f"{sysroot}: could not find any packages"
logging.debug(
"Initial Package list to work through:\n%s", "\n".join(sorted(packages))
)
licensing = licenses_lib.Licensing(
sysroot, packages, generateMissing, placeholder=placeholder
)
licensing.LoadPackageInfo()
logging.debug(
"Package list to skip:\n%s",
"\n".join([p for p in sorted(packages) if licensing.packages[p].skip]),
)
logging.debug(
"Package list left to work through:\n%s",
"\n".join(
[p for p in sorted(packages) if not licensing.packages[p].skip]
),
)
licensing.ProcessPackageLicenses()
return licensing
def get_parser() -> commandline.ArgumentParser:
"""Return a command line parser."""
parser = commandline.ArgumentParser(usage=__doc__)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
"-b", "--board", help="which board to run for, like x86-alex"
)
group.add_argument(
"--sysroot",
type="path",
help="which sysroot to run on (e.g. /build/eve)",
)
group.add_argument(
"--placeholder",
action="store_true",
help="Generate a placeholder file (for testing).",
)
parser.add_argument(
"-p",
"--package",
action="append",
default=[],
dest="packages",
help="check the license of the package, e.g.,"
"dev-libs/libatomic_ops-7.2d",
)
parser.add_argument(
"-a",
"--all-packages",
action="store_true",
help="Run licensing against all packages in the "
"build tree, instead of just virtual/target-os "
"dependencies.",
)
parser.add_argument(
"-g",
"--generate-licenses",
action="store_true",
dest="gen_licenses",
help="Generate license information, if missing.",
)
parser.add_argument(
"-o",
"--output",
type="path",
help="which html file to create with output",
)
parser.add_argument(
"-c",
"--compress-output",
action="store_true",
help="whether to compress the html output. If true, output must end in "
"an appropriate extension.",
)
return parser
def main(args):
parser = get_parser()
opts = parser.parse_args(args)
if not opts.output and not opts.gen_licenses:
parser.error("You must specify --output and/or --generate-licenses")
sysroot = opts.sysroot or build_target_lib.get_default_sysroot_path(
opts.board
)
if (
opts.output
and os.path.exists(opts.output)
and not os.path.isfile(opts.output)
):
parser.error(f"--output must point to a file: {opts.output}")
if opts.compress_output:
if not opts.output:
parser.error("--compress-output requires --output")
if (
cros_build_lib.CompressionExtToType(opts.output)
== cros_build_lib.CompressionType.NONE
):
parser.error(
"if --compress-output is specified, --output must end in "
f"appropriate compression format but is: {opts.output}"
)
licensing = LoadPackageInfo(
sysroot,
opts.all_packages,
opts.gen_licenses,
opts.packages,
placeholder=opts.placeholder,
)
if opts.output:
licensing.GenerateHTMLLicenseOutput(
opts.output, compress_output=opts.compress_output
)