| # 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 compression_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="str_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( |
| "--os-version", |
| help="Overall OS version when building CrOS images.", |
| ) |
| parser.add_argument( |
| "--milestone-version", |
| help="Overall OS milestone when building CrOS images.", |
| ) |
| 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="str_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) -> None: |
| 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 ( |
| compression_lib.CompressionType.from_extension(opts.output) |
| == compression_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, |
| os_version=opts.os_version, |
| milestone_version=opts.milestone_version, |
| compress_output=opts.compress_output, |
| ) |