1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
# frozen_string_literal: true
module LicenseFinder
class GoModules
FORMAT = "'{{.Main}},{{.Path}},{{.Version}},{{.Dir}}'"
HEADER = [:main_module, :name, :version, :dir].freeze
def prepare
return if vendored?
within_project_path do
tool_box.install(tool: :golang)
shell.execute([:go, :mod, :download, '-json'], capture: false)
end
end
def current_packages
within_project_path do
modules = vendored? ? parse_go_sum : go_list_all
modules.map { |hash| map_from(hash) }.compact
end
end
private
def go_list_all
env = { 'GOFLAGS' => ENV.fetch('GOFLAGS', '-mod=readonly') }
command = [:go, :list, '-m', '-f', FORMAT, :all]
stdout, _stderr, status = shell.execute(command, env: env)
return [] unless status.success?
stdout.each_line.map { |line| Hash[HEADER.zip(line.chomp.split(','))] }
end
def parse_go_sum
go_sum_path
.each_line.map { |x| x.split(' ') }
.each_with_object({}) do |(name, version), memo|
next unless module_path?(name)
memo["#{name}:#{version}"] = {
name: name,
version: version.split('/')[0],
dir: vendored_path_to(name)
}
end.values
end
def map_from(hash)
return if hash[:main_module] == "true"
Dependency.new(
'Go',
hash[:name],
hash[:version],
install_path: install_dir_for(hash),
detection_path: go_sum_path
)
end
def go_sum_path
@go_sum_path ||= Pathname.glob(project_path.join('go.sum')).find(&:exist?)
end
def vendor_path
@vendor_path ||= go_sum_path.parent.join('vendor')
end
def vendored?
vendor_path.exist? && vendor_path.directory?
end
def vendored_path_to(module_name)
vendor_path.join(module_name)
end
def install_dir_for(hash)
dir = hash[:dir]
pathname = dir && !dir.empty? ? Pathname.new(dir) : vendored_path_to(hash[:name])
pathname.exist? ? pathname : nil
end
# https://golang.org/ref/mod#tmp_9
def module_path?(module_path)
!module_path.start_with?('/') &&
!module_path.end_with?('/') &&
module_path.split('/').all? { |x| element?(x) }
end
def element?(element)
!element.empty? &&
!element.start_with?('.') &&
!element.end_with?('.') &&
element.match?(/\A[A-Za-z0-9+-._~]+\Z/)
end
end
end
|