license_finder 7.0.0 → 7.1.0
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 +4 -4
- data/.github/dependabot.yml +7 -0
- data/.pre-commit-hooks.yaml +10 -0
- data/CHANGELOG.md +41 -9
- data/CONTRIBUTING.md +1 -0
- data/Dockerfile +69 -52
- data/README.md +72 -29
- data/VERSION +1 -1
- data/dlf +6 -1
- data/lib/license_finder/cli/base.rb +2 -0
- data/lib/license_finder/cli/licenses.rb +8 -3
- data/lib/license_finder/cli/main.rb +3 -1
- data/lib/license_finder/configuration.rb +8 -0
- data/lib/license_finder/core.rb +2 -0
- data/lib/license_finder/decision_applier.rb +1 -1
- data/lib/license_finder/decisions.rb +24 -6
- data/lib/license_finder/license/definitions.rb +2 -0
- data/lib/license_finder/license/templates/Apache2.txt +0 -2
- data/lib/license_finder/manual_licenses.rb +79 -0
- data/lib/license_finder/package.rb +1 -0
- data/lib/license_finder/package_manager.rb +1 -0
- data/lib/license_finder/package_managers/dotnet.rb +5 -2
- data/lib/license_finder/package_managers/maven.rb +2 -6
- data/lib/license_finder/package_managers/nuget.rb +5 -0
- data/lib/license_finder/package_managers/pnpm.rb +120 -0
- data/lib/license_finder/package_managers/yarn.rb +91 -31
- data/lib/license_finder/package_utils/pypi.rb +3 -1
- data/lib/license_finder/packages/npm_package.rb +21 -0
- data/lib/license_finder/packages/pnpm_package.rb +13 -0
- data/lib/license_finder/reports/csv_report.rb +10 -1
- data/lib/license_finder/scanner.rb +1 -1
- data/license_finder.gemspec +4 -4
- metadata +19 -15
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'open-uri'
|
4
4
|
require 'license_finder/license'
|
5
|
+
require 'license_finder/manual_licenses'
|
5
6
|
|
6
7
|
module LicenseFinder
|
7
8
|
class Decisions
|
@@ -11,8 +12,8 @@ module LicenseFinder
|
|
11
12
|
|
12
13
|
attr_reader :packages, :permitted, :restricted, :ignored, :ignored_groups, :project_name, :inherited_decisions
|
13
14
|
|
14
|
-
def licenses_of(name)
|
15
|
-
@
|
15
|
+
def licenses_of(name, version = nil)
|
16
|
+
@manual_licenses.licenses_of(name, version)
|
16
17
|
end
|
17
18
|
|
18
19
|
def homepage_of(name)
|
@@ -76,7 +77,7 @@ module LicenseFinder
|
|
76
77
|
def initialize
|
77
78
|
@decisions = []
|
78
79
|
@packages = Set.new
|
79
|
-
@
|
80
|
+
@manual_licenses = ManualLicenses.new
|
80
81
|
@homepages = {}
|
81
82
|
@approvals = {}
|
82
83
|
@permitted = Set.new
|
@@ -100,13 +101,29 @@ module LicenseFinder
|
|
100
101
|
|
101
102
|
def license(name, lic, txn = {})
|
102
103
|
add_decision [:license, name, lic, txn]
|
103
|
-
|
104
|
+
|
105
|
+
versions = txn[:versions]
|
106
|
+
|
107
|
+
if versions.nil? || versions.empty?
|
108
|
+
@manual_licenses.assign_to_all_versions(name, lic)
|
109
|
+
else
|
110
|
+
@manual_licenses.assign_to_specific_versions(name, lic, versions)
|
111
|
+
end
|
112
|
+
|
104
113
|
self
|
105
114
|
end
|
106
115
|
|
107
116
|
def unlicense(name, lic, txn = {})
|
108
117
|
add_decision [:unlicense, name, lic, txn]
|
109
|
-
|
118
|
+
|
119
|
+
versions = txn[:versions]
|
120
|
+
|
121
|
+
if versions.nil? || versions.empty?
|
122
|
+
@manual_licenses.unassign_from_all_versions(name, lic)
|
123
|
+
else
|
124
|
+
@manual_licenses.unassign_from_specific_versions(name, lic, versions)
|
125
|
+
end
|
126
|
+
|
110
127
|
self
|
111
128
|
end
|
112
129
|
|
@@ -235,9 +252,10 @@ module LicenseFinder
|
|
235
252
|
end
|
236
253
|
|
237
254
|
def restore_inheritance(decisions)
|
255
|
+
previous_value = @inherited
|
238
256
|
@inherited = true
|
239
257
|
self.class.restore(decisions, self)
|
240
|
-
@inherited =
|
258
|
+
@inherited = previous_value
|
241
259
|
self
|
242
260
|
end
|
243
261
|
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LicenseFinder
|
4
|
+
class ManualLicenses
|
5
|
+
def initialize
|
6
|
+
@all_versions = {}
|
7
|
+
@specific_versions = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def licenses_of(name, version = nil)
|
11
|
+
return @all_versions[name] if @all_versions[name]
|
12
|
+
|
13
|
+
if version && @specific_versions[name] && @specific_versions[name][version]
|
14
|
+
@specific_versions[name][version]
|
15
|
+
else
|
16
|
+
Set.new
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def assign_to_all_versions(name, lic)
|
21
|
+
# Ex: licenses add foo_gem MIT => Adds MIT at "all" versions for this gem
|
22
|
+
|
23
|
+
@all_versions[name] ||= Set.new
|
24
|
+
@all_versions[name] << to_license(lic)
|
25
|
+
|
26
|
+
@specific_versions.delete(name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def assign_to_specific_versions(name, lic, versions)
|
30
|
+
# Ex: licenses add foo_gem MIT --version=1.0 => Adds MIT at only 1.0 for this gem
|
31
|
+
|
32
|
+
@specific_versions[name] ||= {}
|
33
|
+
versions.each do |version|
|
34
|
+
@specific_versions[name][version] ||= Set.new
|
35
|
+
@specific_versions[name][version] << to_license(lic)
|
36
|
+
end
|
37
|
+
|
38
|
+
@all_versions.delete(name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def unassign_from_all_versions(name, lic = nil)
|
42
|
+
if lic
|
43
|
+
# Ex: licenses remove foo_gem MIT => Removes MIT at all versions for this gem
|
44
|
+
@all_versions[name]&.delete(to_license(lic))
|
45
|
+
|
46
|
+
@specific_versions[name]&.each do |_version, licenses|
|
47
|
+
licenses.delete(to_license(lic))
|
48
|
+
end
|
49
|
+
else
|
50
|
+
# Ex: licenses remove foo_gem => Removes all licenses for all versions of the gem
|
51
|
+
@all_versions.delete(name)
|
52
|
+
@specific_versions.delete(name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def unassign_from_specific_versions(name, lic, versions)
|
57
|
+
return unless @specific_versions[name]
|
58
|
+
|
59
|
+
versions.each do |version|
|
60
|
+
if @specific_versions[name][version]
|
61
|
+
if lic
|
62
|
+
# Ex: licenses remove foo_gem MIT --version=1.0 => Removes MIT at only 1.0 for this gem
|
63
|
+
@specific_versions[name][version].delete(to_license(lic))
|
64
|
+
@specific_versions[name].delete(version) if @specific_versions[name][version].empty?
|
65
|
+
else
|
66
|
+
# Ex: licenses remove foo_gem --version=1.0 => Removes all licenses at only 1.0 for the gem
|
67
|
+
@specific_versions[name].delete(version)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def to_license(lic)
|
76
|
+
License.find_by_name(lic)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -187,6 +187,7 @@ require 'license_finder/packages/merged_package'
|
|
187
187
|
require 'license_finder/packages/nuget_package'
|
188
188
|
require 'license_finder/packages/conan_package'
|
189
189
|
require 'license_finder/packages/yarn_package'
|
190
|
+
require 'license_finder/packages/pnpm_package'
|
190
191
|
require 'license_finder/packages/sbt_package'
|
191
192
|
require 'license_finder/packages/cargo_package'
|
192
193
|
require 'license_finder/packages/composer_package'
|
@@ -158,6 +158,7 @@ require 'license_finder/package_managers/go_modules'
|
|
158
158
|
require 'license_finder/package_managers/trash'
|
159
159
|
require 'license_finder/package_managers/bundler'
|
160
160
|
require 'license_finder/package_managers/npm'
|
161
|
+
require 'license_finder/package_managers/pnpm'
|
161
162
|
require 'license_finder/package_managers/yarn'
|
162
163
|
require 'license_finder/package_managers/pip'
|
163
164
|
require 'license_finder/package_managers/pipenv'
|
@@ -42,9 +42,13 @@ module LicenseFinder
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def read_license_urls
|
45
|
-
possible_spec_paths.flat_map do |path|
|
45
|
+
raw_licenses = possible_spec_paths.flat_map do |path|
|
46
46
|
Nuget.nuspec_license_urls(File.read(path)) if File.exist? path
|
47
47
|
end.compact
|
48
|
+
|
49
|
+
raw_licenses&.map! do |license|
|
50
|
+
license.gsub('https://licenses.nuget.org/', '')
|
51
|
+
end
|
48
52
|
end
|
49
53
|
|
50
54
|
def ==(other)
|
@@ -61,7 +65,6 @@ module LicenseFinder
|
|
61
65
|
package_metadatas = asset_files
|
62
66
|
.flat_map { |path| AssetFile.new(path).dependencies }
|
63
67
|
.uniq { |d| [d.name, d.version] }
|
64
|
-
|
65
68
|
package_metadatas.map do |d|
|
66
69
|
path = Dir.glob("#{Dir.home}/.nuget/packages/#{d.name.downcase}/#{d.version}").first
|
67
70
|
NugetPackage.new(d.name, d.version, spec_licenses: d.read_license_urls, install_path: path)
|
@@ -34,14 +34,10 @@ module LicenseFinder
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def package_management_command
|
37
|
-
wrapper =
|
38
|
-
'mvnw.cmd'
|
39
|
-
else
|
40
|
-
'./mvnw'
|
41
|
-
end
|
37
|
+
wrapper = File.join(project_path, Platform.windows? ? 'mvnw.cmd' : 'mvnw')
|
42
38
|
maven = 'mvn'
|
43
39
|
|
44
|
-
File.exist?(
|
40
|
+
File.exist?(wrapper) ? wrapper : maven
|
45
41
|
end
|
46
42
|
|
47
43
|
def possible_package_paths
|
@@ -51,6 +51,10 @@ module LicenseFinder
|
|
51
51
|
def current_packages
|
52
52
|
dependencies.each_with_object({}) do |dep, memo|
|
53
53
|
licenses = license_urls(dep)
|
54
|
+
licenses&.map! do |license|
|
55
|
+
license.gsub('https://licenses.nuget.org/', '')
|
56
|
+
end
|
57
|
+
|
54
58
|
path = Dir.glob("#{Dir.home}/.nuget/packages/#{dep.name.downcase}/#{dep.version}").first
|
55
59
|
|
56
60
|
memo[dep.name] ||= NugetPackage.new(dep.name, dep.version, spec_licenses: licenses, install_path: path)
|
@@ -60,6 +64,7 @@ module LicenseFinder
|
|
60
64
|
|
61
65
|
def license_urls(dep)
|
62
66
|
files = Dir["**/#{dep.name}.#{dep.version}.nupkg"]
|
67
|
+
|
63
68
|
return nil if files.empty?
|
64
69
|
|
65
70
|
file = files.first
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
module LicenseFinder
|
7
|
+
class PNPM < PackageManager
|
8
|
+
def initialize(options = {})
|
9
|
+
super
|
10
|
+
@pnpm_options = options[:pnpm_options]
|
11
|
+
end
|
12
|
+
|
13
|
+
SHELL_COMMAND = 'pnpm licenses list --json --long'
|
14
|
+
|
15
|
+
def possible_package_paths
|
16
|
+
[project_path.join('pnpm-lock.yaml')]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.takes_priority_over
|
20
|
+
NPM
|
21
|
+
end
|
22
|
+
|
23
|
+
def current_packages
|
24
|
+
# check if the minimum version of PNPM is met
|
25
|
+
raise 'The minimum PNPM version is not met, requires 7.17.0 or later' unless supported_pnpm?
|
26
|
+
|
27
|
+
# check if the project directory has workspace file
|
28
|
+
cmd = PNPM::SHELL_COMMAND.to_s
|
29
|
+
cmd += ' --no-color'
|
30
|
+
cmd += ' --recursive' unless project_has_workspaces == false
|
31
|
+
cmd += " --dir #{project_path}" unless project_path.nil?
|
32
|
+
cmd += " #{@pnpm_options}" unless @pnpm_options.nil?
|
33
|
+
|
34
|
+
stdout, stderr, status = Cmd.run(cmd)
|
35
|
+
raise "Command '#{cmd}' failed to execute: #{stderr}" unless status.success?
|
36
|
+
|
37
|
+
json_objects = JSON.parse(stdout)
|
38
|
+
get_pnpm_packages(json_objects)
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_pnpm_packages(json_objects)
|
42
|
+
packages = []
|
43
|
+
incompatible_packages = []
|
44
|
+
|
45
|
+
json_objects.map do |_, value|
|
46
|
+
value.each do |pkg|
|
47
|
+
name = pkg['name']
|
48
|
+
version = pkg['version']
|
49
|
+
license = pkg['license']
|
50
|
+
homepage = pkg['vendorUrl']
|
51
|
+
author = pkg['vendorName']
|
52
|
+
module_path = pkg['path']
|
53
|
+
|
54
|
+
package = PNPMPackage.new(
|
55
|
+
name,
|
56
|
+
version,
|
57
|
+
spec_licenses: [license],
|
58
|
+
homepage: homepage,
|
59
|
+
authors: author,
|
60
|
+
install_path: module_path
|
61
|
+
)
|
62
|
+
packages << package
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
packages + incompatible_packages.uniq
|
67
|
+
end
|
68
|
+
|
69
|
+
def package_management_command
|
70
|
+
'pnpm'
|
71
|
+
end
|
72
|
+
|
73
|
+
def prepare_command
|
74
|
+
'pnpm install --no-lockfile --ignore-scripts'
|
75
|
+
end
|
76
|
+
|
77
|
+
def prepare
|
78
|
+
prep_cmd = "#{prepare_command}#{production_flag}"
|
79
|
+
_stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(prep_cmd) }
|
80
|
+
|
81
|
+
return if status.success?
|
82
|
+
|
83
|
+
log_errors stderr
|
84
|
+
raise "Prepare command '#{prep_cmd}' failed" unless @prepare_no_fail
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def project_has_workspaces
|
90
|
+
Dir.chdir(project_path) do
|
91
|
+
return File.file?('pnpm-workspace.yaml')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# PNPM introduced the licenses command in 7.17.0
|
96
|
+
def supported_pnpm?
|
97
|
+
Dir.chdir(project_path) do
|
98
|
+
version_string, stderr_str, status = Cmd.run('pnpm --version')
|
99
|
+
raise "Command 'pnpm -v' failed to execute: #{stderr_str}" unless status.success?
|
100
|
+
|
101
|
+
version = version_string.split('.').map(&:to_i)
|
102
|
+
major = version[0]
|
103
|
+
minor = version[1]
|
104
|
+
patch = version[1]
|
105
|
+
|
106
|
+
return true if major > 7
|
107
|
+
return true if major == 7 && minor > 17
|
108
|
+
return true if major == 7 && minor == 17 && patch >= 0
|
109
|
+
|
110
|
+
return false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def production_flag
|
115
|
+
return '' if @ignored_groups.nil?
|
116
|
+
|
117
|
+
@ignored_groups.include?('devDependencies') ? ' --prod' : ''
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -2,40 +2,37 @@
|
|
2
2
|
|
3
3
|
module LicenseFinder
|
4
4
|
class Yarn < PackageManager
|
5
|
-
|
5
|
+
def initialize(options = {})
|
6
|
+
super
|
7
|
+
@yarn_options = options[:yarn_options]
|
8
|
+
end
|
9
|
+
|
10
|
+
SHELL_COMMAND = 'yarn licenses list --recursive --json'
|
6
11
|
|
7
12
|
def possible_package_paths
|
8
13
|
[project_path.join('yarn.lock')]
|
9
14
|
end
|
10
15
|
|
11
16
|
def current_packages
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
# the licenses plugin supports the classic production flag
|
18
|
+
cmd = "#{Yarn::SHELL_COMMAND}#{classic_yarn_production_flag}"
|
19
|
+
if yarn_version == 1
|
20
|
+
cmd += ' --no-progress'
|
21
|
+
cmd += " --cwd #{project_path}" unless project_path.nil?
|
22
|
+
cmd += " #{@yarn_options}" unless @yarn_options.nil?
|
23
|
+
end
|
15
24
|
|
16
25
|
stdout, stderr, status = Cmd.run(cmd)
|
17
26
|
raise "Command '#{cmd}' failed to execute: #{stderr}" unless status.success?
|
18
27
|
|
19
|
-
packages = []
|
20
|
-
incompatible_packages = []
|
21
|
-
|
22
28
|
json_strings = stdout.encode('ASCII', invalid: :replace, undef: :replace, replace: '?').split("\n")
|
23
29
|
json_objects = json_strings.map { |json_object| JSON.parse(json_object) }
|
24
30
|
|
25
|
-
if
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
json_objects.each do |json_object|
|
31
|
-
match = /(?<name>[\w,\-]+)@(?<version>(\d+\.?)+)/ =~ json_object['data'].to_s
|
32
|
-
if match
|
33
|
-
package = YarnPackage.new(name, version, spec_licenses: ['unknown'])
|
34
|
-
incompatible_packages.push(package)
|
35
|
-
end
|
31
|
+
if yarn_version == 1
|
32
|
+
get_yarn1_packages(json_objects)
|
33
|
+
else
|
34
|
+
get_yarn_packages(json_objects)
|
36
35
|
end
|
37
|
-
|
38
|
-
packages + incompatible_packages.uniq
|
39
36
|
end
|
40
37
|
|
41
38
|
def prepare
|
@@ -56,33 +53,96 @@ module LicenseFinder
|
|
56
53
|
end
|
57
54
|
|
58
55
|
def prepare_command
|
59
|
-
if
|
60
|
-
|
56
|
+
if yarn_version == 1
|
57
|
+
classic_yarn_prepare_command
|
61
58
|
else
|
62
|
-
|
59
|
+
yarn_prepare_command
|
63
60
|
end
|
64
61
|
end
|
65
62
|
|
66
63
|
private
|
67
64
|
|
68
|
-
def
|
69
|
-
"#{
|
65
|
+
def yarn_prepare_command
|
66
|
+
"#{yarn_plugin_production_command}yarn install && yarn plugin import https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/#{yarn_licenses_plugin_version}/bundles/@yarnpkg/plugin-licenses.js"
|
70
67
|
end
|
71
68
|
|
72
|
-
def
|
73
|
-
"yarn install --ignore-engines --ignore-scripts#{
|
69
|
+
def classic_yarn_prepare_command
|
70
|
+
"yarn install --ignore-engines --ignore-scripts#{classic_yarn_production_flag}"
|
74
71
|
end
|
75
72
|
|
76
|
-
def
|
73
|
+
def yarn_licenses_plugin_version
|
74
|
+
if yarn_version == 2
|
75
|
+
'v0.6.0'
|
76
|
+
else
|
77
|
+
'v0.7.2'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def yarn_version
|
77
82
|
Dir.chdir(project_path) do
|
78
83
|
version_string, stderr_str, status = Cmd.run('yarn -v')
|
79
84
|
raise "Command 'yarn -v' failed to execute: #{stderr_str}" unless status.success?
|
80
85
|
|
81
86
|
version = version_string.split('.').map(&:to_i)
|
82
|
-
return version[0]
|
87
|
+
return version[0]
|
83
88
|
end
|
84
89
|
end
|
85
90
|
|
91
|
+
def get_yarn_packages(json_objects)
|
92
|
+
packages = []
|
93
|
+
incompatible_packages = []
|
94
|
+
json_objects.each do |json_object|
|
95
|
+
license = json_object['value']
|
96
|
+
body = json_object['children']
|
97
|
+
|
98
|
+
body.each do |package_name, vendor_info|
|
99
|
+
valid_match = %r{(?<name>[@,\w,\-,/,.]+)@(?<manager>\D*):\D*(?<version>(\d+\.?)+)} =~ package_name.to_s
|
100
|
+
valid_match = %r{(?<name>[@,\w,\-,/,.]+)@virtual:.+#(\D*):\D*(?<version>(\d+\.?)+)} =~ package_name.to_s if manager.eql?('virtual')
|
101
|
+
|
102
|
+
if valid_match
|
103
|
+
homepage = vendor_info['children']['vendorUrl']
|
104
|
+
author = vendor_info['children']['vendorName']
|
105
|
+
package = YarnPackage.new(
|
106
|
+
name,
|
107
|
+
version,
|
108
|
+
spec_licenses: [license],
|
109
|
+
homepage: homepage,
|
110
|
+
authors: author,
|
111
|
+
install_path: project_path.join(modules_folder, name)
|
112
|
+
)
|
113
|
+
packages << package
|
114
|
+
end
|
115
|
+
incompatible_match = /(?<name>[\w,\-]+)@[a-z]*:(?<version>(\.))/ =~ package_name.to_s
|
116
|
+
|
117
|
+
if incompatible_match
|
118
|
+
package = YarnPackage.new(name, version, spec_licenses: ['unknown'])
|
119
|
+
incompatible_packages.push(package)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
packages + incompatible_packages.uniq
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_yarn1_packages(json_objects)
|
128
|
+
packages = []
|
129
|
+
incompatible_packages = []
|
130
|
+
if json_objects.last['type'] == 'table'
|
131
|
+
license_json = json_objects.pop['data']
|
132
|
+
packages = packages_from_json(license_json)
|
133
|
+
end
|
134
|
+
|
135
|
+
json_objects.each do |json_object|
|
136
|
+
match = /(?<name>[\w,\-]+)@(?<version>(\d+\.?)+)/ =~ json_object['data'].to_s
|
137
|
+
if match
|
138
|
+
package = YarnPackage.new(name, version, spec_licenses: ['unknown'])
|
139
|
+
incompatible_packages.push(package)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
packages + incompatible_packages.uniq
|
144
|
+
end
|
145
|
+
|
86
146
|
def packages_from_json(json_data)
|
87
147
|
body = json_data['body']
|
88
148
|
head = json_data['head']
|
@@ -120,13 +180,13 @@ module LicenseFinder
|
|
120
180
|
all_packages - [yarn_internal_package]
|
121
181
|
end
|
122
182
|
|
123
|
-
def
|
183
|
+
def classic_yarn_production_flag
|
124
184
|
return '' if @ignored_groups.nil?
|
125
185
|
|
126
186
|
@ignored_groups.include?('devDependencies') ? ' --production' : ''
|
127
187
|
end
|
128
188
|
|
129
|
-
def
|
189
|
+
def yarn_plugin_production_command
|
130
190
|
return '' if @ignored_groups.nil?
|
131
191
|
|
132
192
|
@ignored_groups.include?('devDependencies') ? 'yarn plugin import workspace-tools && yarn workspaces focus --all --production && ' : ''
|
@@ -25,7 +25,9 @@ module LicenseFinder
|
|
25
25
|
def definition(name, version)
|
26
26
|
response = request("https://pypi.org/pypi/#{name}/#{version}/json")
|
27
27
|
response.is_a?(Net::HTTPSuccess) ? JSON.parse(response.body).fetch('info', {}) : {}
|
28
|
-
rescue *CONNECTION_ERRORS
|
28
|
+
rescue *CONNECTION_ERRORS => e
|
29
|
+
raise e, "Unable to read package from pypi.org #{name} #{version}: #{e}" unless @prepare_no_fail
|
30
|
+
|
29
31
|
{}
|
30
32
|
end
|
31
33
|
|
@@ -72,11 +72,32 @@ module LicenseFinder
|
|
72
72
|
@identifier.version,
|
73
73
|
description: npm_json['description'],
|
74
74
|
homepage: npm_json['homepage'],
|
75
|
+
authors: author_names,
|
75
76
|
spec_licenses: Package.license_names_from_standard_spec(npm_json),
|
76
77
|
install_path: npm_json['path'],
|
77
78
|
children: @dependencies.map(&:name))
|
78
79
|
end
|
79
80
|
|
81
|
+
def author_names
|
82
|
+
names = []
|
83
|
+
names.push(author_name(@json['author'])) unless @json['author'].nil?
|
84
|
+
names += @json['contributors'].map { |c| author_name(c) } if @json['contributors'].is_a?(Array)
|
85
|
+
names.join(', ')
|
86
|
+
end
|
87
|
+
|
88
|
+
def author_name(author)
|
89
|
+
if author.instance_of?(String)
|
90
|
+
author_name_from_combined(author)
|
91
|
+
else
|
92
|
+
author['name']
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def author_name_from_combined(author)
|
97
|
+
matches = author.match /^(.*?)\s*(<.*?>)?\s*(\(.*?\))?\s*$/
|
98
|
+
matches[1]
|
99
|
+
end
|
100
|
+
|
80
101
|
def ==(other)
|
81
102
|
other.is_a?(NpmPackage) && @identifier == other.identifier
|
82
103
|
end
|
@@ -4,7 +4,7 @@ module LicenseFinder
|
|
4
4
|
class CsvReport < Report
|
5
5
|
COMMA_SEP = ','.freeze
|
6
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
|
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
8
|
MISSING_DEPENDENCY_TEXT = 'This package is not installed. Please install to determine licenses.'.freeze
|
9
9
|
|
10
10
|
def initialize(dependencies, options)
|
@@ -95,5 +95,14 @@ module LicenseFinder
|
|
95
95
|
dep.groups.join(self.class::COMMA_SEP)
|
96
96
|
end
|
97
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
|
+
|
98
107
|
end
|
99
108
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module LicenseFinder
|
4
4
|
class Scanner
|
5
5
|
PACKAGE_MANAGERS = [
|
6
|
-
GoModules, GoDep, GoWorkspace, Go15VendorExperiment, Glide, Gvt, Govendor, Trash, Dep, Bundler, NPM, Pip,
|
6
|
+
GoModules, GoDep, GoWorkspace, Go15VendorExperiment, Glide, Gvt, Govendor, Trash, Dep, Bundler, NPM, PNPM, Pip,
|
7
7
|
Yarn, Bower, Maven, Gradle, CocoaPods, Rebar, Erlangmk, Nuget, Carthage, Mix, Conan, Sbt, Cargo, Dotnet, Composer, Pipenv,
|
8
8
|
Conda, Spm, Pub
|
9
9
|
].freeze
|
data/license_finder.gemspec
CHANGED
@@ -50,11 +50,11 @@ Gem::Specification.new do |s|
|
|
50
50
|
s.add_dependency 'with_env', '1.1.0'
|
51
51
|
s.add_dependency 'xml-simple', '~> 1.1.9'
|
52
52
|
|
53
|
-
s.add_development_dependency 'addressable', '2.8.
|
53
|
+
s.add_development_dependency 'addressable', '2.8.1'
|
54
54
|
s.add_development_dependency 'capybara', '~> 3.32.2'
|
55
55
|
s.add_development_dependency 'cocoapods', '>= 1.0.0' if RUBY_PLATFORM.match?(/darwin/)
|
56
56
|
s.add_development_dependency 'e2mmap', '~> 0.1.0'
|
57
|
-
s.add_development_dependency 'fakefs', '~> 1.
|
57
|
+
s.add_development_dependency 'fakefs', '~> 1.8.0'
|
58
58
|
s.add_development_dependency 'matrix', '~> 0.1.0'
|
59
59
|
s.add_development_dependency 'mime-types', '3.4.1'
|
60
60
|
s.add_development_dependency 'pry', '~> 0.14.1'
|
@@ -66,8 +66,8 @@ Gem::Specification.new do |s|
|
|
66
66
|
s.add_development_dependency 'webmock', '~> 3.14'
|
67
67
|
|
68
68
|
s.add_development_dependency 'nokogiri', '~>1.10'
|
69
|
-
s.add_development_dependency 'rack', '~>
|
70
|
-
s.add_development_dependency 'rack-test', '
|
69
|
+
s.add_development_dependency 'rack', '~> 3.0.0'
|
70
|
+
s.add_development_dependency 'rack-test', '> 0.7', '~> 2.0.2'
|
71
71
|
|
72
72
|
s.files = `git ls-files`.split("\n").reject { |f| f.start_with?('spec', 'features') }
|
73
73
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|