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,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