license_finder-rubyzip3 7.2.1.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.
- checksums.yaml +7 -0
- data/.force-build +0 -0
- data/.github/dependabot.yml +16 -0
- data/.gitignore +13 -0
- data/.pre-commit-hooks.yaml +10 -0
- data/.rspec +1 -0
- data/.rubocop.yml +84 -0
- data/CHANGELOG.md +1066 -0
- data/CONTRIBUTING.md +122 -0
- data/Dockerfile +275 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +597 -0
- data/Rakefile +77 -0
- data/TODO.md +12 -0
- data/VERSION +1 -0
- data/appveyor.yml +21 -0
- data/bin/license_finder +6 -0
- data/bin/license_finder_pip.py +43 -0
- data/ci/pipelines/pull-request.yml.erb +138 -0
- data/ci/pipelines/release.yml.erb +176 -0
- data/ci/scripts/containerize-tests.sh +14 -0
- data/ci/scripts/pushscript.sh +31 -0
- data/ci/scripts/run-rubocop.sh +15 -0
- data/ci/scripts/run-tests.sh +41 -0
- data/ci/scripts/test.ps1 +81 -0
- data/ci/scripts/updateChangelog.sh +84 -0
- data/ci/tasks/build-and-push-gem.yml +10 -0
- data/ci/tasks/build-windows.yml +6 -0
- data/ci/tasks/build.yml +16 -0
- data/ci/tasks/rubocop.yml +15 -0
- data/ci/tasks/run-tests.yml +10 -0
- data/ci/tasks/update-changelog.yml +18 -0
- data/dlf +21 -0
- data/examples/Gemfile +4 -0
- data/examples/custom_erb_template.rb +24 -0
- data/examples/extract_license_data.rb +63 -0
- data/examples/sample_template.erb +7 -0
- data/lib/license_finder/cli/approvals.rb +28 -0
- data/lib/license_finder/cli/base.rb +113 -0
- data/lib/license_finder/cli/dependencies.rb +44 -0
- data/lib/license_finder/cli/ignored_dependencies.rb +32 -0
- data/lib/license_finder/cli/ignored_groups.rb +32 -0
- data/lib/license_finder/cli/inherited_decisions.rb +50 -0
- data/lib/license_finder/cli/licenses.rb +31 -0
- data/lib/license_finder/cli/main.rb +229 -0
- data/lib/license_finder/cli/makes_decisions.rb +38 -0
- data/lib/license_finder/cli/patched_thor.rb +33 -0
- data/lib/license_finder/cli/permitted_licenses.rb +32 -0
- data/lib/license_finder/cli/project_name.rb +32 -0
- data/lib/license_finder/cli/restricted_licenses.rb +32 -0
- data/lib/license_finder/cli.rb +20 -0
- data/lib/license_finder/configuration.rb +197 -0
- data/lib/license_finder/core.rb +121 -0
- data/lib/license_finder/decision_applier.rb +70 -0
- data/lib/license_finder/decisions.rb +334 -0
- data/lib/license_finder/decisions_factory.rb +13 -0
- data/lib/license_finder/diff.rb +51 -0
- data/lib/license_finder/license/any_matcher.rb +15 -0
- data/lib/license_finder/license/definitions.rb +498 -0
- data/lib/license_finder/license/header_matcher.rb +17 -0
- data/lib/license_finder/license/matcher.rb +24 -0
- data/lib/license_finder/license/none_matcher.rb +11 -0
- data/lib/license_finder/license/template.rb +19 -0
- data/lib/license_finder/license/templates/0BSD.txt +10 -0
- data/lib/license_finder/license/templates/AGPL3.txt +661 -0
- data/lib/license_finder/license/templates/Apache1_1.txt +16 -0
- data/lib/license_finder/license/templates/Apache2.txt +170 -0
- data/lib/license_finder/license/templates/Artistic.txt +128 -0
- data/lib/license_finder/license/templates/BSD.txt +24 -0
- data/lib/license_finder/license/templates/CC01.txt +30 -0
- data/lib/license_finder/license/templates/CC01_alt.txt +31 -0
- data/lib/license_finder/license/templates/CDDL1.txt +131 -0
- data/lib/license_finder/license/templates/CDDL1_1.txt +123 -0
- data/lib/license_finder/license/templates/CPL1.txt +217 -0
- data/lib/license_finder/license/templates/EPL1.txt +86 -0
- data/lib/license_finder/license/templates/EPL2.txt +80 -0
- data/lib/license_finder/license/templates/GPLv2.txt +339 -0
- data/lib/license_finder/license/templates/GPLv3.txt +674 -0
- data/lib/license_finder/license/templates/ISC.txt +2 -0
- data/lib/license_finder/license/templates/LGPL.txt +165 -0
- data/lib/license_finder/license/templates/LGPL2_1.txt +169 -0
- data/lib/license_finder/license/templates/MIT.txt +9 -0
- data/lib/license_finder/license/templates/MPL1_1.txt +469 -0
- data/lib/license_finder/license/templates/MPL2.txt +373 -0
- data/lib/license_finder/license/templates/NewBSD.txt +21 -0
- data/lib/license_finder/license/templates/OFL.txt +91 -0
- data/lib/license_finder/license/templates/Python.txt +47 -0
- data/lib/license_finder/license/templates/Ruby.txt +52 -0
- data/lib/license_finder/license/templates/SimplifiedBSD.txt +19 -0
- data/lib/license_finder/license/templates/Unlicense.txt +24 -0
- data/lib/license_finder/license/templates/WTFPL.txt +14 -0
- data/lib/license_finder/license/templates/Zlib.txt +17 -0
- data/lib/license_finder/license/text.rb +49 -0
- data/lib/license_finder/license.rb +123 -0
- data/lib/license_finder/license_aggregator.rb +59 -0
- data/lib/license_finder/logger.rb +69 -0
- data/lib/license_finder/manual_licenses.rb +79 -0
- data/lib/license_finder/package.rb +195 -0
- data/lib/license_finder/package_delta.rb +61 -0
- data/lib/license_finder/package_manager.rb +183 -0
- data/lib/license_finder/package_managers/bower.rb +37 -0
- data/lib/license_finder/package_managers/bundler.rb +110 -0
- data/lib/license_finder/package_managers/cargo.rb +38 -0
- data/lib/license_finder/package_managers/carthage.rb +68 -0
- data/lib/license_finder/package_managers/cocoa_pods.rb +66 -0
- data/lib/license_finder/package_managers/composer.rb +63 -0
- data/lib/license_finder/package_managers/conan.rb +70 -0
- data/lib/license_finder/package_managers/conda.rb +131 -0
- data/lib/license_finder/package_managers/dep.rb +45 -0
- data/lib/license_finder/package_managers/dotnet.rb +86 -0
- data/lib/license_finder/package_managers/erlangmk.rb +50 -0
- data/lib/license_finder/package_managers/glide.rb +42 -0
- data/lib/license_finder/package_managers/go_15vendorexperiment.rb +87 -0
- data/lib/license_finder/package_managers/go_dep.rb +80 -0
- data/lib/license_finder/package_managers/go_modules.rb +93 -0
- data/lib/license_finder/package_managers/go_workspace.rb +117 -0
- data/lib/license_finder/package_managers/govendor.rb +73 -0
- data/lib/license_finder/package_managers/gradle.rb +99 -0
- data/lib/license_finder/package_managers/gvt.rb +69 -0
- data/lib/license_finder/package_managers/maven.rb +69 -0
- data/lib/license_finder/package_managers/mix.rb +131 -0
- data/lib/license_finder/package_managers/npm.rb +70 -0
- data/lib/license_finder/package_managers/nuget.rb +159 -0
- data/lib/license_finder/package_managers/pip.rb +70 -0
- data/lib/license_finder/package_managers/pipenv.rb +63 -0
- data/lib/license_finder/package_managers/pnpm.rb +126 -0
- data/lib/license_finder/package_managers/pub.rb +86 -0
- data/lib/license_finder/package_managers/rebar.rb +65 -0
- data/lib/license_finder/package_managers/sbt.rb +46 -0
- data/lib/license_finder/package_managers/spm.rb +93 -0
- data/lib/license_finder/package_managers/trash.rb +43 -0
- data/lib/license_finder/package_managers/yarn.rb +195 -0
- data/lib/license_finder/package_utils/activation.rb +40 -0
- data/lib/license_finder/package_utils/conan_info_parser.rb +77 -0
- data/lib/license_finder/package_utils/conan_info_parser_v2.rb +82 -0
- data/lib/license_finder/package_utils/gradle_dependency_finder.rb +15 -0
- data/lib/license_finder/package_utils/license_files.rb +51 -0
- data/lib/license_finder/package_utils/licensing.rb +40 -0
- data/lib/license_finder/package_utils/maven_dependency_finder.rb +57 -0
- data/lib/license_finder/package_utils/notice_files.rb +51 -0
- data/lib/license_finder/package_utils/possible_license_file.rb +33 -0
- data/lib/license_finder/package_utils/pypi.rb +43 -0
- data/lib/license_finder/package_utils/sbt_dependency_finder.rb +15 -0
- data/lib/license_finder/packages/bower_package.rb +45 -0
- data/lib/license_finder/packages/bundler_package.rb +33 -0
- data/lib/license_finder/packages/cargo_package.rb +28 -0
- data/lib/license_finder/packages/carthage_package.rb +18 -0
- data/lib/license_finder/packages/cocoa_pods_package.rb +22 -0
- data/lib/license_finder/packages/composer_package.rb +13 -0
- data/lib/license_finder/packages/conan_package.rb +23 -0
- data/lib/license_finder/packages/conda_package.rb +74 -0
- data/lib/license_finder/packages/erlangmk_package.rb +112 -0
- data/lib/license_finder/packages/go_package.rb +30 -0
- data/lib/license_finder/packages/gradle_package.rb +30 -0
- data/lib/license_finder/packages/manual_package.rb +27 -0
- data/lib/license_finder/packages/maven_package.rb +39 -0
- data/lib/license_finder/packages/merged_package.rb +44 -0
- data/lib/license_finder/packages/mix_package.rb +13 -0
- data/lib/license_finder/packages/npm_package.rb +219 -0
- data/lib/license_finder/packages/nuget_package.rb +13 -0
- data/lib/license_finder/packages/pip_package.rb +50 -0
- data/lib/license_finder/packages/pnpm_package.rb +13 -0
- data/lib/license_finder/packages/pubspec_package.rb +18 -0
- data/lib/license_finder/packages/rebar_package.rb +13 -0
- data/lib/license_finder/packages/sbt_package.rb +22 -0
- data/lib/license_finder/packages/spm_package.rb +18 -0
- data/lib/license_finder/packages/yarn_package.rb +13 -0
- data/lib/license_finder/platform.rb +15 -0
- data/lib/license_finder/printer.rb +39 -0
- data/lib/license_finder/project_finder.rb +62 -0
- data/lib/license_finder/report.rb +34 -0
- data/lib/license_finder/reports/csv_report.rb +108 -0
- data/lib/license_finder/reports/diff_report.rb +29 -0
- data/lib/license_finder/reports/erb_report.rb +62 -0
- data/lib/license_finder/reports/html_report.rb +13 -0
- data/lib/license_finder/reports/json_report.rb +31 -0
- data/lib/license_finder/reports/junit_report.rb +23 -0
- data/lib/license_finder/reports/markdown_report.rb +9 -0
- data/lib/license_finder/reports/merged_report.rb +16 -0
- data/lib/license_finder/reports/templates/bootstrap.css +9 -0
- data/lib/license_finder/reports/templates/html_report.erb +113 -0
- data/lib/license_finder/reports/templates/junit_report.erb +41 -0
- data/lib/license_finder/reports/templates/markdown_report.erb +49 -0
- data/lib/license_finder/reports/templates/xml_report.erb +19 -0
- data/lib/license_finder/reports/text_report.rb +12 -0
- data/lib/license_finder/reports/xml_report.rb +23 -0
- data/lib/license_finder/scanner.rb +83 -0
- data/lib/license_finder/shared_helpers/cmd.rb +13 -0
- data/lib/license_finder/shared_helpers/common_path.rb +29 -0
- data/lib/license_finder/version.rb +6 -0
- data/lib/license_finder.rb +14 -0
- data/license_finder.gemspec +79 -0
- data/release/instructions.md +8 -0
- data/swift-all-keys.asc +240 -0
- metadata +604 -0
|
@@ -0,0 +1,219 @@
|
|
|
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] = package_for_dependency(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 = package_for_dependency(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
|
+
# Read the dependency's package.json file in order to get details like the license, authors,
|
|
43
|
+
# and so on. In NPM versions < 7, this information was included in the output of `npm list`.
|
|
44
|
+
# In later versions, it no longer is, and has to be read from the package.json file instead.
|
|
45
|
+
def package_for_dependency(npm_json)
|
|
46
|
+
package_path = npm_json['path']
|
|
47
|
+
package_json_path = Pathname.new(package_path).join('package.json') unless package_path.nil?
|
|
48
|
+
|
|
49
|
+
if package_json_path.nil? || !package_json_path.exist?
|
|
50
|
+
# Ancient NPM versions did not have the "path" field. Resort to the old way of gathering
|
|
51
|
+
# the details, expecting them to be contained in the output of `npm list`.
|
|
52
|
+
NpmPackage.new(npm_json)
|
|
53
|
+
else
|
|
54
|
+
package_json = JSON.parse(package_json_path.read, max_nesting: false)
|
|
55
|
+
NpmPackage.new(npm_json, package_json)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def populate_groups(package_json)
|
|
60
|
+
package_json.groups.each do |group|
|
|
61
|
+
group.package_names.each do |package_name|
|
|
62
|
+
@packages.each_key do |identifier|
|
|
63
|
+
next unless identifier.name == package_name
|
|
64
|
+
|
|
65
|
+
dependency = @packages[identifier]
|
|
66
|
+
dependency.groups |= [group.name]
|
|
67
|
+
populate_child_groups(dependency, @packages)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def populate_child_groups(dependency, packages, populated_ids = [])
|
|
74
|
+
dependency.dependencies.each do |id|
|
|
75
|
+
next if populated_ids.include? id
|
|
76
|
+
|
|
77
|
+
populated_ids.push id
|
|
78
|
+
packages[id].groups |= dependency.groups
|
|
79
|
+
populate_child_groups(packages[id], packages, populated_ids)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def initialize(npm_json, package_json = npm_json)
|
|
85
|
+
@npm_json = npm_json
|
|
86
|
+
@json = package_json
|
|
87
|
+
@identifier = Identifier.from_hash(npm_json)
|
|
88
|
+
@dependencies = deps_from_json
|
|
89
|
+
super(@identifier.name,
|
|
90
|
+
@identifier.version,
|
|
91
|
+
description: package_json['description'],
|
|
92
|
+
homepage: package_json['homepage'],
|
|
93
|
+
authors: author_names,
|
|
94
|
+
spec_licenses: Package.license_names_from_standard_spec(package_json),
|
|
95
|
+
install_path: npm_json['path'],
|
|
96
|
+
children: @dependencies.map(&:name))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def author_names
|
|
100
|
+
names = []
|
|
101
|
+
if @json['author'].is_a?(Array)
|
|
102
|
+
# "author":["foo","bar"] isn't valid according to the NPM package.json schema, but can be found in the wild.
|
|
103
|
+
names += @json['author'].map { |a| author_name(a) }
|
|
104
|
+
else
|
|
105
|
+
names << author_name(@json['author']) unless @json['author'].nil?
|
|
106
|
+
end
|
|
107
|
+
names += @json['contributors'].map { |c| author_name(c) } if @json['contributors'].is_a?(Array)
|
|
108
|
+
names.compact.join(', ')
|
|
109
|
+
rescue TypeError
|
|
110
|
+
puts "Warning: Invalid author and/or contributors metadata found in package.json for #{@identifier}"
|
|
111
|
+
nil
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def author_name(author)
|
|
115
|
+
if author.instance_of?(String)
|
|
116
|
+
author_name_from_combined(author)
|
|
117
|
+
else
|
|
118
|
+
author['name']
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def author_name_from_combined(author)
|
|
123
|
+
matches = author.match(/^(.*?)\s*(<.*?>)?\s*(\(.*?\))?\s*$/)
|
|
124
|
+
matches[1]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def ==(other)
|
|
128
|
+
other.is_a?(NpmPackage) && @identifier == other.identifier
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def to_s
|
|
132
|
+
@identifier.to_s
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def package_manager
|
|
136
|
+
'Npm'
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def package_url
|
|
140
|
+
"https://www.npmjs.com/package/#{CGI.escape(name)}/v/#{CGI.escape(version)}"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def deps_from_json
|
|
146
|
+
@npm_json.fetch('dependencies', {}).values.map { |dep| Identifier.from_hash(dep) }.compact
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
class Identifier
|
|
150
|
+
attr_accessor :name, :version
|
|
151
|
+
|
|
152
|
+
def initialize(name, version)
|
|
153
|
+
@name = name
|
|
154
|
+
@version = version
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def self.from_hash(hash)
|
|
158
|
+
name = hash['name']
|
|
159
|
+
version = hash['version']
|
|
160
|
+
return nil if name.nil? || name.empty? || version.nil? || version.empty?
|
|
161
|
+
|
|
162
|
+
Identifier.new(name, version)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def ==(other)
|
|
166
|
+
other.is_a?(Identifier) && @name == other.name && @version == other.version
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def eql?(other)
|
|
170
|
+
self == other
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def hash
|
|
174
|
+
[@name, @version].hash
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def <=>(other)
|
|
178
|
+
sort_name = @name <=> other.name
|
|
179
|
+
sort_name.zero? ? @version <=> other.version : sort_name
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def to_s
|
|
183
|
+
"#{@name} - #{@version}"
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
class Group
|
|
188
|
+
attr_accessor :name, :package_names
|
|
189
|
+
|
|
190
|
+
def initialize(name, hash)
|
|
191
|
+
@name = name
|
|
192
|
+
@package_names = hash.keys
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def include?(identifier)
|
|
196
|
+
@package_names.include? identifier.name
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def to_s
|
|
200
|
+
@name
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
class PackageJson
|
|
205
|
+
attr_reader :groups
|
|
206
|
+
|
|
207
|
+
DEPENDENCY_GROUPS = %w[dependencies devDependencies].freeze
|
|
208
|
+
|
|
209
|
+
def initialize(path)
|
|
210
|
+
json = JSON.parse(File.read(path), max_nesting: false)
|
|
211
|
+
@groups = DEPENDENCY_GROUPS.map { |name| Group.new(name, json.fetch(name, {})) }
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def groups_for(identifier)
|
|
215
|
+
@groups.select { |g| g.include? identifier }.map(&:name)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
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,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LicenseFinder
|
|
4
|
+
class PubPackage < 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
|
+
'Pub'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
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,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,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LicenseFinder
|
|
4
|
+
class Printer
|
|
5
|
+
attr_reader :padding
|
|
6
|
+
|
|
7
|
+
def initialize # :nodoc:
|
|
8
|
+
@base = nil
|
|
9
|
+
@mute = false
|
|
10
|
+
@padding = 0
|
|
11
|
+
@always_force = false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def say(message = '', color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
|
|
15
|
+
buffer = prepare_message(message, *color)
|
|
16
|
+
buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
|
|
17
|
+
|
|
18
|
+
stdout.print(buffer)
|
|
19
|
+
stdout.flush
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def prepare_message(message, *color)
|
|
23
|
+
spaces = ' ' * padding
|
|
24
|
+
spaces + set_color(message.to_s, *color)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def set_color(string, *) # :nodoc:
|
|
28
|
+
string
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def padding=(value)
|
|
32
|
+
@padding = [0, value].max
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def stdout
|
|
36
|
+
$stdout
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
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,34 @@
|
|
|
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
|
+
@use_spdx_id = options[:use_spdx_id]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
attr_reader :dependencies, :project_name, :use_spdx_id
|
|
18
|
+
|
|
19
|
+
def sorted_dependencies
|
|
20
|
+
dependencies.sort
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
require 'license_finder/reports/erb_report'
|
|
26
|
+
require 'license_finder/reports/csv_report'
|
|
27
|
+
require 'license_finder/reports/text_report'
|
|
28
|
+
require 'license_finder/reports/diff_report'
|
|
29
|
+
require 'license_finder/reports/merged_report'
|
|
30
|
+
require 'license_finder/reports/html_report'
|
|
31
|
+
require 'license_finder/reports/markdown_report'
|
|
32
|
+
require 'license_finder/reports/xml_report'
|
|
33
|
+
require 'license_finder/reports/json_report'
|
|
34
|
+
require 'license_finder/reports/junit_report'
|
|
@@ -0,0 +1,108 @@
|
|
|
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 approved_by approved_reason].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(&@use_spdx_id ? :standard_id : :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
|
+
|
|
99
|
+
def format_approved_by(dep)
|
|
100
|
+
dep.approved_manually? ? dep.manual_approval.who : ''
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def format_approved_reason(dep)
|
|
104
|
+
dep.approved_manually? ? dep.manual_approval.why : ''
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module LicenseFinder
|
|
2
|
+
class DiffReport < CsvReport
|
|
3
|
+
AVAILABLE_COLUMNS = AVAILABLE_COLUMNS + %w[status current_version previous_version project_paths]
|
|
4
|
+
|
|
5
|
+
def initialize(dependencies, options = {})
|
|
6
|
+
super(dependencies, options.merge(columns: build_columns(dependencies)))
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def format_status(dep)
|
|
10
|
+
dep.status
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def format_version(dep)
|
|
14
|
+
dep.version
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def format_project_paths(dep)
|
|
18
|
+
dep.aggregate_paths.join(self.class::COMMA_SEP)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def build_columns(dependencies)
|
|
24
|
+
columns = %w[status name version licenses]
|
|
25
|
+
columns << 'project_paths' if dependencies.all?(&:merged_package?)
|
|
26
|
+
columns
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|