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