From f2feaef90b8e6760321e0fdaa8f975b25ce3c87a Mon Sep 17 00:00:00 2001 From: Rose Judge Date: Fri, 6 Sep 2019 13:47:12 -0700 Subject: [PATCH] CLI: update command line {report} options Tern's command line is a bit cluttered. This commit attempts to re-structure some of the {report} positional arguments. Namely: - Use '-f REPORT_FORMAT' to denote report format instead of '-m' - Use '-o FILE' to denote an report output file instead of '-f' - Shorten '--keep-working-dir' option to '--keep-wd' - Change '-V' to '-v' in order to get the version There are a few other various style imorovemenets to the 'tern -h' output such as changing ';' to '.' and removing an indentation. This commit also updates the README documenation to reflect the updated command line options, updates the invocation of the tests in ci/test_files_touched.py and updates tern/report/report.py to reflect the updated argument name values where applicable. Since this commit changes Tern's user interface, it will break API and not be compatible with downstream versions. Resolves #390 Signed-off-by: Rose Judge --- README.md | 14 +++++++------- ci/test_files_touched.py | 6 +++--- tern/__main__.py | 27 ++++++++++++++------------- tern/report/report.py | 16 ++++++++-------- 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index acd96a12..32fdf6c0 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ $ ./docker_run.sh workdir ternd "report -i debian:buster" > output.txt To produce a json report run ``` -$ ./docker_run.sh workdir ternd "report -m json -i debian:buster" +$ ./docker_run.sh workdir ternd "report -f json -i debian:buster" ``` What the `docker_run.sh` script does is create the directory `workdir` if not present in your current working directory and run the built container as privileged with `workdir` bind mounted to it. @@ -105,7 +105,7 @@ $ vagrant ssh Run: ``` -$ tern -l report -i debian:buster -f output.txt +$ tern -l report -i debian:buster -o output.txt ``` ## Getting Started on Linux @@ -143,7 +143,7 @@ $ pip install tern Run Tern: ``` -$ tern -l report -f output.txt -i debian:buster +$ tern -l report -o output.txt -i debian:buster ``` # Using Tern @@ -173,7 +173,7 @@ Tern creates BoM reports suitable to read over or to provide to another tool for ## Human Readable Format The default report Tern produces is a human readable report. The object of this report is to give the container developer a deeper understanding of what is installed in a container image during development. This allows a developer to glean basic information about the container such as what the true base operating system is, what the app dependencies are, if the container is using an official or personal repository for sources or binaries, whether the dependencies are at the correct versions, etc. ``` -$ tern -l report -i golang:1.12-alpine -f output.txt +$ tern -l report -i golang:1.12-alpine -o output.txt ``` ## Summary Format @@ -187,19 +187,19 @@ WARNING: Tern is meant to give guidance on what may be installed in a container ## JSON Format You can get the results in a JSON file to pass around in a network. ``` -$ tern report -m json -i golang:1.12-alpine +$ tern report -f json -i golang:1.12-alpine ``` ## YAML Format You can get the results in a YAML file to be consumed by a downstream tool or script. ``` -$ tern -l report -m yaml -i golang:1.12-alpine -f output.yaml +$ tern -l report -f yaml -i golang:1.12-alpine -o output.yaml ``` ## SPDX tag-value Format [SPDX](https://spdx.org/) is a format developed by the Linux Foundation to provide a standard way of reporting license information. Many compliance tools are compatible with SPDX. Tern follows the [SPDX specifications](https://spdx.org/specifications) specifically the tag-value format which is the most compatible format with the toolkit the organization provides. The tag-value format is the only SPDX format Tern supports. There are conversion tools available [here](https://github.com/spdx/tools) (some still in development). You can read an overview of the SPDX tag-value specification [here](./docs/spdx-tag-value-overview) and about how Tern maps its properties to the keys mandated by the spec [here](./docs/spdx-tag-value-mapping.md). ``` -$ tern -l report -m spdxtagvalue -i golang:1.12-alpine -f spdx.txt +$ tern -l report -f spdxtagvalue -i golang:1.12-alpine -o spdx.txt ``` # Running tests diff --git a/ci/test_files_touched.py b/ci/test_files_touched.py index 6723e7c5..4546878a 100644 --- a/ci/test_files_touched.py +++ b/ci/test_files_touched.py @@ -76,10 +76,10 @@ # tern/report re.compile('tern/report'): [ 'tern -l report -i golang:alpine', - 'tern -l report -m yaml -i photon:3.0', + 'tern -l report -f yaml -i photon:3.0', 'tern -l report -s -i photon:3.0', - 'tern -l report -m json -i photon:3.0', - 'tern -l report -m spdxtagvalue -i photon:3.0', + 'tern -l report -f json -i photon:3.0', + 'tern -l report -f spdxtagvalue -i photon:3.0', 'tern -l report -d samples/alpine_python/Dockerfile'], # tern/tools re.compile('tern/tools'): diff --git a/tern/__main__.py b/tern/__main__.py index 062e2d10..3dddfb29 100755 --- a/tern/__main__.py +++ b/tern/__main__.py @@ -83,25 +83,25 @@ def main(): formatter_class=argparse.RawTextHelpFormatter, prog='Tern', description=''' - Tern is a container image component curation tool. Tern retrieves + Tern is a container image component curation tool. Tern retrieves information about packages that are installed in a container image. Learn more at https://github.com/vmware/tern''') parser.add_argument('-l', '--log-stream', action='store_true', - help="Stream logs to the console;" + help="Stream logs to the console; " "Useful when running in a shell") parser.add_argument('-c', '--clear-cache', action='store_true', help="Clear the cache before running") - parser.add_argument('-k', '--keep-working-dir', action='store_true', - help="Keep the working directory after execution;" - "Useful when debugging container images") + parser.add_argument('-k', '--keep-wd', action='store_true', + help="Keep the working directory after execution." + " Useful when debugging container images") parser.add_argument('-b', '--bind-mount', action='store_true', - help="Treat working directory as a bind mount;" - "Needed when running from within a container") + help="Treat working directory as a bind mount." + " Needed when running from within a container") parser.add_argument('-r', '--redo', action='store_true', help="Repopulate the cache for found layers") # sys.version gives more information than we care to print py_ver = sys.version.replace('\n', '').split('[')[0] - parser.add_argument('-V', '--version', action='version', + parser.add_argument('-v', '--version', action='version', version="{ver_str}\n python version = {py_v}".format( ver_str=get_version(), py_v=py_ver)) subparsers = parser.add_subparsers(help='Subcommands') @@ -109,7 +109,7 @@ def main(): parser_report = subparsers.add_parser('report', help="Create a BoM report." " Run 'tern report -h' for" - " format options.") + " report format options.") parser_report.add_argument('-d', '--dockerfile', type=check_file_existence, help="Dockerfile used to build the Docker" " image") @@ -122,13 +122,14 @@ def main(): parser_report.add_argument('-s', '--summary', action='store_true', help="Summarize the report as a list of" " packages with associated information") - parser_report.add_argument('-m', '--report-format', - metavar='REPORT_MODULE', + parser_report.add_argument('-f', '--report-format', + metavar='REPORT_FORMAT', help="Format the report using one of the " "available formats: " "spdxtagvalue, json, yaml") - parser_report.add_argument('-f', '--file', default=None, - help="Write the report to a file; " + parser_report.add_argument('-o', '--output-file', default=None, + metavar='FILE', + help="Write the report to a file. " "If no file is given the default file in " "utils/constants.py will be used") parser_report.set_defaults(name='report') diff --git a/tern/report/report.py b/tern/report/report.py index 570425fe..86ac390f 100644 --- a/tern/report/report.py +++ b/tern/report/report.py @@ -40,8 +40,8 @@ def write_report(report, args): '''Write the report to a file''' - if args.file: - file_name = args.file + if args.output_file: + file_name = args.output_file else: file_name = constants.report_file with open(file_name, 'w') as f: @@ -215,7 +215,7 @@ def report_out(args, *images): report = generate_report(args, *images) if not report: logger.error("%s not a recognized plugin.", args.report_format) - elif args.file: + elif args.output_file: write_report(report, args) else: print(report) @@ -258,7 +258,7 @@ def execute_dockerfile(args): completed = False # clean up image container.remove_image(full_image.repotag) - if not args.keep_working_dir: + if not args.keep_wd: clean_image_tars(full_image) else: # cannot build the image @@ -285,7 +285,7 @@ def execute_dockerfile(args): stub_image = get_dockerfile_packages() # clean up image container.remove_image(base_image.repotag) - if not args.keep_working_dir: + if not args.keep_wd: clean_image_tars(base_image) # generate report based on what images were created if completed: @@ -294,7 +294,7 @@ def execute_dockerfile(args): report_out(args, base_image, stub_image) logger.debug('Teardown...') teardown() - if not args.keep_working_dir: + if not args.keep_wd: clean_working_dir(args.bind_mount) @@ -317,9 +317,9 @@ def execute_docker_image(args): else: # we cannot load the full image logger.warning('Cannot retrieve full image metadata') - if not args.keep_working_dir: + if not args.keep_wd: clean_image_tars(full_image) logger.debug('Teardown...') teardown() - if not args.keep_working_dir: + if not args.keep_wd: clean_working_dir(args.bind_mount)