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,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module LicenseFinder
6
+ class GoWorkspacePackageManagerError < ::StandardError
7
+ end
8
+
9
+ class GoWorkspace < PackageManager
10
+ Submodule = Struct.new :install_path, :revision
11
+ ENVRC_REGEXP = /GOPATH|GO15VENDOREXPERIMENT/.freeze
12
+
13
+ def initialize(options = {})
14
+ super
15
+ @full_version = options[:go_full_version]
16
+ @strict_matching = options[:strict_matching]
17
+ end
18
+
19
+ def package_management_command
20
+ 'go'
21
+ end
22
+
23
+ def current_packages
24
+ go_list_packages = go_list
25
+ git_modules.map do |submodule|
26
+ # We are filtering the non-standard packages because the word "net"
27
+ # seems to be common that can give false positive when filtering the git submodules
28
+ import_path = go_list_packages.find do |gp|
29
+ submodule.install_path =~ /#{repo_name(gp)}$/
30
+ end
31
+ next unless import_path
32
+
33
+ dependency_info = {
34
+ 'ImportPath' => repo_name(import_path),
35
+ 'Homepage' => repo_name(import_path),
36
+ 'InstallPath' => submodule.install_path,
37
+ 'Rev' => submodule.revision
38
+ }
39
+ GoPackage.from_dependency(dependency_info, nil, @full_version)
40
+ end.compact
41
+ end
42
+
43
+ def self.takes_priority_over
44
+ Go15VendorExperiment
45
+ end
46
+
47
+ def possible_package_paths
48
+ [envrc_path.dirname]
49
+ end
50
+
51
+ def active?
52
+ return false if @strict_matching
53
+
54
+ godep = LicenseFinder::GoDep.new(project_path: Pathname(project_path))
55
+ dep = LicenseFinder::Dep.new(project_path: Pathname(project_path))
56
+ # go workspace is only active if GoDep wasn't. There are some projects
57
+ # that will use the .envrc and have a Godep folder as well.
58
+ !!(!godep.active? && !dep.active? && envrc_path && ENVRC_REGEXP.match(IO.read(envrc_path)))
59
+ end
60
+
61
+ private
62
+
63
+ def repo_name(import_path)
64
+ import_path.split('/')[0..2].join('/')
65
+ end
66
+
67
+ def project_src
68
+ project_path.join('src')
69
+ end
70
+
71
+ def envrc_path
72
+ p = Pathname.new project_path
73
+ 4.times.reduce([p]) { |memo, _| memo << memo.last.parent }.map { |path| path.join('.envrc') }.find(&:exist?)
74
+ end
75
+
76
+ def go_list
77
+ Dir.chdir(project_path) do
78
+ # avoid checking canonical import path. some projects uses
79
+ # non-canonical import path and rely on the fact that the deps are
80
+ # checked in. Canonical paths are only checked by `go get'. We
81
+ # discovered that `go list' will print a warning and unfortunately exit
82
+ # with status code 1. Setting GOPATH to nil removes those warnings.
83
+ orig_gopath = ENV['GOPATH']
84
+ ENV['GOPATH'] = nil
85
+ val, stderr, status = Cmd.run('go list -f "{{join .Deps \"\n\"}}" ./...')
86
+ ENV['GOPATH'] = project_path.to_s
87
+ val, stderr, status = Cmd.run('go list -f "{{join .Deps \"\n\"}}" ./...') unless status.success?
88
+ ENV['GOPATH'] = orig_gopath
89
+ raise GoWorkspacePackageManagerError, "go list failed:\n#{stderr}" unless status.success?
90
+
91
+ # Select non-standard packages. `go list std` returns the list of standard
92
+ # dependencies. We then filter those dependencies out of the full list of
93
+ # dependencies.
94
+ deps = val.split("\n")
95
+ Cmd.run('go list std').first.split("\n").each do |std|
96
+ deps.delete_if do |dep|
97
+ dep =~ %r{(\/|^)#{std}(\/|$)}
98
+ end
99
+ end
100
+ deps
101
+ end
102
+ end
103
+
104
+ def git_modules
105
+ Dir.chdir(detected_package_path) do |_d|
106
+ result, _stderr, status = Cmd.run('git submodule status')
107
+ raise 'git submodule status failed' unless status.success?
108
+
109
+ result.lines.map do |l|
110
+ columns = l.split.map(&:strip)
111
+ Submodule.new File.join(detected_package_path, columns[1]), columns[0]
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'license_finder/shared_helpers/common_path'
4
+ require 'json'
5
+
6
+ module LicenseFinder
7
+ class Govendor < PackageManager
8
+ def possible_package_paths
9
+ [project_path.join('vendor', 'vendor.json')]
10
+ end
11
+
12
+ def current_packages
13
+ file = File.read(detected_package_path)
14
+ packages = packages_from_json(file)
15
+ packages.map do |package|
16
+ GoPackage.from_dependency({
17
+ 'ImportPath' => package[:path],
18
+ 'InstallPath' => project_path.join('vendor', package[:path]),
19
+ 'Rev' => package[:sha]
20
+ }, nil, true)
21
+ end
22
+ end
23
+
24
+ def self.takes_priority_over
25
+ Go15VendorExperiment
26
+ end
27
+
28
+ def package_management_command
29
+ 'govendor'
30
+ end
31
+
32
+ def prepare_command
33
+ 'govendor sync'
34
+ end
35
+
36
+ private
37
+
38
+ def packages_from_json(json_string)
39
+ data = JSON.parse(json_string)
40
+ packages = data['package']
41
+
42
+ packages_by_sha = {}
43
+ packages_with_no_sha = []
44
+
45
+ packages.each do |package|
46
+ package_path = package['origin'] || package['path']
47
+ package_revision = package['revision']
48
+
49
+ if !package_is_versioned?(package)
50
+ packages_with_no_sha << { sha: '', path: package_path }
51
+ elsif packages_by_sha[package_revision].nil?
52
+ packages_by_sha[package_revision] = [package_path]
53
+ else
54
+ packages_by_sha[package_revision] << package_path
55
+ end
56
+ end
57
+
58
+ result = packages_with_no_sha
59
+ packages_by_sha.each do |sha, paths|
60
+ common_paths = CommonPathHelper.longest_common_paths(paths)
61
+ common_paths.each { |cp| result << { sha: sha, path: cp } }
62
+ end
63
+
64
+ result
65
+ end
66
+
67
+ def package_is_versioned?(package)
68
+ package_revision = package['revision']
69
+
70
+ !package_revision.nil? && !package_revision.empty?
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'xmlsimple'
4
+ require 'with_env'
5
+ require 'license_finder/package_utils/gradle_dependency_finder'
6
+
7
+ module LicenseFinder
8
+ class Gradle < PackageManager
9
+ def initialize(options = {})
10
+ super
11
+ @command = options[:gradle_command] || package_management_command
12
+ @include_groups = options[:gradle_include_groups]
13
+ end
14
+
15
+ def current_packages
16
+ WithEnv.with_env('TERM' => 'dumb') do
17
+ command = "#{@command} downloadLicenses"
18
+ _stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(command) }
19
+ raise "Command '#{command}' failed to execute: #{stderr}" unless status.success?
20
+
21
+ dependencies = GradleDependencyFinder.new(project_path).dependencies
22
+ packages = dependencies.flat_map do |xml_file|
23
+ options = { 'GroupTags' => { 'dependencies' => 'dependency' } }
24
+ contents = XmlSimple.xml_in(xml_file, options).fetch('dependency', [])
25
+ contents.map do |dep|
26
+ GradlePackage.new(dep, logger: logger, include_groups: @include_groups)
27
+ end
28
+ end
29
+ packages.uniq
30
+ end
31
+ end
32
+
33
+ def package_management_command
34
+ if Platform.windows?
35
+ wrapper = 'gradlew.bat'
36
+ gradle = 'gradle.bat'
37
+ else
38
+ wrapper = './gradlew'
39
+ gradle = 'gradle'
40
+ end
41
+
42
+ File.exist?(File.join(project_path, wrapper)) ? wrapper : gradle
43
+ end
44
+
45
+ def project_root?
46
+ active? && root_module?
47
+ end
48
+
49
+ private
50
+
51
+ def root_module?
52
+ return false if project_path.to_s.include?('buildSrc')
53
+
54
+ command = "#{package_management_command} -Dorg.gradle.jvmargs=-Xmx6144m properties | grep 'parent: '"
55
+ stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(command) }
56
+
57
+ if stderr&.include?('not part of the build defined by settings file')
58
+ Dir.chdir(project_path) do
59
+ Cmd.run('touch settings.gradle')
60
+ stdout, stderr, status = Cmd.run(command)
61
+ Cmd.run('rm settings.gradle')
62
+ end
63
+ end
64
+
65
+ raise "Command '#{command}' failed to execute in #{project_path}: #{stderr}" unless status.success?
66
+
67
+ root_project_name = stdout.gsub(/\s|parent:|\n/, '')
68
+ root_project_name == 'null'
69
+ end
70
+
71
+ def detected_package_path
72
+ alternate_build_file = build_file_from_settings(project_path)
73
+ return alternate_build_file if alternate_build_file
74
+
75
+ build_gradle_file
76
+ end
77
+
78
+ def build_gradle_file
79
+ kotlin_gradle_path = project_path.join('build.gradle.kts')
80
+ return kotlin_gradle_path if File.exist? kotlin_gradle_path
81
+
82
+ project_path.join('build.gradle')
83
+ end
84
+
85
+ def build_file_from_settings(project_path)
86
+ settings_gradle_path = project_path.join 'settings.gradle'
87
+
88
+ return nil unless File.exist? settings_gradle_path
89
+
90
+ settings_gradle = File.read settings_gradle_path
91
+
92
+ match = /rootProject.buildFileName = ['"](?<build_file>.*)['"]/.match settings_gradle
93
+
94
+ return nil unless match
95
+
96
+ project_path.join match[:build_file]
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'license_finder/shared_helpers/common_path'
4
+
5
+ module LicenseFinder
6
+ class Gvt < PackageManager
7
+ def possible_package_paths
8
+ potential_path = project_path.join('vendor', 'manifest')
9
+ [Pathname(potential_path)]
10
+ end
11
+
12
+ def package_management_command
13
+ 'gvt'
14
+ end
15
+
16
+ def prepare_command
17
+ 'gvt restore'
18
+ end
19
+
20
+ def current_packages
21
+ shell_command = "cd #{project_path} && gvt list -f \"{{.Importpath}} {{.Revision}} {{.Repository}}\""
22
+ path = project_path.join(project_path, 'vendor')
23
+
24
+ stdout, _stderr, status = Cmd.run(shell_command)
25
+ return [] unless status.success?
26
+
27
+ packages_from_output(stdout, path)
28
+ end
29
+
30
+ def self.takes_priority_over
31
+ Go15VendorExperiment
32
+ end
33
+
34
+ private
35
+
36
+ def packages_from_output(output, path)
37
+ package_lines = output.split("\n")
38
+ packages_by_sha = {}
39
+ package_lines.each do |p|
40
+ package_path, sha, repo = p.split
41
+ if packages_by_sha[sha].nil?
42
+ packages_by_sha[sha] = {}
43
+ packages_by_sha[sha]['paths'] = [package_path]
44
+ packages_by_sha[sha]['repo'] = repo
45
+ else
46
+ packages_by_sha[sha]['paths'] << package_path
47
+ end
48
+ end
49
+
50
+ result = []
51
+ packages_by_sha.each do |sha, info|
52
+ paths = CommonPathHelper.longest_common_paths(info['paths'])
53
+
54
+ paths.each { |p| result << [sha, p, info['repo']] }
55
+ end
56
+
57
+ result.map do |package_info|
58
+ sha, import_path, repo = package_info
59
+
60
+ GoPackage.from_dependency({
61
+ 'ImportPath' => import_path,
62
+ 'InstallPath' => path.join(import_path),
63
+ 'Rev' => sha,
64
+ 'Homepage' => repo
65
+ }, nil, true)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'xmlsimple'
4
+ require 'license_finder/package_utils/maven_dependency_finder'
5
+
6
+ module LicenseFinder
7
+ class Maven < PackageManager
8
+ def initialize(options = {})
9
+ super
10
+ @ignored_groups = options[:ignored_groups]
11
+ @include_groups = options[:maven_include_groups]
12
+ @maven_options = options[:maven_options]
13
+ end
14
+
15
+ def current_packages
16
+ command = "#{package_management_command} org.codehaus.mojo:license-maven-plugin:download-licenses"
17
+ command += " -Dlicense.excludedScopes=#{@ignored_groups.to_a.join(',')}" if @ignored_groups && !@ignored_groups.empty?
18
+ command += " #{@maven_options}" unless @maven_options.nil?
19
+ _stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(command) }
20
+ raise "Command '#{command}' failed to execute: #{stderr}" unless status.success?
21
+
22
+ dependencies = MavenDependencyFinder.new(project_path).dependencies
23
+ packages = dependencies.flat_map do |xml|
24
+ options = {
25
+ 'GroupTags' => { 'licenses' => 'license', 'dependencies' => 'dependency' },
26
+ 'ForceArray' => %w[license dependency]
27
+ }
28
+ contents = XmlSimple.xml_in(xml, options)['dependencies']
29
+ contents.map do |dep|
30
+ MavenPackage.new(dep, logger: logger, include_groups: @include_groups)
31
+ end
32
+ end
33
+ packages.uniq
34
+ end
35
+
36
+ def package_management_command
37
+ wrapper = if Platform.windows?
38
+ 'mvnw.cmd'
39
+ else
40
+ './mvnw'
41
+ end
42
+ maven = 'mvn'
43
+
44
+ File.exist?(File.join(project_path, wrapper)) ? wrapper : maven
45
+ end
46
+
47
+ def possible_package_paths
48
+ [project_path.join('pom.xml')]
49
+ end
50
+
51
+ def project_root?
52
+ active? && root_module?
53
+ end
54
+
55
+ private
56
+
57
+ def root_module?
58
+ command = "#{package_management_command} help:evaluate -Dexpression=project.parent -q -DforceStdout"
59
+ stdout, _stderr, status = Dir.chdir(project_path) { Cmd.run(command) }
60
+ raise "Command '#{command}' failed to execute in #{project_path}: #{stdout}" unless status.success?
61
+
62
+ stdout.include?('null object or invalid expression')
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class Mix < PackageManager
5
+ def initialize(options = {})
6
+ super
7
+ @command = options[:mix_command] || package_management_command
8
+ @elixir_command = options[:elixir_command] || 'elixir'
9
+ @deps_path = Pathname(options[:mix_deps_dir] || 'deps')
10
+ end
11
+
12
+ def current_packages
13
+ mix_output.map do |name, version|
14
+ MixPackage.new(
15
+ name,
16
+ version,
17
+ install_path: @deps_path.join(name),
18
+ logger: logger,
19
+ spec_licenses: licenses(name)
20
+ )
21
+ end
22
+ end
23
+
24
+ def licenses(name)
25
+ licenses_by_package = load_all_licenses
26
+ licenses_by_package.fetch(name, ['license is not in deps'])
27
+ end
28
+
29
+ def package_management_command
30
+ 'mix'
31
+ end
32
+
33
+ def self.package_lock_file
34
+ 'mix.lock'
35
+ end
36
+
37
+ def prepare_command
38
+ 'mix deps.get'
39
+ end
40
+
41
+ def possible_package_paths
42
+ [project_path.join('mix.exs')]
43
+ end
44
+
45
+ def installed?(logger = Core.default_logger)
46
+ if package_management_command.nil?
47
+ logger.debug self.class, 'no command defined'
48
+ true
49
+ elsif command_exists?('elixir') && command_exists?('mix')
50
+ logger.debug self.class, 'is installed', color: :green
51
+ true
52
+ else
53
+ logger.info self.class, '(elixir) is not installed', color: :red
54
+ false
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def load_all_licenses
61
+ elixir_code = <<-ELIXIR
62
+ deps_path = "#{@deps_path}"
63
+
64
+ case File.ls(deps_path) do
65
+ {:ok, dirs} ->
66
+ Enum.reduce(dirs, [], fn name, acc ->
67
+ with hexmetadata_file <- Path.join([deps_path, name, "hex_metadata.config"]),
68
+ {:ok, metadata} <- :file.consult(hexmetadata_file),
69
+ {"licenses", licenses} <- List.keyfind(metadata, "licenses", 0) do
70
+ [[name, licenses] | acc]
71
+ else
72
+ _ -> acc
73
+ end
74
+ end)
75
+ {:error, _} ->
76
+ []
77
+ end
78
+ |> IO.inspect(limit: :infinity)
79
+ ELIXIR
80
+ command = "#{@elixir_command} -e '#{elixir_code}'"
81
+ return {} unless File.directory?(project_path)
82
+
83
+ stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(command) }
84
+ raise "Command '#{command}' failed to execute: #{stderr}" unless status.success?
85
+
86
+ Hash[JSON.parse(stdout)]
87
+ end
88
+
89
+ def end_of_package_lines?(line)
90
+ line == 'ok'
91
+ end
92
+
93
+ def mix_output
94
+ command = "#{@command} deps"
95
+ stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(command) }
96
+ raise "Command '#{command}' failed to execute: #{stderr}" unless status.success?
97
+
98
+ packages_lines(stdout)
99
+ .reject { |package_lines| package_lines.length == 1 || package_lines.empty? } # in_umbrella: true dependencies
100
+ .map { |package_lines| [package_lines[0].split(' ')[1], resolve_version(package_lines[1])] }
101
+ end
102
+
103
+ def packages_lines(stdout)
104
+ packages_lines, last_package_lines =
105
+ stdout
106
+ .each_line
107
+ .map(&:strip)
108
+ .reject { |line| end_of_package_lines?(line) }
109
+ .reduce([[], []]) do |(packages_lines, package_lines), line|
110
+ if start_of_package_lines?(line)
111
+ packages_lines.push(package_lines) unless package_lines.empty?
112
+
113
+ [packages_lines, [line]]
114
+ else
115
+ package_lines.push(line)
116
+ [packages_lines, package_lines]
117
+ end
118
+ end
119
+
120
+ packages_lines.push(last_package_lines)
121
+ end
122
+
123
+ def resolve_version(line)
124
+ line =~ /locked at ([^\s]+)/ ? Regexp.last_match(1) : line
125
+ end
126
+
127
+ def start_of_package_lines?(line)
128
+ line.start_with?('* ')
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'tempfile'
5
+
6
+ module LicenseFinder
7
+ class NPM < PackageManager
8
+ def initialize(options = {})
9
+ super
10
+ @npm_options = options[:npm_options]
11
+ end
12
+
13
+ def current_packages
14
+ NpmPackage.packages_from_json(npm_json, detected_package_path)
15
+ end
16
+
17
+ def package_management_command
18
+ 'npm'
19
+ end
20
+
21
+ def prepare_command
22
+ 'npm install --no-save --ignore-scripts'
23
+ end
24
+
25
+ def possible_package_paths
26
+ [project_path.join('package.json')]
27
+ end
28
+
29
+ def prepare
30
+ prep_cmd = "#{prepare_command}#{production_flag}"
31
+ _stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(prep_cmd) }
32
+
33
+ return if status.success?
34
+
35
+ log_errors stderr
36
+ raise "Prepare command '#{prep_cmd}' failed" unless @prepare_no_fail
37
+ end
38
+
39
+ private
40
+
41
+ def npm_json
42
+ command = "#{package_management_command} list --json --long#{production_flag}"
43
+ command += " #{@npm_options}" unless @npm_options.nil?
44
+ stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(command) }
45
+ # we can try and continue if we got an exit status 1 - unmet peer dependency
46
+ raise "Command '#{command}' failed to execute: #{stderr}" if !status.success? && status.exitstatus != 1
47
+
48
+ JSON.parse(stdout)
49
+ end
50
+
51
+ def production_flag
52
+ return '' if @ignored_groups.nil?
53
+
54
+ @ignored_groups.include?('devDependencies') ? ' --production' : ''
55
+ end
56
+ end
57
+ end