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