xref: /aosp_15_r20/external/spdx-tools/examples/4-search/example_search.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1*ba677afaSXin Li// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2*ba677afaSXin Li
3*ba677afaSXin Li// Example for: *idsearcher*, *tvsaver*
4*ba677afaSXin Li
5*ba677afaSXin Li// This example demonstrates building an SPDX document for a directory's
6*ba677afaSXin Li// contents (implicitly using *builder*); searching through that directory for
7*ba677afaSXin Li// [SPDX short-form IDs](https://spdx.org/ids/); filling those IDs into the
8*ba677afaSXin Li// document's Package and File license fields; and saving the resulting document
9*ba677afaSXin Li// to disk.
10*ba677afaSXin Li// Run project: go run example_search.go project2 ../../testdata/project2/folder test.spdx
11*ba677afaSXin Li
12*ba677afaSXin Lipackage main
13*ba677afaSXin Li
14*ba677afaSXin Liimport (
15*ba677afaSXin Li	"fmt"
16*ba677afaSXin Li	"os"
17*ba677afaSXin Li
18*ba677afaSXin Li	"github.com/spdx/tools-golang/idsearcher"
19*ba677afaSXin Li
20*ba677afaSXin Li	"github.com/spdx/tools-golang/tvsaver"
21*ba677afaSXin Li)
22*ba677afaSXin Li
23*ba677afaSXin Lifunc main() {
24*ba677afaSXin Li
25*ba677afaSXin Li	// check that we've received the right number of arguments
26*ba677afaSXin Li	args := os.Args
27*ba677afaSXin Li	if len(args) != 4 {
28*ba677afaSXin Li		fmt.Printf("Usage: %v <package-name> <package-root-dir> <spdx-file-out>\n", args[0])
29*ba677afaSXin Li		fmt.Printf("  Build a SPDX 2.2 document with one package called <package-name>;\n")
30*ba677afaSXin Li		fmt.Printf("  create files with hashes corresponding to the files in <package-root-dir>;\n")
31*ba677afaSXin Li		fmt.Printf("  search for SPDX short-form IDs, and use them to fill in license data\n")
32*ba677afaSXin Li		fmt.Printf("  where possible; and save it out as a tag-value file to <spdx-file-out>.\n")
33*ba677afaSXin Li		return
34*ba677afaSXin Li	}
35*ba677afaSXin Li
36*ba677afaSXin Li	// get the command-line arguments
37*ba677afaSXin Li	packageName := args[1]
38*ba677afaSXin Li	packageRootDir := args[2]
39*ba677afaSXin Li	fileOut := args[3]
40*ba677afaSXin Li
41*ba677afaSXin Li	// to use the SPDX idsearcher package, the first step is to define a
42*ba677afaSXin Li	// idsearcher.Config2_2 struct. this config data can be reused, in case you
43*ba677afaSXin Li	// are building SPDX documents for several directories in sequence.
44*ba677afaSXin Li	config := &idsearcher.Config2_2{
45*ba677afaSXin Li
46*ba677afaSXin Li		// NamespacePrefix is a prefix that will be used to populate the
47*ba677afaSXin Li		// mandatory DocumentNamespace field in the Creation Info section.
48*ba677afaSXin Li		// Because it needs to be unique, the value that will be filled in
49*ba677afaSXin Li		// for the document will have the package name and verification code
50*ba677afaSXin Li		// appended to this prefix.
51*ba677afaSXin Li		NamespacePrefix: "https://example.com/whatever/testdata-",
52*ba677afaSXin Li
53*ba677afaSXin Li		// CreatorType and Creator, from builder.Config2_2, are not needed for
54*ba677afaSXin Li		// idsearcher.Config2_2. Because it is automated and doesn't assume
55*ba677afaSXin Li		// further review, the following two Creator fields are filled in:
56*ba677afaSXin Li		// Creator: Tool: github.com/spdx/tools-golang/builder
57*ba677afaSXin Li		// Creator: Tool: github.com/spdx/tools-golang/idsearcher
58*ba677afaSXin Li
59*ba677afaSXin Li		// You can define one or more paths that should be ignored
60*ba677afaSXin Li		// when walking through the directory. This is intended to omit files
61*ba677afaSXin Li		// that are located within the package's directory, but which should
62*ba677afaSXin Li		// be omitted from the SPDX document.
63*ba677afaSXin Li		// This is directly passed through to builder, and uses the same
64*ba677afaSXin Li		// format as shown in examples/3-build/example_build.go.
65*ba677afaSXin Li		BuilderPathsIgnored: []string{
66*ba677afaSXin Li
67*ba677afaSXin Li			// ignore all files in the .git/ directory at the package root
68*ba677afaSXin Li			"/.git/",
69*ba677afaSXin Li
70*ba677afaSXin Li			// ignore all files in all __pycache__/ directories, anywhere
71*ba677afaSXin Li			// within the package directory tree
72*ba677afaSXin Li			"**/__pycache__/",
73*ba677afaSXin Li
74*ba677afaSXin Li			// ignore the file with this specific path relative to the
75*ba677afaSXin Li			// package root
76*ba677afaSXin Li			"/.ignorefile",
77*ba677afaSXin Li
78*ba677afaSXin Li			// or ignore all files with this filename, anywhere within the
79*ba677afaSXin Li			// package directory tree
80*ba677afaSXin Li			"**/.DS_Store",
81*ba677afaSXin Li		},
82*ba677afaSXin Li
83*ba677afaSXin Li		// Finally, SearcherPathsIgnored lists certain paths that should not be
84*ba677afaSXin Li		// searched by idsearcher, even if those paths have Files present (and
85*ba677afaSXin Li		// had files filled in by builder). This is useful, for instance, if
86*ba677afaSXin Li		// your project has some directories or files with
87*ba677afaSXin Li		// "SPDX-License-Identifier:" tags, but for one reason or another you
88*ba677afaSXin Li		// want to exclude those files' tags from being picked up by the
89*ba677afaSXin Li		// searcher.
90*ba677afaSXin Li		// SearcherPathsIgnored uses the same format as BuilderPathsIgnored.
91*ba677afaSXin Li		SearcherPathsIgnored: []string{
92*ba677afaSXin Li
93*ba677afaSXin Li			// Example for the Linux kernel: ignore the documentation file
94*ba677afaSXin Li			// which explains how to use SPDX short-form IDs (and therefore
95*ba677afaSXin Li			// has a bunch of "SPDX-License-Identifier:" tags that we wouldn't
96*ba677afaSXin Li			// want to pick up).
97*ba677afaSXin Li			"/Documentation/process/license-rules.rst",
98*ba677afaSXin Li
99*ba677afaSXin Li			// Similar example for the Linux kernel: ignore all files in the
100*ba677afaSXin Li			// /LICENSES/ directory.
101*ba677afaSXin Li			"/LICENSES/",
102*ba677afaSXin Li		},
103*ba677afaSXin Li	}
104*ba677afaSXin Li
105*ba677afaSXin Li	// now, when we actually ask idsearcher to walk through a directory and
106*ba677afaSXin Li	// build an SPDX document, we need to give it three things:
107*ba677afaSXin Li	//   - what to name the package; and
108*ba677afaSXin Li	//   - where the directory is located on disk; and
109*ba677afaSXin Li	//   - the config object we just defined.
110*ba677afaSXin Li	// these are the same arguments needed for builder, and in fact they get
111*ba677afaSXin Li	// passed through to builder (with the relevant data from the config
112*ba677afaSXin Li	// object extracted behind the scenes).
113*ba677afaSXin Li	doc, err := idsearcher.BuildIDsDocument2_2(packageName, packageRootDir, config)
114*ba677afaSXin Li	if err != nil {
115*ba677afaSXin Li		fmt.Printf("Error while building document: %v\n", err)
116*ba677afaSXin Li		return
117*ba677afaSXin Li	}
118*ba677afaSXin Li
119*ba677afaSXin Li	// if we got here, the document has been created.
120*ba677afaSXin Li	// all file hashes and the package verification code have been filled in
121*ba677afaSXin Li	// appropriately by builder.
122*ba677afaSXin Li	// And, all files with "SPDX-License-Identifier:" tags have had their
123*ba677afaSXin Li	// licenses extracted into LicenseInfoInFiles and LicenseConcluded for
124*ba677afaSXin Li	// each file by idsearcher. The PackageLicenseInfoFromFiles field will
125*ba677afaSXin Li	// also be filled in with all license identifiers.
126*ba677afaSXin Li	fmt.Printf("Successfully created document and searched for IDs for package %s\n", packageName)
127*ba677afaSXin Li
128*ba677afaSXin Li	// NOTE that BuildIDsDocument does NOT do any validation of the license
129*ba677afaSXin Li	// identifiers, to confirm that they are e.g. on the SPDX License List
130*ba677afaSXin Li	// or in other appropriate format (e.g., LicenseRef-...)
131*ba677afaSXin Li
132*ba677afaSXin Li	// we can now save it to disk, using tvsaver.
133*ba677afaSXin Li
134*ba677afaSXin Li	// create a new file for writing
135*ba677afaSXin Li	w, err := os.Create(fileOut)
136*ba677afaSXin Li	if err != nil {
137*ba677afaSXin Li		fmt.Printf("Error while opening %v for writing: %v\n", fileOut, err)
138*ba677afaSXin Li		return
139*ba677afaSXin Li	}
140*ba677afaSXin Li	defer w.Close()
141*ba677afaSXin Li
142*ba677afaSXin Li	err = tvsaver.Save2_2(doc, w)
143*ba677afaSXin Li	if err != nil {
144*ba677afaSXin Li		fmt.Printf("Error while saving %v: %v", fileOut, err)
145*ba677afaSXin Li		return
146*ba677afaSXin Li	}
147*ba677afaSXin Li
148*ba677afaSXin Li	fmt.Printf("Successfully saved %v\n", fileOut)
149*ba677afaSXin Li}
150