From 34361fdab2dc3f197f7aec6408175018dee3b453 Mon Sep 17 00:00:00 2001 From: Mark Severson Date: Thu, 2 Jul 2020 15:06:53 -0600 Subject: [PATCH] Change Go modules to list imported modules If module mode is enabled (`-m`), all possible module dependencies are listed, regardless of whether the packages requiring the module are actually imported. This results in un-imported modules being listed, which is incongruous with other Go package manager implementations. The removal of the `-m` flag causes `go list` to list imported packages. A format string is used so that the corresponding module is listed in place of each imported package. --- .../package_managers/go_modules.rb | 28 +++++++++++++++---- .../package_managers/go_modules_spec.rb | 8 ++++-- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/lib/license_finder/package_managers/go_modules.rb b/lib/license_finder/package_managers/go_modules.rb index 897b9acd7..3d2b94685 100644 --- a/lib/license_finder/package_managers/go_modules.rb +++ b/lib/license_finder/package_managers/go_modules.rb @@ -30,12 +30,30 @@ def current_packages def packages_info Dir.chdir(project_path) do - info_output, stderr, _status = Cmd.run("GO111MODULE=on go list -m -f '{{.Path}},{{.Version}},{{.Dir}}' all") - if stderr =~ Regexp.compile("can't compute 'all' using the vendor directory") - info_output, _stderr, _status = Cmd.run("GO111MODULE=on go list -m -mod=mod -f '{{.Path}},{{.Version}},{{.Dir}}' all") - end + # Explanations: + # * Ignore standard library packages + # (not .Standard) + # * Replacement modules are respected + # (or .Module.Replace .Module) + # * Module cache directory or (vendored) package directory + # (or $mod.Dir .Dir) + format_str = \ + '{{ if not .Standard }}'\ + '{{ $mod := (or .Module.Replace .Module) }}'\ + '{{ $mod.Path }},{{ $mod.Version }},{{ or $mod.Dir .Dir }}'\ + '{{ end }}' - info_output.split("\n") + # The module list flag (`-m`) is intentionally not used here. If the module + # dependency tree were followed, transitive dependencies that are never imported + # may be included. + # + # 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") + + # Since many packages may belong to a single module, #uniq is used to deduplicate + info_output.split("\n").uniq end end 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 e94e7e3f7..a7fa0d65d 100644 --- a/spec/lib/license_finder/package_managers/go_modules_spec.rb +++ b/spec/lib/license_finder/package_managers/go_modules_spec.rb @@ -10,9 +10,11 @@ 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_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"\ +"gopkg.in/yaml.v2,v2.2.1,/workspace/LicenseFinder/features/fixtures/go_modules/vendor/gopkg.in/yaml.v2\n"\ 'gopkg.in/yaml.v2,v2.2.1,/workspace/LicenseFinder/features/fixtures/go_modules/vendor/gopkg.in/yaml.v2' end subject { GoModules.new(project_path: Pathname(src_path), logger: double(:logger, active: nil)) } @@ -24,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 -m -f '{{.Path}},{{.Version}},{{.Dir}}' all").and_return(go_list_string) + allow(SharedHelpers::Cmd).to receive(:run).with("GO111MODULE=on go list -f '#{go_list_format}' all").and_return(go_list_string) end after do @@ -58,10 +60,10 @@ module LicenseFinder context 'when compute is not allowed on vendor' do before do allow(SharedHelpers::Cmd).to receive(:run) - .with("GO111MODULE=on go list -m -f '{{.Path}},{{.Version}},{{.Dir}}' all") + .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 -m -mod=mod -f '{{.Path}},{{.Version}},{{.Dir}}' all") + .with("GO111MODULE=on go list -mod=mod -f '#{go_list_format}' all") .and_return(go_list_string) end