gitlab-license_finder 6.14.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. checksums.yaml +7 -0
  2. data/.force-build +0 -0
  3. data/.gitignore +13 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +70 -0
  6. data/CHANGELOG.md +981 -0
  7. data/CONTRIBUTING.md +121 -0
  8. data/Dockerfile +249 -0
  9. data/Gemfile +2 -0
  10. data/LICENSE +22 -0
  11. data/README.md +555 -0
  12. data/Rakefile +77 -0
  13. data/TODO.md +12 -0
  14. data/VERSION +1 -0
  15. data/appveyor.yml +21 -0
  16. data/bin/license_finder +6 -0
  17. data/bin/license_finder_pip.py +43 -0
  18. data/ci/pipelines/pull-request.yml.erb +141 -0
  19. data/ci/pipelines/release.yml.erb +200 -0
  20. data/ci/scripts/containerize-tests.sh +14 -0
  21. data/ci/scripts/pushscript.sh +32 -0
  22. data/ci/scripts/run-rubocop.sh +15 -0
  23. data/ci/scripts/run-tests.sh +24 -0
  24. data/ci/scripts/test.ps1 +81 -0
  25. data/ci/scripts/updateChangelog.sh +84 -0
  26. data/ci/tasks/build-and-push-gem.yml +10 -0
  27. data/ci/tasks/build-windows.yml +6 -0
  28. data/ci/tasks/build.yml +16 -0
  29. data/ci/tasks/rubocop.yml +15 -0
  30. data/ci/tasks/run-tests.yml +10 -0
  31. data/ci/tasks/update-changelog.yml +18 -0
  32. data/dlf +12 -0
  33. data/examples/Gemfile +4 -0
  34. data/examples/custom_erb_template.rb +24 -0
  35. data/examples/extract_license_data.rb +63 -0
  36. data/examples/sample_template.erb +7 -0
  37. data/lib/license_finder/cli/approvals.rb +28 -0
  38. data/lib/license_finder/cli/base.rb +107 -0
  39. data/lib/license_finder/cli/dependencies.rb +44 -0
  40. data/lib/license_finder/cli/ignored_dependencies.rb +32 -0
  41. data/lib/license_finder/cli/ignored_groups.rb +32 -0
  42. data/lib/license_finder/cli/inherited_decisions.rb +50 -0
  43. data/lib/license_finder/cli/licenses.rb +26 -0
  44. data/lib/license_finder/cli/main.rb +221 -0
  45. data/lib/license_finder/cli/makes_decisions.rb +38 -0
  46. data/lib/license_finder/cli/patched_thor.rb +33 -0
  47. data/lib/license_finder/cli/permitted_licenses.rb +32 -0
  48. data/lib/license_finder/cli/project_name.rb +32 -0
  49. data/lib/license_finder/cli/restricted_licenses.rb +32 -0
  50. data/lib/license_finder/cli.rb +20 -0
  51. data/lib/license_finder/configuration.rb +186 -0
  52. data/lib/license_finder/core.rb +118 -0
  53. data/lib/license_finder/decision_applier.rb +70 -0
  54. data/lib/license_finder/decisions.rb +312 -0
  55. data/lib/license_finder/decisions_factory.rb +13 -0
  56. data/lib/license_finder/diff.rb +51 -0
  57. data/lib/license_finder/license/any_matcher.rb +15 -0
  58. data/lib/license_finder/license/definitions.rb +366 -0
  59. data/lib/license_finder/license/header_matcher.rb +17 -0
  60. data/lib/license_finder/license/matcher.rb +24 -0
  61. data/lib/license_finder/license/none_matcher.rb +11 -0
  62. data/lib/license_finder/license/template.rb +19 -0
  63. data/lib/license_finder/license/templates/0BSD.txt +10 -0
  64. data/lib/license_finder/license/templates/Apache1_1.txt +16 -0
  65. data/lib/license_finder/license/templates/Apache2.txt +172 -0
  66. data/lib/license_finder/license/templates/BSD.txt +24 -0
  67. data/lib/license_finder/license/templates/CC01.txt +30 -0
  68. data/lib/license_finder/license/templates/CDDL1.txt +131 -0
  69. data/lib/license_finder/license/templates/EPL1.txt +86 -0
  70. data/lib/license_finder/license/templates/GPLv2.txt +339 -0
  71. data/lib/license_finder/license/templates/GPLv3.txt +674 -0
  72. data/lib/license_finder/license/templates/ISC.txt +2 -0
  73. data/lib/license_finder/license/templates/LGPL.txt +165 -0
  74. data/lib/license_finder/license/templates/LGPL2_1.txt +169 -0
  75. data/lib/license_finder/license/templates/MIT.txt +9 -0
  76. data/lib/license_finder/license/templates/MPL1_1.txt +469 -0
  77. data/lib/license_finder/license/templates/MPL2.txt +373 -0
  78. data/lib/license_finder/license/templates/NewBSD.txt +21 -0
  79. data/lib/license_finder/license/templates/OFL.txt +91 -0
  80. data/lib/license_finder/license/templates/Python.txt +47 -0
  81. data/lib/license_finder/license/templates/Ruby.txt +52 -0
  82. data/lib/license_finder/license/templates/SimplifiedBSD.txt +19 -0
  83. data/lib/license_finder/license/templates/WTFPL.txt +14 -0
  84. data/lib/license_finder/license/templates/Zlib.txt +17 -0
  85. data/lib/license_finder/license/text.rb +45 -0
  86. data/lib/license_finder/license.rb +117 -0
  87. data/lib/license_finder/license_aggregator.rb +59 -0
  88. data/lib/license_finder/logger.rb +69 -0
  89. data/lib/license_finder/package.rb +202 -0
  90. data/lib/license_finder/package_delta.rb +61 -0
  91. data/lib/license_finder/package_manager.rb +181 -0
  92. data/lib/license_finder/package_managers/bower.rb +37 -0
  93. data/lib/license_finder/package_managers/bundler.rb +110 -0
  94. data/lib/license_finder/package_managers/cargo.rb +38 -0
  95. data/lib/license_finder/package_managers/carthage.rb +68 -0
  96. data/lib/license_finder/package_managers/cocoa_pods.rb +61 -0
  97. data/lib/license_finder/package_managers/composer.rb +63 -0
  98. data/lib/license_finder/package_managers/conan.rb +28 -0
  99. data/lib/license_finder/package_managers/conda.rb +131 -0
  100. data/lib/license_finder/package_managers/dep.rb +43 -0
  101. data/lib/license_finder/package_managers/dotnet.rb +83 -0
  102. data/lib/license_finder/package_managers/erlangmk.rb +50 -0
  103. data/lib/license_finder/package_managers/glide.rb +36 -0
  104. data/lib/license_finder/package_managers/go_15vendorexperiment.rb +87 -0
  105. data/lib/license_finder/package_managers/go_dep.rb +80 -0
  106. data/lib/license_finder/package_managers/go_modules.rb +93 -0
  107. data/lib/license_finder/package_managers/go_workspace.rb +116 -0
  108. data/lib/license_finder/package_managers/govendor.rb +73 -0
  109. data/lib/license_finder/package_managers/gradle.rb +99 -0
  110. data/lib/license_finder/package_managers/gvt.rb +69 -0
  111. data/lib/license_finder/package_managers/maven.rb +65 -0
  112. data/lib/license_finder/package_managers/mix.rb +131 -0
  113. data/lib/license_finder/package_managers/npm.rb +57 -0
  114. data/lib/license_finder/package_managers/nuget.rb +154 -0
  115. data/lib/license_finder/package_managers/pip.rb +70 -0
  116. data/lib/license_finder/package_managers/pipenv.rb +63 -0
  117. data/lib/license_finder/package_managers/rebar.rb +65 -0
  118. data/lib/license_finder/package_managers/sbt.rb +50 -0
  119. data/lib/license_finder/package_managers/spm.rb +93 -0
  120. data/lib/license_finder/package_managers/trash.rb +43 -0
  121. data/lib/license_finder/package_managers/yarn.rb +107 -0
  122. data/lib/license_finder/package_utils/activation.rb +40 -0
  123. data/lib/license_finder/package_utils/conan_info_parser.rb +77 -0
  124. data/lib/license_finder/package_utils/gradle_dependency_finder.rb +15 -0
  125. data/lib/license_finder/package_utils/license_files.rb +41 -0
  126. data/lib/license_finder/package_utils/licensing.rb +39 -0
  127. data/lib/license_finder/package_utils/maven_dependency_finder.rb +15 -0
  128. data/lib/license_finder/package_utils/notice_files.rb +40 -0
  129. data/lib/license_finder/package_utils/possible_license_file.rb +27 -0
  130. data/lib/license_finder/package_utils/pypi.rb +41 -0
  131. data/lib/license_finder/package_utils/sbt_dependency_finder.rb +15 -0
  132. data/lib/license_finder/packages/bower_package.rb +42 -0
  133. data/lib/license_finder/packages/bundler_package.rb +33 -0
  134. data/lib/license_finder/packages/cargo_package.rb +28 -0
  135. data/lib/license_finder/packages/carthage_package.rb +18 -0
  136. data/lib/license_finder/packages/cocoa_pods_package.rb +22 -0
  137. data/lib/license_finder/packages/composer_package.rb +13 -0
  138. data/lib/license_finder/packages/conan_package.rb +23 -0
  139. data/lib/license_finder/packages/conda_package.rb +74 -0
  140. data/lib/license_finder/packages/erlangmk_package.rb +114 -0
  141. data/lib/license_finder/packages/go_package.rb +32 -0
  142. data/lib/license_finder/packages/gradle_package.rb +30 -0
  143. data/lib/license_finder/packages/manual_package.rb +27 -0
  144. data/lib/license_finder/packages/maven_package.rb +27 -0
  145. data/lib/license_finder/packages/merged_package.rb +44 -0
  146. data/lib/license_finder/packages/mix_package.rb +13 -0
  147. data/lib/license_finder/packages/npm_package.rb +171 -0
  148. data/lib/license_finder/packages/nuget_package.rb +13 -0
  149. data/lib/license_finder/packages/pip_package.rb +50 -0
  150. data/lib/license_finder/packages/rebar_package.rb +13 -0
  151. data/lib/license_finder/packages/sbt_package.rb +22 -0
  152. data/lib/license_finder/packages/spm_package.rb +18 -0
  153. data/lib/license_finder/packages/yarn_package.rb +13 -0
  154. data/lib/license_finder/platform.rb +15 -0
  155. data/lib/license_finder/project_finder.rb +62 -0
  156. data/lib/license_finder/report.rb +33 -0
  157. data/lib/license_finder/reports/csv_report.rb +99 -0
  158. data/lib/license_finder/reports/diff_report.rb +29 -0
  159. data/lib/license_finder/reports/erb_report.rb +58 -0
  160. data/lib/license_finder/reports/html_report.rb +13 -0
  161. data/lib/license_finder/reports/json_report.rb +30 -0
  162. data/lib/license_finder/reports/junit_report.rb +19 -0
  163. data/lib/license_finder/reports/markdown_report.rb +9 -0
  164. data/lib/license_finder/reports/merged_report.rb +16 -0
  165. data/lib/license_finder/reports/templates/bootstrap.css +9 -0
  166. data/lib/license_finder/reports/templates/html_report.erb +113 -0
  167. data/lib/license_finder/reports/templates/junit_report.erb +41 -0
  168. data/lib/license_finder/reports/templates/markdown_report.erb +49 -0
  169. data/lib/license_finder/reports/templates/xml_report.erb +19 -0
  170. data/lib/license_finder/reports/text_report.rb +12 -0
  171. data/lib/license_finder/reports/xml_report.rb +19 -0
  172. data/lib/license_finder/scanner.rb +83 -0
  173. data/lib/license_finder/shared_helpers/cmd.rb +13 -0
  174. data/lib/license_finder/shared_helpers/common_path.rb +29 -0
  175. data/lib/license_finder/version.rb +6 -0
  176. data/lib/license_finder.rb +14 -0
  177. data/license_finder.gemspec +72 -0
  178. data/release/instructions.md +8 -0
  179. data/swift-all-keys.asc +240 -0
  180. metadata +544 -0
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rexml/document'
4
+ require 'zip'
5
+
6
+ module LicenseFinder
7
+ class Nuget < PackageManager
8
+ class Assembly
9
+ attr_reader :name, :path
10
+
11
+ def initialize(path, name)
12
+ @path = path
13
+ @name = name
14
+ end
15
+
16
+ def dependencies
17
+ xml = REXML::Document.new(File.read(path.join('packages.config')))
18
+ packages = REXML::XPath.match(xml, '//package')
19
+ packages.map do |p|
20
+ attrs = p.attributes
21
+ Dependency.new(attrs['id'], attrs['version'], name)
22
+ end
23
+ end
24
+ end
25
+
26
+ Dependency = Struct.new(:name, :version, :assembly)
27
+
28
+ def possible_package_paths
29
+ path = project_path.join('vendor/*.nupkg')
30
+ nuget_dir = Dir[path].map { |pkg| File.dirname(pkg) }.uniq
31
+
32
+ # Presence of a .sln is a good indicator for a dotnet solution
33
+ # cf.: https://docs.microsoft.com/en-us/nuget/tools/cli-ref-restore#remarks
34
+ path = project_path.join('*.sln')
35
+ solution_file = Dir[path].first
36
+
37
+ possible_paths = [project_path.join('packages.config'), project_path.join('.nuget')]
38
+ possible_paths.unshift(Pathname(solution_file)) unless solution_file.nil?
39
+ possible_paths.unshift(Pathname(nuget_dir.first)) unless nuget_dir.empty?
40
+ possible_paths
41
+ end
42
+
43
+ def assemblies
44
+ Dir.glob(project_path.join('**', 'packages.config'), File::FNM_DOTMATCH).map do |d|
45
+ path = Pathname.new(d).dirname
46
+ name = path.basename.to_s
47
+ Assembly.new path, name
48
+ end
49
+ end
50
+
51
+ def current_packages
52
+ dependencies.each_with_object({}) do |dep, memo|
53
+ licenses = license_urls(dep)
54
+ path = Dir.glob("#{Dir.home}/.nuget/packages/#{dep.name.downcase}/#{dep.version}").first
55
+
56
+ memo[dep.name] ||= NugetPackage.new(dep.name, dep.version, spec_licenses: licenses, install_path: path)
57
+ memo[dep.name].groups << dep.assembly unless memo[dep.name].groups.include? dep.assembly
58
+ end.values
59
+ end
60
+
61
+ def license_urls(dep)
62
+ files = Dir["**/#{dep.name}.#{dep.version}.nupkg"]
63
+ return nil if files.empty?
64
+
65
+ file = files.first
66
+ Zip::File.open file do |zipfile|
67
+ content = zipfile.read(dep.name + '.nuspec')
68
+ Nuget.nuspec_license_urls(content)
69
+ end
70
+ end
71
+
72
+ def dependencies
73
+ assemblies.flat_map(&:dependencies)
74
+ end
75
+
76
+ def nuget_binary
77
+ legacy_vcproj = Dir['**/*.vcproj'].any?
78
+
79
+ if legacy_vcproj
80
+ '/usr/local/bin/nugetv3.5.0.exe'
81
+ else
82
+ '/usr/local/bin/nuget.exe'
83
+ end
84
+ end
85
+
86
+ def package_management_command
87
+ return 'nuget' if LicenseFinder::Platform.windows?
88
+
89
+ "mono #{nuget_binary}"
90
+ end
91
+
92
+ def prepare
93
+ Dir.chdir(project_path) do
94
+ cmd = prepare_command
95
+ stdout, stderr, status = Cmd.run(cmd)
96
+ return if status.success?
97
+
98
+ log_errors stderr
99
+
100
+ if stderr.include?('-PackagesDirectory')
101
+ logger.info cmd, 'trying fallback prepare command', color: :magenta
102
+
103
+ cmd = "#{cmd} -PackagesDirectory /#{Dir.home}/.nuget/packages"
104
+ stdout, stderr, status = Cmd.run(cmd)
105
+ return if status.success?
106
+
107
+ log_errors_with_cmd(cmd, stderr)
108
+ end
109
+
110
+ error_message = "Prepare command '#{cmd}' failed\n#{stderr}"
111
+ error_message += "\n#{stdout}\n" if !stdout.nil? && !stdout.empty?
112
+ raise error_message unless @prepare_no_fail
113
+ end
114
+ end
115
+
116
+ def prepare_command
117
+ cmd = package_management_command
118
+ sln_files = Dir['*.sln']
119
+ cmds = []
120
+ if sln_files.count > 1
121
+ sln_files.each do |sln|
122
+ cmds << "#{cmd} restore #{sln}"
123
+ end
124
+ else
125
+ cmds << "#{cmd} restore"
126
+ end
127
+
128
+ cmds.join(' && ')
129
+ end
130
+
131
+ def installed?(logger = Core.default_logger)
132
+ _stdout, _stderr, status = Cmd.run(nuget_check)
133
+ if status.success?
134
+ logger.debug self.class, 'is installed', color: :green
135
+ else
136
+ logger.info self.class, 'is not installed', color: :red
137
+ end
138
+ status.success?
139
+ end
140
+
141
+ def nuget_check
142
+ return 'where nuget' if LicenseFinder::Platform.windows?
143
+
144
+ "which mono && ls #{nuget_binary}"
145
+ end
146
+
147
+ def self.nuspec_license_urls(specfile_content)
148
+ xml = REXML::Document.new(specfile_content)
149
+ REXML::XPath.match(xml, '//metadata//licenseUrl')
150
+ .map(&:get_text)
151
+ .map(&:to_s)
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module LicenseFinder
6
+ class Pip < PackageManager
7
+ DEFAULT_VERSION = '2'
8
+
9
+ def initialize(options = {})
10
+ super
11
+ @requirements_path = options[:pip_requirements_path] || Pathname('requirements.txt')
12
+ @python_version = options[:python_version] || DEFAULT_VERSION
13
+ raise "Invalid python version \'#{@python_version}\'. Valid versions are '2' or '3'." unless %w[2 3].include?(@python_version)
14
+ end
15
+
16
+ def current_packages
17
+ pip_output.map do |name, version, children, location|
18
+ PipPackage.new(
19
+ name,
20
+ version,
21
+ PyPI.definition(name, version),
22
+ logger: logger,
23
+ children: children,
24
+ install_path: Pathname(location).join(name)
25
+ )
26
+ end
27
+ end
28
+
29
+ def package_management_command
30
+ "pip#{@python_version}"
31
+ end
32
+
33
+ def prepare_command
34
+ "pip#{@python_version} install"
35
+ end
36
+
37
+ def prepare
38
+ prep_cmd = "#{prepare_command} -r #{@requirements_path}"
39
+ _stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(prep_cmd) }
40
+ return if status.success?
41
+
42
+ log_errors stderr
43
+ raise "Prepare command '#{prep_cmd}' failed" unless @prepare_no_fail
44
+ end
45
+
46
+ def possible_package_paths
47
+ if project_path.nil?
48
+ [@requirements_path]
49
+ else
50
+ [project_path.join(@requirements_path)]
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def pip_output
57
+ command = "python#{@python_version == '2' ? '' : '3'} #{LicenseFinder::BIN_PATH.join('license_finder_pip.py')} #{detected_package_path}"
58
+ stdout, stderr, status = Cmd.run(command)
59
+
60
+ if status.success?
61
+ JSON(stdout).map do |package|
62
+ package.values_at('name', 'version', 'dependencies', 'location')
63
+ end
64
+ else
65
+ log_errors "LicenseFinder command '#{command}' failed:\n\t#{stderr}"
66
+ []
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'license_finder/package_utils/pypi'
5
+
6
+ module LicenseFinder
7
+ class Pipenv < PackageManager
8
+ def initialize(options = {})
9
+ super
10
+ @lockfile = Pathname('Pipfile.lock')
11
+ end
12
+
13
+ def current_packages
14
+ @current_packages ||=
15
+ begin
16
+ packages = {}
17
+ each_dependency(groups: allowed_groups) do |name, data, group|
18
+ version = canonicalize(data['version'] || 'unknown')
19
+ package = packages.fetch(key_for(name, version)) do |key|
20
+ packages[key] = build_package_for(name, version)
21
+ end
22
+ package.groups << group
23
+ end
24
+ packages.values
25
+ end
26
+ end
27
+
28
+ def possible_package_paths
29
+ project_path ? [project_path.join(@lockfile)] : [@lockfile]
30
+ end
31
+
32
+ private
33
+
34
+ def each_dependency(groups: [])
35
+ dependencies = JSON.parse(IO.read(detected_package_path))
36
+ groups.each do |group|
37
+ dependencies[group].each do |name, data|
38
+ yield name, data, group
39
+ end
40
+ end
41
+ end
42
+
43
+ def canonicalize(version)
44
+ version.sub(/^==/, '')
45
+ end
46
+
47
+ def build_package_for(name, version)
48
+ PipPackage.new(name, version, PyPI.definition(name, version))
49
+ end
50
+
51
+ def key_for(name, version)
52
+ "#{name}-#{version}"
53
+ end
54
+
55
+ def allowed_groups
56
+ %w[default develop] - ignored_groups.to_a
57
+ end
58
+
59
+ def ignored_groups
60
+ @ignored_groups || []
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class Rebar < PackageManager
5
+ def initialize(options = {})
6
+ super
7
+ @command = options[:rebar_command] || package_management_command
8
+ @deps_path = Pathname(options[:rebar_deps_dir] || File.join(project_path, '_build/default/lib'))
9
+ end
10
+
11
+ def current_packages
12
+ rebar_deps.map do |name, version|
13
+ licenses, homepage = dep_info(name)
14
+ RebarPackage.new(
15
+ name,
16
+ version,
17
+ install_path: @deps_path.join(name),
18
+ homepage: homepage,
19
+ spec_licenses: licenses.nil? ? [] : [licenses],
20
+ logger: logger
21
+ )
22
+ end
23
+ end
24
+
25
+ def package_management_command
26
+ 'rebar3'
27
+ end
28
+
29
+ def possible_package_paths
30
+ [project_path.join('rebar.config')]
31
+ end
32
+
33
+ private
34
+
35
+ def rebar_deps
36
+ command = "#{@command} tree"
37
+ stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(command) }
38
+ raise "Command '#{command}' failed to execute: #{stderr}" unless status.success?
39
+
40
+ stdout
41
+ .each_line
42
+ .reject { |line| line.start_with?('=') || line.include?('project app') }
43
+ .map do |line|
44
+ matches = line.match(/(?<name>\w+)─(?<version>[\S.]+)\s*/)
45
+ [matches[:name], matches[:version]] if matches
46
+ end.compact
47
+ end
48
+
49
+ def dep_info(name)
50
+ command = "#{@command} pkgs #{name}"
51
+ stdout, _, status = Cmd.run(command)
52
+ return [nil, nil] unless status.success?
53
+
54
+ licenses = nil
55
+ homepage = nil
56
+
57
+ stdout.scan(/Licenses: (?<licenses>.+)|(?<homepage>(https|http).*)/) do |pkg_licenses, pkg_homepage|
58
+ licenses ||= pkg_licenses
59
+ homepage ||= pkg_homepage
60
+ end
61
+
62
+ [licenses, homepage]
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+ require 'license_finder/package_utils/sbt_dependency_finder'
5
+
6
+ module LicenseFinder
7
+ class Sbt < PackageManager
8
+ def initialize(options = {})
9
+ super
10
+ @include_groups = options[:sbt_include_groups]
11
+ end
12
+
13
+ def current_packages
14
+ command = "#{package_management_command} dumpLicenseReport"
15
+ _stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(command) }
16
+ raise "Command '#{command}' failed to execute: #{stderr}" unless status.success?
17
+
18
+ dependencies = SbtDependencyFinder.new(project_path).dependencies
19
+ packages = dependencies.flat_map do |text|
20
+ options = {
21
+ headers: true
22
+ }
23
+
24
+ contents = CSV.parse(text, options)
25
+ contents.map do |row|
26
+ group_id, name, version = row['Dependency'].split('#').map(&:strip)
27
+ spec = {
28
+ 'artifactId' => name,
29
+ 'groupId' => group_id,
30
+ 'version' => version,
31
+ 'licenses' => [{ 'name' => row['License'] }]
32
+ }
33
+
34
+ path = File.join("#{Dir.home}/.ivy2/cache", "#{spec['groupId']}/#{spec['artifactId']}")
35
+ SbtPackage.new(spec, logger: logger, include_groups: @include_groups, install_path: path)
36
+ end
37
+ end
38
+
39
+ packages.uniq
40
+ end
41
+
42
+ def package_management_command
43
+ 'sbt'
44
+ end
45
+
46
+ def possible_package_paths
47
+ [project_path.join('build.sbt')]
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module LicenseFinder
6
+ class Spm < PackageManager
7
+ class SpmError < RuntimeError; end
8
+
9
+ def current_packages
10
+ unless File.exist?(workspace_state_path)
11
+ raise SpmError, 'No checked-out SPM packages found.
12
+ Please install your dependencies first.'
13
+ end
14
+
15
+ workspace_state = JSON.parse(IO.read(workspace_state_path))
16
+ workspace_state['object']['dependencies'].map do |dependency|
17
+ package_ref = dependency['packageRef']
18
+ checkout_state = dependency['state']['checkoutState']
19
+
20
+ subpath = dependency['subpath']
21
+ package_name = package_ref['name']
22
+ package_version = checkout_state['version'] || checkout_state['revision']
23
+ homepage = package_ref['path']
24
+
25
+ SpmPackage.new(
26
+ package_name,
27
+ package_version,
28
+ license_text(subpath),
29
+ logger: logger,
30
+ install_path: project_checkout(subpath),
31
+ homepage: homepage
32
+ )
33
+ end
34
+ end
35
+
36
+ def package_management_command
37
+ LicenseFinder::Platform.darwin? ? 'xcodebuild' : 'swift'
38
+ end
39
+
40
+ def prepare_command
41
+ LicenseFinder::Platform.darwin? ? 'xcodebuild -resolvePackageDependencies' : 'swift package resolve'
42
+ end
43
+
44
+ def possible_package_paths
45
+ [workspace_state_path]
46
+ end
47
+
48
+ private
49
+
50
+ def resolved_package
51
+ if File.exist?(resolved_path)
52
+ @resolved_file ||= IO.read(resolved_path)
53
+ else
54
+ raise SpmError, 'No Package.resolved found.
55
+ Please install your dependencies first and provide it via environment variable
56
+ SPM_PACKAGE_RESOLVED'
57
+ end
58
+ end
59
+
60
+ def resolved_path
61
+ # Xcode projects have SPM packages info under project's derived data location
62
+ derived_data_folder = ENV['SPM_DERIVED_DATA']
63
+ if derived_data_folder
64
+ pathname = Pathname.new(derived_data_folder)
65
+ pathname.absolute? ? pathname : project_path.join(derived_data_folder)
66
+ else
67
+ project_path.join('.build')
68
+ end
69
+ end
70
+
71
+ def workspace_state_path
72
+ resolved_path.join('workspace-state.json')
73
+ end
74
+
75
+ def license_text(subpath)
76
+ license_path = license_pattern(subpath).find { |f| File.exist?(f) }
77
+ license_path.nil? ? nil : IO.read(license_path)
78
+ end
79
+
80
+ def project_checkout(subpath)
81
+ resolved_path.join('checkouts', subpath)
82
+ end
83
+
84
+ def license_pattern(subpath)
85
+ checkout_path = project_checkout(subpath)
86
+ Dir.glob(checkout_path.join('LICENSE*'), File::FNM_CASEFOLD)
87
+ end
88
+
89
+ def name_version_from_line(cartfile_line)
90
+ cartfile_line.split(' ')[1, 2].map { |f| f.split('/').last.delete('"').gsub('.git', '') }
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class Trash < PackageManager
5
+ class << self
6
+ def package_management_command
7
+ 'trash'
8
+ end
9
+
10
+ def takes_priority_over
11
+ Go15VendorExperiment
12
+ end
13
+ end
14
+
15
+ def prepare_command
16
+ 'trash'
17
+ end
18
+
19
+ def possible_package_paths
20
+ [project_path.join('vendor.conf')]
21
+ end
22
+
23
+ def current_packages
24
+ dependencies_path = project_path.join('trash.lock')
25
+
26
+ YAML.load_file(dependencies_path).fetch('import').map do |package_hash|
27
+ import_path = package_hash.fetch('package')
28
+ license_path = project_path.join('vendor', import_path)
29
+
30
+ GoPackage.from_dependency({
31
+ 'ImportPath' => import_path,
32
+ 'InstallPath' => license_path,
33
+ 'Rev' => package_hash.fetch('version'),
34
+ 'Homepage' => repo_name(import_path)
35
+ }, nil, true)
36
+ end
37
+ end
38
+
39
+ def repo_name(name)
40
+ name.split('/')[0..2].join('/')
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class Yarn < PackageManager
5
+ SHELL_COMMAND = 'yarn licenses list --no-progress --json'
6
+
7
+ def possible_package_paths
8
+ [project_path.join('yarn.lock')]
9
+ end
10
+
11
+ def current_packages
12
+ cmd = "#{Yarn::SHELL_COMMAND}#{production_flag}"
13
+ suffix = " --cwd #{project_path}" unless project_path.nil?
14
+ cmd += suffix unless suffix.nil?
15
+
16
+ stdout, _stderr, status = Cmd.run(cmd)
17
+ return [] unless status.success?
18
+
19
+ packages = []
20
+ incompatible_packages = []
21
+
22
+ json_strings = stdout.encode('ASCII', invalid: :replace, undef: :replace, replace: '?').split("\n")
23
+ json_objects = json_strings.map { |json_object| JSON.parse(json_object) }
24
+
25
+ if json_objects.last['type'] == 'table'
26
+ license_json = json_objects.pop['data']
27
+ packages = packages_from_json(license_json)
28
+ end
29
+
30
+ json_objects.each do |json_object|
31
+ match = /(?<name>[\w,\-]+)@(?<version>(\d+\.?)+)/ =~ json_object['data'].to_s
32
+ if match
33
+ package = YarnPackage.new(name, version, spec_licenses: ['unknown'])
34
+ incompatible_packages.push(package)
35
+ end
36
+ end
37
+
38
+ packages + incompatible_packages.uniq
39
+ end
40
+
41
+ def prepare
42
+ prep_cmd = "#{prepare_command}#{production_flag}"
43
+ _stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(prep_cmd) }
44
+ return if status.success?
45
+
46
+ log_errors stderr
47
+ raise "Prepare command '#{prep_cmd}' failed" unless @prepare_no_fail
48
+ end
49
+
50
+ def self.takes_priority_over
51
+ NPM
52
+ end
53
+
54
+ def package_management_command
55
+ 'yarn'
56
+ end
57
+
58
+ def prepare_command
59
+ 'yarn install --ignore-engines --ignore-scripts'
60
+ end
61
+
62
+ private
63
+
64
+ def packages_from_json(json_data)
65
+ body = json_data['body']
66
+ head = json_data['head']
67
+
68
+ packages = body.map do |json_package|
69
+ Hash[head.zip(json_package)]
70
+ end
71
+
72
+ valid_packages = filter_yarn_internal_package(packages)
73
+
74
+ valid_packages.map do |package_hash|
75
+ YarnPackage.new(
76
+ package_hash['Name'],
77
+ package_hash['Version'],
78
+ spec_licenses: [package_hash['License']],
79
+ homepage: package_hash['VendorUrl'],
80
+ authors: package_hash['VendorName'],
81
+ install_path: project_path.join(modules_folder, package_hash['Name'])
82
+ )
83
+ end
84
+ end
85
+
86
+ def modules_folder
87
+ return @modules_folder if @modules_folder
88
+
89
+ stdout, _stderr, status = Cmd.run('yarn config get modules-folder')
90
+ @modules_folder = 'node_modules' if !status.success? || stdout.strip == 'undefined'
91
+ @modules_folder ||= stdout.strip
92
+ end
93
+
94
+ # remove fake package created by yarn [Yarn Bug]
95
+ def filter_yarn_internal_package(all_packages)
96
+ internal_package_pattern = /workspace-aggregator-[a-zA-z0-9]{8}-[a-zA-z0-9]{4}-[a-zA-z0-9]{4}-[a-zA-z0-9]{4}-[a-zA-z0-9]{12}/
97
+ yarn_internal_package = all_packages.find { |package| internal_package_pattern.match(package['Name']) }
98
+ all_packages - [yarn_internal_package]
99
+ end
100
+
101
+ def production_flag
102
+ return '' if @ignored_groups.nil?
103
+
104
+ @ignored_groups.include?('devDependencies') ? ' --production' : ''
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ module Activation
5
+ # An Activation reports that a license has been activated for a package, and
6
+ # tracks the source of that information
7
+ Basic = Struct.new(:package, :license)
8
+
9
+ class FromDecision < Basic
10
+ def sources
11
+ ['from decision']
12
+ end
13
+ end
14
+
15
+ class FromSpec < Basic
16
+ def sources
17
+ ['from spec']
18
+ end
19
+ end
20
+
21
+ class FromFiles < Basic
22
+ def initialize(package, license, files)
23
+ super(package, license)
24
+ @files = files
25
+ end
26
+
27
+ attr_reader :files
28
+
29
+ def sources
30
+ files.map { |file| "from file '#{file.path}'" }
31
+ end
32
+ end
33
+
34
+ class None < Basic
35
+ def sources
36
+ []
37
+ end
38
+ end
39
+ end
40
+ end