blob: 58e79f87f7e9e9ba6675a215c6cea3360ce89527 [file] [log] [blame]
Steve Winslowfd31b9b2021-04-20 23:04:52 -04001# Copyright (c) 2021 The Linux Foundation
2#
3# SPDX-License-Identifier: Apache-2.0
4
5import os
6import uuid
7
8from west.commands import WestCommand
9from west import log
10
11from zspdx.sbom import SBOMConfig, makeSPDX, setupCmakeQuery
12
13SPDX_DESCRIPTION = """\
14This command creates an SPDX 2.2 tag-value bill of materials
15following the completion of a Zephyr build.
16
17Prior to the build, an empty file must be created at
18BUILDDIR/.cmake/api/v1/query/codemodel-v2 in order to enable
19the CMake file-based API, which the SPDX command relies upon.
20This can be done by calling `west spdx --init` prior to
21calling `west build`."""
22
23class ZephyrSpdx(WestCommand):
24 def __init__(self):
25 super().__init__(
26 'spdx',
27 'create SPDX bill of materials',
28 SPDX_DESCRIPTION)
29
30 def do_add_parser(self, parser_adder):
31 parser = parser_adder.add_parser(self.name,
32 help=self.help,
33 description = self.description)
34
Martí Bolívar91f02122021-05-27 10:09:24 -070035 # If you update these options, make sure to keep the docs in
36 # doc/guides/west/zephyr-cmds.rst up to date.
Steve Winslowfd31b9b2021-04-20 23:04:52 -040037 parser.add_argument('-i', '--init', action="store_true",
38 help="initialize CMake file-based API")
39 parser.add_argument('-d', '--build-dir',
40 help="build directory")
41 parser.add_argument('-n', '--namespace-prefix',
42 help="namespace prefix")
43 parser.add_argument('-s', '--spdx-dir',
44 help="SPDX output directory")
45 parser.add_argument('--analyze-includes', action="store_true",
46 help="also analyze included header files")
47 parser.add_argument('--include-sdk', action="store_true",
48 help="also generate SPDX document for SDK")
49
50 return parser
51
52 def do_run(self, args, unknown_args):
53 log.dbg(f"running zephyr SPDX generator")
54
55 log.dbg(f" --init is", args.init)
56 log.dbg(f" --build-dir is", args.build_dir)
57 log.dbg(f" --namespace-prefix is", args.namespace_prefix)
58 log.dbg(f" --spdx-dir is", args.spdx_dir)
59 log.dbg(f" --analyze-includes is", args.analyze_includes)
60 log.dbg(f" --include-sdk is", args.include_sdk)
61
62 if args.init:
63 do_run_init(args)
64 else:
65 do_run_spdx(args)
66
67def do_run_init(args):
68 log.inf("initializing Cmake file-based API prior to build")
69
70 if not args.build_dir:
71 log.die("Build directory not specified; call `west spdx --init --build-dir=BUILD_DIR`")
72
73 # initialize CMake file-based API - empty query file
74 query_ready = setupCmakeQuery(args.build_dir)
75 if query_ready:
76 log.inf("initialized; run `west build` then run `west spdx`")
77 else:
78 log.err("Couldn't create Cmake file-based API query directory")
79 log.err("You can manually create an empty file at $BUILDDIR/.cmake/api/v1/query/codemodel-v2")
80
81def do_run_spdx(args):
82 if not args.build_dir:
83 log.die("Build directory not specified; call `west spdx --build-dir=BUILD_DIR`")
84
85 # create the SPDX files
86 cfg = SBOMConfig()
87 cfg.buildDir = args.build_dir
88 if args.namespace_prefix:
89 cfg.namespacePrefix = args.namespace_prefix
90 else:
91 # create default namespace according to SPDX spec
92 # note that this is intentionally _not_ an actual URL where
93 # this document will be stored
94 cfg.namespacePrefix = f"http://spdx.org/spdxdocs/zephyr-{str(uuid.uuid4())}"
95 if args.spdx_dir:
96 cfg.spdxDir = args.spdx_dir
97 else:
98 cfg.spdxDir = os.path.join(args.build_dir, "spdx")
99 if args.analyze_includes:
100 cfg.analyzeIncludes = True
101 if args.include_sdk:
102 cfg.includeSDK = True
103
104 # make sure SPDX directory exists, or create it if it doesn't
105 if os.path.exists(cfg.spdxDir):
106 if not os.path.isdir(cfg.spdxDir):
107 log.err(f'SPDX output directory {cfg.spdxDir} exists but is not a directory')
108 return
109 # directory exists, we're good
110 else:
111 # create the directory
112 os.makedirs(cfg.spdxDir, exist_ok=False)
113
114 makeSPDX(cfg)