gitlab-license_finder 6.14.2.1

Sign up to get free protection for your applications and to get access to all the features.
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,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'license_finder/package'
4
+
5
+ module LicenseFinder
6
+ class GoPackage < Package
7
+ def package_manager
8
+ 'Go'
9
+ end
10
+
11
+ def package_url
12
+ "https://pkg.go.dev/#{CGI.escape(name)}@#{CGI.escape(version)}"
13
+ end
14
+
15
+ class << self
16
+ def from_dependency(hash, prefix, full_version)
17
+ name = hash['ImportPath']
18
+ install_path = hash['InstallPath']
19
+ install_path ||= install_path(prefix.join(name))
20
+ version = full_version ? hash['Rev'].gsub('+incompatible', '') : hash['Rev'][0..6]
21
+ homepage = hash['Homepage']
22
+ new(name, version, install_path: install_path, package_manager: 'Go', homepage: homepage)
23
+ end
24
+
25
+ private
26
+
27
+ def install_path(path)
28
+ Pathname(path).cleanpath.to_s
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class GradlePackage < Package
5
+ def initialize(spec, options = {})
6
+ name = spec['name']
7
+ if name.scan(':').size >= 1
8
+ group, name, version = name.split(':')
9
+ else
10
+ version = 'unknown'
11
+ end
12
+
13
+ name = options[:include_groups] ? "#{group}:#{name}" : name
14
+
15
+ licenses = Array(spec['license'])
16
+ .map { |l| l['name'] }
17
+ .reject { |reject_name| reject_name == 'No license found' }
18
+
19
+ super(name, version, options.merge(spec_licenses: licenses))
20
+ end
21
+
22
+ def package_manager
23
+ 'Gradle'
24
+ end
25
+
26
+ def package_url
27
+ "https://plugins.gradle.org/plugin/#{CGI.escape(name)}/#{CGI.escape(version)}"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class ManualPackage < Package
5
+ def ==(other)
6
+ eql? other
7
+ end
8
+
9
+ def eql?(other)
10
+ name == other.name
11
+ end
12
+
13
+ def hash
14
+ name.hash
15
+ end
16
+
17
+ private
18
+
19
+ def licenses_from_spec
20
+ Set.new
21
+ end
22
+
23
+ def licenses_from_files
24
+ Set.new
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class MavenPackage < Package
5
+ def initialize(spec, options = {})
6
+ name = spec['artifactId']
7
+ name = "#{spec['groupId']}:#{name}" if options[:include_groups]
8
+
9
+ super(
10
+ name,
11
+ spec['version'],
12
+ options.merge(
13
+ spec_licenses: Array(spec['licenses']).map { |l| l['name'] },
14
+ groups: Array(spec['groupId'])
15
+ )
16
+ )
17
+ end
18
+
19
+ def package_manager
20
+ 'Maven'
21
+ end
22
+
23
+ def package_url
24
+ "https://search.maven.org/artifact/#{CGI.escape(groups.first)}/#{CGI.escape(name.split(':').last)}/#{CGI.escape(version)}/jar"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class MergedPackage < Package
5
+ extend Forwardable
6
+ attr_reader :dependency
7
+
8
+ def initialize(package, aggregate_paths)
9
+ @dependency = package
10
+ @aggregate_paths = aggregate_paths.map { |p| Pathname(p) }
11
+ super(package.name, package.version)
12
+ end
13
+
14
+ def_delegators :@dependency, :name, :version, :authors, :summary, :description, :homepage, :package_url, :children, :parents,
15
+ :groups, :permitted, :restricted, :manual_approval, :install_path, :licenses, :approved_manually?,
16
+ :approved_manually!, :approved?, :permitted!, :permitted?, :restricted!, :restricted?, :hash,
17
+ :activations, :missing, :license_names_from_spec, :decided_licenses, :licensing, :decide_on_license,
18
+ :license_files, :package_manager, :missing?, :log_activation, :notice_files
19
+
20
+ def aggregate_paths
21
+ @aggregate_paths.map { |p| p.expand_path.to_s }
22
+ end
23
+
24
+ def <=>(other)
25
+ dependency <=> other.dependency
26
+ end
27
+
28
+ def eql?(other)
29
+ if other.instance_of? MergedPackage
30
+ other.dependency.eql?(dependency)
31
+ else
32
+ dependency.eql?(other)
33
+ end
34
+ end
35
+
36
+ def ==(other)
37
+ dependency.eql?(other.dependency) && aggregate_paths.eql?(other.aggregate_paths)
38
+ end
39
+
40
+ def method_missing(_method_name)
41
+ nil
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class MixPackage < Package
5
+ def package_manager
6
+ 'Mix'
7
+ end
8
+
9
+ def package_url
10
+ "https://hex.pm/packages/#{CGI.escape(name)}/#{CGI.escape(version)}"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class NpmPackage < Package
5
+ attr_accessor :identifier, :dependencies, :groups, :json
6
+
7
+ class << self
8
+ def packages_from_json(npm_json, package_path)
9
+ @packages = flattened_dependencies(npm_json)
10
+ package_json = PackageJson.new(package_path)
11
+ populate_groups(package_json)
12
+ @packages.reject! do |_identifier, package|
13
+ package.name.empty? &&
14
+ package.version.empty? &&
15
+ package.licenses.length == 1 &&
16
+ package.licenses.first.name == 'unknown'
17
+ end
18
+ @packages.values
19
+ end
20
+
21
+ private
22
+
23
+ def flattened_dependencies(npm_json, existing_packages = {})
24
+ identifier = Identifier.from_hash npm_json
25
+ if existing_packages[identifier].nil?
26
+ existing_packages[identifier] = NpmPackage.new(npm_json) if identifier
27
+ npm_json.fetch('dependencies', {}).values.map do |d|
28
+ flattened_dependencies(d, existing_packages)
29
+ end
30
+ else
31
+ duplicate_package = NpmPackage.new(npm_json)
32
+ unless existing_packages[identifier].dependencies.include?(duplicate_package.dependencies)
33
+ existing_packages[identifier].dependencies |= duplicate_package.dependencies
34
+ npm_json.fetch('dependencies', {}).values.map do |d|
35
+ flattened_dependencies(d, existing_packages)
36
+ end
37
+ end
38
+ end
39
+ existing_packages
40
+ end
41
+
42
+ def populate_groups(package_json)
43
+ package_json.groups.each do |group|
44
+ group.package_names.each do |package_name|
45
+ @packages.each_key do |identifier|
46
+ next unless identifier.name == package_name
47
+
48
+ dependency = @packages[identifier]
49
+ dependency.groups |= [group.name]
50
+ populate_child_groups(dependency, @packages)
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ def populate_child_groups(dependency, packages, populated_ids = [])
57
+ dependency.dependencies.each do |id|
58
+ next if populated_ids.include? id
59
+
60
+ populated_ids.push id
61
+ packages[id].groups |= dependency.groups
62
+ populate_child_groups(packages[id], packages, populated_ids)
63
+ end
64
+ end
65
+ end
66
+
67
+ def initialize(npm_json)
68
+ @json = npm_json
69
+ @identifier = Identifier.from_hash(npm_json)
70
+ @dependencies = deps_from_json
71
+ super(@identifier.name,
72
+ @identifier.version,
73
+ description: npm_json['description'],
74
+ homepage: npm_json['homepage'],
75
+ spec_licenses: Package.license_names_from_standard_spec(npm_json),
76
+ install_path: npm_json['path'],
77
+ children: @dependencies.map(&:name))
78
+ end
79
+
80
+ def ==(other)
81
+ other.is_a?(NpmPackage) && @identifier == other.identifier
82
+ end
83
+
84
+ def to_s
85
+ @identifier.to_s
86
+ end
87
+
88
+ def package_manager
89
+ 'Npm'
90
+ end
91
+
92
+ def package_url
93
+ "https://www.npmjs.com/package/#{CGI.escape(name)}/v/#{CGI.escape(version)}"
94
+ end
95
+
96
+ private
97
+
98
+ def deps_from_json
99
+ @json.fetch('dependencies', {}).values.map { |dep| Identifier.from_hash(dep) }.compact
100
+ end
101
+
102
+ class Identifier
103
+ attr_accessor :name, :version
104
+
105
+ def initialize(name, version)
106
+ @name = name
107
+ @version = version
108
+ end
109
+
110
+ def self.from_hash(hash)
111
+ name = hash['name']
112
+ version = hash['version']
113
+ return nil if name.nil? || version.nil?
114
+
115
+ Identifier.new(name, version)
116
+ end
117
+
118
+ def ==(other)
119
+ other.is_a?(Identifier) && @name == other.name && @version == other.version
120
+ end
121
+
122
+ def eql?(other)
123
+ self == other
124
+ end
125
+
126
+ def hash
127
+ [@name, @version].hash
128
+ end
129
+
130
+ def <=>(other)
131
+ sort_name = @name <=> other.name
132
+ sort_name.zero? ? @version <=> other.version : sort_name
133
+ end
134
+
135
+ def to_s
136
+ "#{@name} - #{@version}"
137
+ end
138
+ end
139
+
140
+ class Group
141
+ attr_accessor :name, :package_names
142
+
143
+ def initialize(name, hash)
144
+ @name = name
145
+ @package_names = hash.keys
146
+ end
147
+
148
+ def include?(identifier)
149
+ @package_names.include? identifier.name
150
+ end
151
+
152
+ def to_s
153
+ @name
154
+ end
155
+ end
156
+
157
+ class PackageJson
158
+ attr_reader :groups
159
+ DEPENDENCY_GROUPS = %w[dependencies devDependencies].freeze
160
+
161
+ def initialize(path)
162
+ json = JSON.parse(File.read(path), max_nesting: false)
163
+ @groups = DEPENDENCY_GROUPS.map { |name| Group.new(name, json.fetch(name, {})) }
164
+ end
165
+
166
+ def groups_for(identifier)
167
+ @groups.select { |g| g.include? identifier }.map(&:name)
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class NugetPackage < Package
5
+ def package_manager
6
+ 'Nuget'
7
+ end
8
+
9
+ def package_url
10
+ "https://www.nuget.org/packages/#{CGI.escape(name)}/#{CGI.escape(version)}"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module LicenseFinder
6
+ class PipPackage < Package
7
+ LICENSE_FORMAT = /^License.*::\s*(.*)$/.freeze
8
+ INVALID_LICENSES = ['', 'UNKNOWN'].to_set
9
+
10
+ def self.license_names_from_spec(spec)
11
+ license_names = spec['license'].to_s.strip.split(' or ')
12
+ has_unrecognized_license = false
13
+
14
+ license_names.each do |license_name|
15
+ license = License.find_by_name(license_name.strip)
16
+
17
+ has_unrecognized_license ||= license.unrecognized_matcher?
18
+ end
19
+
20
+ return license_names if !license_names.empty? && !has_unrecognized_license
21
+
22
+ spec
23
+ .fetch('classifiers', [])
24
+ .select { |c| c =~ LICENSE_FORMAT }
25
+ .map { |c| c.gsub(LICENSE_FORMAT, '\1') }
26
+ end
27
+
28
+ def initialize(name, version, spec, options = {})
29
+ super(
30
+ name,
31
+ version,
32
+ options.merge(
33
+ authors: spec['author'],
34
+ summary: spec['summary'],
35
+ description: spec['description'],
36
+ homepage: spec['home_page'],
37
+ spec_licenses: self.class.license_names_from_spec(spec)
38
+ )
39
+ )
40
+ end
41
+
42
+ def package_manager
43
+ 'Pip'
44
+ end
45
+
46
+ def package_url
47
+ "https://pypi.org/project/#{CGI.escape(name)}/#{CGI.escape(version)}/"
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class RebarPackage < Package
5
+ def package_manager
6
+ 'Rebar'
7
+ end
8
+
9
+ def package_url
10
+ "https://hex.pm/packages/#{CGI.escape(name)}/#{CGI.escape(version)}"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class SbtPackage < Package
5
+ def initialize(spec, options = {})
6
+ name = spec['artifactId']
7
+ name = "#{spec['groupId']}:#{name}" if options[:include_groups]
8
+
9
+ super(
10
+ name,
11
+ spec['version'],
12
+ options.merge(
13
+ spec_licenses: Array(spec['licenses']).map { |l| l['name'] }
14
+ )
15
+ )
16
+ end
17
+
18
+ def package_manager
19
+ 'Sbt'
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class SpmPackage < Package
5
+ def initialize(name, version, license_text, options = {})
6
+ super(name, version, options)
7
+ @license = License.find_by_text(license_text.to_s)
8
+ end
9
+
10
+ def licenses_from_spec
11
+ [@license].compact
12
+ end
13
+
14
+ def package_manager
15
+ 'Spm'
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class YarnPackage < Package
5
+ def package_manager
6
+ 'Yarn'
7
+ end
8
+
9
+ def package_url
10
+ "https://yarn.pm/#{CGI.escape(name)}"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ module Platform
5
+ def self.darwin?
6
+ RUBY_PLATFORM =~ /darwin/
7
+ end
8
+
9
+ def self.windows?
10
+ # SO: What is the correct way to detect if ruby is running on Windows?,
11
+ # cf. https://stackoverflow.com/a/21468976/2592915
12
+ Gem.win_platform? || RUBY_PLATFORM =~ /mswin|cygwin|mingw/
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class ProjectFinder
5
+ def initialize(main_project_path, strict_matching = false)
6
+ @package_managers = LicenseFinder::Scanner::PACKAGE_MANAGERS
7
+ @strict_matching = strict_matching
8
+ @main_project_path = main_project_path
9
+ end
10
+
11
+ def find_projects
12
+ project_paths = []
13
+ all_paths = find_all_paths
14
+ until all_paths.empty?
15
+ project_paths << collect_project_path(all_paths)
16
+ all_paths.shift
17
+ end
18
+ project_paths.compact
19
+ end
20
+
21
+ def collect_project_path(all_paths)
22
+ potential_project_path = all_paths.first
23
+ is_active_project = active_project?(potential_project_path)
24
+ return unless is_active_project
25
+
26
+ potential_project_path.to_s
27
+ end
28
+
29
+ private
30
+
31
+ def find_all_paths
32
+ Dir.glob("#{@main_project_path}/**/").map { |path| full_path(path) }
33
+ end
34
+
35
+ def remove_nested(pathname, paths)
36
+ return if project_root?(pathname)
37
+
38
+ paths.reject! { |path| nested_path?(path, pathname) }
39
+ end
40
+
41
+ def project_root?(pathname)
42
+ full_path(@main_project_path).to_s == pathname.to_s
43
+ end
44
+
45
+ def active_project?(project_path)
46
+ active_project = @package_managers.map do |pm_class|
47
+ pm = pm_class.new(project_path: project_path, strict_matching: @strict_matching)
48
+ pm.active?
49
+ end
50
+
51
+ active_project.include?(true)
52
+ end
53
+
54
+ def full_path(rel_path)
55
+ Pathname.new(rel_path).expand_path
56
+ end
57
+
58
+ def nested_path?(path, pathname)
59
+ path.to_s.start_with?(pathname.to_s) && path.to_s != pathname.to_s
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LicenseFinder
4
+ class Report
5
+ def self.of(dependencies, options)
6
+ new(dependencies, options).to_s
7
+ end
8
+
9
+ def initialize(dependencies, options)
10
+ @dependencies = dependencies
11
+ @project_name = options[:project_name]
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :dependencies, :project_name
17
+
18
+ def sorted_dependencies
19
+ dependencies.sort
20
+ end
21
+ end
22
+ end
23
+
24
+ require 'license_finder/reports/erb_report'
25
+ require 'license_finder/reports/csv_report'
26
+ require 'license_finder/reports/text_report'
27
+ require 'license_finder/reports/diff_report'
28
+ require 'license_finder/reports/merged_report'
29
+ require 'license_finder/reports/html_report'
30
+ require 'license_finder/reports/markdown_report'
31
+ require 'license_finder/reports/xml_report'
32
+ require 'license_finder/reports/json_report'
33
+ require 'license_finder/reports/junit_report'
@@ -0,0 +1,99 @@
1
+ require 'csv'
2
+
3
+ module LicenseFinder
4
+ class CsvReport < Report
5
+ COMMA_SEP = ','.freeze
6
+ NEWLINE_SEP = '\@NL'.freeze
7
+ AVAILABLE_COLUMNS = %w[name version authors licenses license_links approved summary description homepage install_path package_manager groups texts notice].freeze
8
+ MISSING_DEPENDENCY_TEXT = 'This package is not installed. Please install to determine licenses.'.freeze
9
+
10
+ def initialize(dependencies, options)
11
+ super
12
+ options[:columns] ||= %w[name version licenses]
13
+ @columns = Array(options[:columns]) & self.class::AVAILABLE_COLUMNS
14
+ @write_headers = options[:write_headers] || false
15
+ end
16
+
17
+ def to_s
18
+ CSV.generate(col_sep: self.class::COMMA_SEP, headers: @columns, write_headers: @write_headers) do |csv|
19
+ sorted_dependencies.each do |s|
20
+ csv << format_dependency(s)
21
+ end
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def format_dependency(dep)
28
+ @columns.map do |column|
29
+ send("format_#{column}", dep)
30
+ end
31
+ end
32
+
33
+ def format_texts(dep)
34
+ dep.license_files.map { |file| file.text.split(/[\n\r]+/).join(self.class::NEWLINE_SEP) }
35
+ .join(self.class::NEWLINE_SEP).force_encoding("ISO-8859-1").encode("UTF-8")
36
+ end
37
+
38
+ def format_notice(dep)
39
+ dep.notice_files.map { |file| file.text.split(/[\n\r]+/).join(self.class::NEWLINE_SEP) }
40
+ .join(self.class::NEWLINE_SEP).force_encoding("ISO-8859-1").encode("UTF-8")
41
+ end
42
+
43
+ def format_name(dep)
44
+ dep.name
45
+ end
46
+
47
+ def format_version(dep)
48
+ dep.version
49
+ end
50
+
51
+ def format_authors(dep)
52
+ dep.authors.to_s.strip
53
+ end
54
+
55
+ def format_homepage(dep)
56
+ dep.homepage
57
+ end
58
+
59
+ def format_licenses(dep)
60
+ if dep.missing?
61
+ MISSING_DEPENDENCY_TEXT
62
+ else
63
+ dep.licenses.map(&:name).join(self.class::COMMA_SEP)
64
+ end
65
+ end
66
+
67
+ def format_license_links(dep)
68
+ dep.licenses.map(&:url).join(self.class::COMMA_SEP)
69
+ end
70
+
71
+ def format_approved(dep)
72
+ dep.approved? ? 'Approved' : 'Not approved'
73
+ end
74
+
75
+ def format_summary(dep)
76
+ dep.summary.to_s.strip
77
+ end
78
+
79
+ def format_description(dep)
80
+ dep.description.to_s.strip
81
+ end
82
+
83
+ def format_install_path(dep)
84
+ dep.install_path
85
+ end
86
+
87
+ def format_package_manager(dep)
88
+ dep.package_manager
89
+ end
90
+
91
+ def format_groups(dep)
92
+ if dep.groups.nil?
93
+ ''
94
+ else
95
+ dep.groups.join(self.class::COMMA_SEP)
96
+ end
97
+ end
98
+ end
99
+ end