diff --git a/README.md b/README.md index 33d8542..5abd24b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ since it uses metadata from the Go compiler to determine the _exact_ set of dependencies embedded in a compiled Go binary. This excludes dependencies that are not used in the final binary. For example, if a library depends on "foo" in function "F" but "F" is never called, then the dependency "foo" will not -be present in the final binary. +be present in the final binary. golicense is not meant to be a complete replacement for open source compliance companies such as [FOSSA](https://fossa.io/) or @@ -58,6 +58,8 @@ $ golicense [flags] [BINARY] $ golicense [flags] [CONFIG] [BINARY] ``` +You may also pass mutliple binaries (but only if you are providing a CONFIG). + ### Configuration File The configuration file can specify allow/deny lists of licenses for reports, diff --git a/go.mod b/go.mod index cf333cd..224b494 100644 --- a/go.mod +++ b/go.mod @@ -45,3 +45,5 @@ require ( gopkg.in/src-d/go-siva.v1 v1.3.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) + +go 1.13 diff --git a/main.go b/main.go index b8634cb..13a42a1 100644 --- a/main.go +++ b/main.go @@ -52,18 +52,13 @@ func realMain() int { "❗️ Path to file to analyze expected.\n\n")) printHelp(flags) return 1 - } else if len(args) > 2 { - fmt.Fprintf(os.Stderr, color.RedString( - "❗️ Exactly one or two arguments is allowed.\n\n")) - printHelp(flags) - return 1 } // Determine the exe path and parse the configuration if given. var cfg config.Config - exePath := args[0] + var exePaths []string if len(args) > 1 { - exePath = args[1] + exePaths = args[1:] c, err := config.ParseFile(args[0]) if err != nil { @@ -74,34 +69,47 @@ func realMain() int { // Store the config and set it on the output cfg = *c + } else { + exePaths = args[:1] } - // Read the dependencies from the binary itself - vsn, err := version.ReadExe(exePath) - if err != nil { - fmt.Fprintf(os.Stderr, color.RedString(fmt.Sprintf( - "❗️ Error reading %q: %s\n", args[0], err))) - return 1 - } + allMods := map[module.Module]struct{}{} + for _, exePath := range exePaths { + // Read the dependencies from the binary itself + vsn, err := version.ReadExe(exePath) + if err != nil { + fmt.Fprintf(os.Stderr, color.RedString(fmt.Sprintf( + "❗️ Error reading %q: %s\n", args[0], err))) + return 1 + } - if vsn.ModuleInfo == "" { - // ModuleInfo empty means that the binary didn't use Go modules - // or it could mean that a binary has no dependencies. Either way - // we error since we can't be sure. - fmt.Fprintf(os.Stderr, color.YellowString(fmt.Sprintf( - "⚠️ %q ⚠️\n\n"+ - "This executable was compiled without using Go modules or has \n"+ - "zero dependencies. golicense considers this an error (exit code 1).\n", exePath))) - return 1 + if vsn.ModuleInfo == "" { + // ModuleInfo empty means that the binary didn't use Go modules + // or it could mean that a binary has no dependencies. Either way + // we error since we can't be sure. + fmt.Fprintf(os.Stderr, color.YellowString(fmt.Sprintf( + "⚠️ %q ⚠️\n\n"+ + "This executable was compiled without using Go modules or has \n"+ + "zero dependencies. golicense considers this an error (exit code 1).\n", exePath))) + return 1 + } + + // From the raw module string from the binary, we need to parse this + // into structured data with the module information. + mods, err := module.ParseExeData(vsn.ModuleInfo) + if err != nil { + fmt.Fprintf(os.Stderr, color.RedString(fmt.Sprintf( + "❗️ Error parsing dependencies: %s\n", err))) + return 1 + } + for _, mod := range mods { + allMods[mod] = struct{}{} + } } - // From the raw module string from the binary, we need to parse this - // into structured data with the module information. - mods, err := module.ParseExeData(vsn.ModuleInfo) - if err != nil { - fmt.Fprintf(os.Stderr, color.RedString(fmt.Sprintf( - "❗️ Error parsing dependencies: %s\n", err))) - return 1 + mods := make([]module.Module, 0, len(allMods)) + for mod := range allMods { + mods = append(mods, mod) } // Complete terminal output setup