From dffae4ab95e34115b6a54bf681fc0966a8611f01 Mon Sep 17 00:00:00 2001 From: Mark Severson Date: Wed, 8 Jul 2020 00:10:17 -0600 Subject: [PATCH] Change Go modules package selectors for `go list` Without module mode being enabled (`-m`), the "all" selector isn't targeting the correct packages. The documentation for "all" states: > "all" expands to all packages found in all the GOPATH trees This could feasibly select all packages on the local system. Instead, the "./..." selector is being used. This has the added benefit of being the same selector used by some of the other Go package managers. As the "./..." selector will only select packages in and beneath the current directory, the "-deps" flag has been added to also select dependencies of those packages, while the .DepOnly field ensures that local packages are not unnecessarily listed. Finally, the -mod=readonly flag has been added to explicitly ignore the vendor directory. The issue appears to be that each package of a module gets listed as the module's install path. This causes the LICENSE files to not be found (because they are at a higher path than the imported package). --- .../package_managers/go_modules.rb | 11 +++++--- .../package_managers/go_modules_spec.rb | 27 ++----------------- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/lib/license_finder/package_managers/go_modules.rb b/lib/license_finder/package_managers/go_modules.rb index 3d2b94685..2a504e15e 100644 --- a/lib/license_finder/package_managers/go_modules.rb +++ b/lib/license_finder/package_managers/go_modules.rb @@ -31,6 +31,8 @@ def current_packages def packages_info Dir.chdir(project_path) do # Explanations: + # * Only list dependencies (packages not listed in the project directory) + # (.DepOnly) # * Ignore standard library packages # (not .Standard) # * Replacement modules are respected @@ -38,7 +40,7 @@ def packages_info # * Module cache directory or (vendored) package directory # (or $mod.Dir .Dir) format_str = \ - '{{ if not .Standard }}'\ + '{{ if and (.DepOnly) (not .Standard) }}'\ '{{ $mod := (or .Module.Replace .Module) }}'\ '{{ $mod.Path }},{{ $mod.Version }},{{ or $mod.Dir .Dir }}'\ '{{ end }}' @@ -49,8 +51,11 @@ def packages_info # # Instead, the owning module is listed for each imported package. This better # matches the implementation of other Go package managers. - info_output, stderr, _status = Cmd.run("GO111MODULE=on go list -f '#{format_str}' all") - info_output, _stderr, _status = Cmd.run("GO111MODULE=on go list -mod=mod -f '#{format_str}' all") if stderr =~ Regexp.compile("can't compute 'all' using the vendor directory") + # + # TODO: Figure out a way to make the vendor directory work (i.e. remove the + # -mod=readonly flag). Each of the imported packages gets listed separatly, + # confusing the issue as to which package is the root of the module. + info_output, _stderr, _status = Cmd.run("GO111MODULE=on go list -mod=readonly -deps -f '#{format_str}' ./...") # Since many packages may belong to a single module, #uniq is used to deduplicate info_output.split("\n").uniq diff --git a/spec/lib/license_finder/package_managers/go_modules_spec.rb b/spec/lib/license_finder/package_managers/go_modules_spec.rb index a7fa0d65d..9648e8b7b 100644 --- a/spec/lib/license_finder/package_managers/go_modules_spec.rb +++ b/spec/lib/license_finder/package_managers/go_modules_spec.rb @@ -10,7 +10,7 @@ module LicenseFinder let(:src_path) { '/workspace/code' } let(:mod_path) { "#{src_path}/go.mod" } let(:vendor_path) { "#{src_path}/vendor" } - let(:go_list_format) { '{{ if not .Standard }}{{ $mod := (or .Module.Replace .Module) }}{{ $mod.Path }},{{ $mod.Version }},{{ or $mod.Dir .Dir }}{{ end }}' } + let(:go_list_format) { '{{ if and (.DepOnly) (not .Standard) }}{{ $mod := (or .Module.Replace .Module) }}{{ $mod.Path }},{{ $mod.Version }},{{ or $mod.Dir .Dir }}{{ end }}' } let(:go_list_string) do "foo,,/workspace/code/\ngopkg.in/check.v1,v0.0.0-20161208181325-20d25e280405,"\ "/workspace/LicenseFinder/features/fixtures/go_modules/vendor/gopkg.in/check.v1\n"\ @@ -26,7 +26,7 @@ module LicenseFinder FileUtils.mkdir_p(vendor_path) File.write(mod_path, content) - allow(SharedHelpers::Cmd).to receive(:run).with("GO111MODULE=on go list -f '#{go_list_format}' all").and_return(go_list_string) + allow(SharedHelpers::Cmd).to receive(:run).with("GO111MODULE=on go list -mod=readonly -deps -f '#{go_list_format}' ./...").and_return(go_list_string) end after do @@ -56,29 +56,6 @@ module LicenseFinder expect(packages.first.package_manager).to eq 'Go' end - - context 'when compute is not allowed on vendor' do - before do - allow(SharedHelpers::Cmd).to receive(:run) - .with("GO111MODULE=on go list -f '#{go_list_format}' all") - .and_return(['', "go list -m: can't compute 'all' using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)\n", 1]) - allow(SharedHelpers::Cmd).to receive(:run) - .with("GO111MODULE=on go list -mod=mod -f '#{go_list_format}' all") - .and_return(go_list_string) - end - - it 'finds all the packages all go.mod files' do - packages = subject.current_packages - - expect(packages.length).to eq 2 - - expect(packages.first.name).to eq 'gopkg.in/check.v1' - expect(packages.first.version).to eq 'v0.0.0-20161208181325-20d25e280405' - - expect(packages.last.name).to eq 'gopkg.in/yaml.v2' - expect(packages.last.version).to eq 'v2.2.1' - end - end end describe '.takes_priority_over' do