license_finder 6.1.2 → 6.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/CHANGELOG.md +64 -0
- data/Dockerfile +23 -15
- data/README.md +24 -2
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/ci/pipelines/release.yml.erb +8 -19
- data/ci/scripts/pushscript.sh +1 -1
- data/ci/scripts/updateChangelog.sh +8 -1
- data/ci/tasks/build-and-push-gem.yml +2 -2
- data/ci/tasks/rubocop.yml +1 -1
- data/ci/tasks/update-changelog.yml +2 -2
- data/lib/license_finder/cli.rb +1 -0
- data/lib/license_finder/cli/base.rb +1 -0
- data/lib/license_finder/cli/inherited_decisions.rb +32 -0
- data/lib/license_finder/cli/main.rb +3 -1
- data/lib/license_finder/configuration.rb +4 -0
- data/lib/license_finder/decision_applier.rb +8 -4
- data/lib/license_finder/decisions.rb +63 -20
- data/lib/license_finder/license/definitions.rb +48 -1
- data/lib/license_finder/license/templates/0BSD.txt +10 -0
- data/lib/license_finder/license/templates/OFL.txt +91 -0
- data/lib/license_finder/license/templates/SimplifiedBSD.txt +0 -4
- data/lib/license_finder/license/templates/WTFPL.txt +14 -0
- data/lib/license_finder/license/text.rb +24 -2
- data/lib/license_finder/logger.rb +2 -0
- data/lib/license_finder/package.rb +2 -1
- data/lib/license_finder/package_manager.rb +6 -2
- data/lib/license_finder/package_managers/bundler.rb +5 -3
- data/lib/license_finder/package_managers/cargo.rb +2 -1
- data/lib/license_finder/package_managers/composer.rb +5 -1
- data/lib/license_finder/package_managers/dep.rb +2 -2
- data/lib/license_finder/package_managers/dotnet.rb +2 -1
- data/lib/license_finder/package_managers/glide.rb +2 -7
- data/lib/license_finder/package_managers/go_15vendorexperiment.rb +1 -1
- data/lib/license_finder/package_managers/go_modules.rb +11 -4
- data/lib/license_finder/package_managers/go_workspace.rb +5 -1
- data/lib/license_finder/package_managers/nuget.rb +37 -3
- data/lib/license_finder/package_managers/pipenv.rb +1 -1
- data/lib/license_finder/package_managers/sbt.rb +3 -1
- data/lib/license_finder/package_managers/yarn.rb +16 -2
- data/lib/license_finder/package_utils/license_files.rb +2 -2
- data/lib/license_finder/packages/bower_package.rb +7 -0
- data/lib/license_finder/packages/bundler_package.rb +4 -0
- data/lib/license_finder/packages/cargo_package.rb +4 -0
- data/lib/license_finder/packages/cocoa_pods_package.rb +4 -0
- data/lib/license_finder/packages/composer_package.rb +4 -0
- data/lib/license_finder/packages/conan_package.rb +4 -0
- data/lib/license_finder/packages/go_package.rb +5 -1
- data/lib/license_finder/packages/gradle_package.rb +4 -0
- data/lib/license_finder/packages/maven_package.rb +6 -1
- data/lib/license_finder/packages/merged_package.rb +1 -1
- data/lib/license_finder/packages/mix_package.rb +4 -0
- data/lib/license_finder/packages/npm_package.rb +4 -0
- data/lib/license_finder/packages/nuget_package.rb +4 -0
- data/lib/license_finder/packages/pip_package.rb +4 -0
- data/lib/license_finder/packages/rebar_package.rb +4 -0
- data/lib/license_finder/packages/yarn_package.rb +4 -0
- data/lib/license_finder/reports/csv_report.rb +7 -3
- data/lib/license_finder/reports/json_report.rb +2 -0
- data/license_finder.gemspec +5 -5
- metadata +20 -22
@@ -6,15 +6,37 @@ module LicenseFinder
|
|
6
6
|
SPACES = /\s+/.freeze
|
7
7
|
QUOTES = /['`"]{1,2}/.freeze
|
8
8
|
PLACEHOLDERS = /<[^<>]+>/.freeze
|
9
|
+
SPECIAL_SINGLE_QUOTES = /[‘’]/.freeze
|
10
|
+
SPECIAL_DOUBLE_QUOTES = /[“”„«»]/.freeze
|
11
|
+
ALPHABET_ORDERED_LIST = /\\\([a-z]\\\)\\\s/.freeze
|
12
|
+
ALPHABET_ORDERED_LIST_OPTIONAL = '(\([a-z]\)\s)?'
|
13
|
+
LIST_BULLETS = /(\d{1,2}\\\.|\\\*)\\\s/.freeze
|
14
|
+
LIST_BULLETS_OPTIONAL = '(\d{1,2}.|\*)?\s*'
|
15
|
+
NEWLINE_CHARACTER = /\n+/.freeze
|
16
|
+
QUOTE_COMMENT_CHARACTER = /^\s*\>+/.freeze
|
17
|
+
ESCAPED_QUOTES = /\\\"/.freeze
|
9
18
|
|
10
19
|
def self.normalize_punctuation(text)
|
11
|
-
text.
|
20
|
+
text.dup.force_encoding('UTF-8')
|
21
|
+
.gsub(SPECIAL_DOUBLE_QUOTES, '"')
|
22
|
+
.gsub(SPECIAL_SINGLE_QUOTES, "'")
|
23
|
+
.gsub(QUOTE_COMMENT_CHARACTER, '')
|
24
|
+
.gsub(SPACES, ' ')
|
25
|
+
.gsub(NEWLINE_CHARACTER, ' ')
|
26
|
+
.gsub(ESCAPED_QUOTES, '"')
|
12
27
|
.gsub(QUOTES, '"')
|
13
28
|
.strip
|
29
|
+
rescue ArgumentError => _e
|
30
|
+
text
|
14
31
|
end
|
15
32
|
|
16
33
|
def self.compile_to_regex(text)
|
17
|
-
Regexp.new(Regexp.escape(text)
|
34
|
+
Regexp.new(Regexp.escape(normalize_punctuation(text))
|
35
|
+
.gsub(PLACEHOLDERS, '(.*)')
|
36
|
+
.gsub(',', '(,)?')
|
37
|
+
.gsub('HOLDER', '(HOLDER|OWNER)')
|
38
|
+
.gsub(ALPHABET_ORDERED_LIST, ALPHABET_ORDERED_LIST_OPTIONAL)
|
39
|
+
.gsub(LIST_BULLETS, LIST_BULLETS_OPTIONAL))
|
18
40
|
end
|
19
41
|
end
|
20
42
|
end
|
@@ -43,6 +43,7 @@ module LicenseFinder
|
|
43
43
|
@summary = options[:summary] || ''
|
44
44
|
@description = options[:description] || ''
|
45
45
|
@homepage = options[:homepage] || ''
|
46
|
+
@package_url = options[:package_url].to_s
|
46
47
|
@children = options[:children] || []
|
47
48
|
@parents = Set.new # will be figured out later by package manager
|
48
49
|
@groups = options[:groups] || []
|
@@ -61,7 +62,7 @@ module LicenseFinder
|
|
61
62
|
|
62
63
|
## DESCRIPTION
|
63
64
|
|
64
|
-
attr_accessor :homepage
|
65
|
+
attr_accessor :homepage, :package_url
|
65
66
|
|
66
67
|
attr_reader :name, :version, :authors,
|
67
68
|
:summary, :description,
|
@@ -119,8 +119,12 @@ module LicenseFinder
|
|
119
119
|
attr_reader :logger, :project_path
|
120
120
|
|
121
121
|
def log_errors(stderr)
|
122
|
-
|
123
|
-
|
122
|
+
log_errors_with_cmd(prepare_command, stderr)
|
123
|
+
end
|
124
|
+
|
125
|
+
def log_errors_with_cmd(prep_cmd, stderr)
|
126
|
+
logger.info prep_cmd, 'did not succeed.', color: :red
|
127
|
+
logger.info prep_cmd, stderr, color: :red
|
124
128
|
log_to_file stderr
|
125
129
|
end
|
126
130
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'bundler'
|
4
|
+
require 'securerandom'
|
4
5
|
|
5
6
|
module LicenseFinder
|
6
7
|
class Bundler < PackageManager
|
@@ -26,7 +27,10 @@ module LicenseFinder
|
|
26
27
|
def prepare_command
|
27
28
|
ignored_groups_argument = !ignored_groups.empty? ? "--without #{ignored_groups.to_a.join(' ')}" : ''
|
28
29
|
|
29
|
-
|
30
|
+
gem_path = "lf-bundler-gems-#{SecureRandom.uuid}"
|
31
|
+
logger.info self.class, "Running bundle install for #{Dir.pwd} with path #{gem_path}", color: :blue
|
32
|
+
|
33
|
+
"bundle install #{ignored_groups_argument} --path #{gem_path}".strip
|
30
34
|
end
|
31
35
|
|
32
36
|
def possible_package_paths
|
@@ -38,8 +42,6 @@ module LicenseFinder
|
|
38
42
|
attr_reader :ignored_groups
|
39
43
|
|
40
44
|
def definition
|
41
|
-
# DI
|
42
|
-
ENV['BUNDLE_PATH'] = project_path.to_s
|
43
45
|
ENV['BUNDLE_GEMFILE'] = "#{project_path}/#{gemfile}"
|
44
46
|
|
45
47
|
@definition ||= ::Bundler::Definition.build(detected_package_path, lockfile_path, nil)
|
@@ -6,7 +6,8 @@ module LicenseFinder
|
|
6
6
|
class Cargo < PackageManager
|
7
7
|
def current_packages
|
8
8
|
cargo_output.map do |package|
|
9
|
-
|
9
|
+
path = Dir.glob("#{Dir.home}/.cargo/registry/src/**/#{package['name']}-#{package['version']}").first
|
10
|
+
CargoPackage.new(package, logger: logger, install_path: path)
|
10
11
|
end
|
11
12
|
end
|
12
13
|
|
@@ -12,7 +12,11 @@ module LicenseFinder
|
|
12
12
|
|
13
13
|
def current_packages
|
14
14
|
dependency_list.map do |name, dependency|
|
15
|
-
|
15
|
+
path_command = "composer show #{name} -P"
|
16
|
+
stdout, _stderr, status = Dir.chdir(project_path) { Cmd.run(path_command) }
|
17
|
+
|
18
|
+
path = status.success? ? stdout.split(' ').last : ''
|
19
|
+
ComposerPackage.new(name, dependency['version'], spec_licenses: dependency['license'], install_path: path)
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'tomlrb'
|
4
4
|
|
5
5
|
module LicenseFinder
|
6
6
|
class Dep < PackageManager
|
@@ -9,7 +9,7 @@ module LicenseFinder
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def current_packages
|
12
|
-
toml =
|
12
|
+
toml = Tomlrb.load_file(detected_package_path)
|
13
13
|
projects = toml['projects']
|
14
14
|
|
15
15
|
return [] if projects.nil?
|
@@ -63,7 +63,8 @@ module LicenseFinder
|
|
63
63
|
.uniq { |d| [d.name, d.version] }
|
64
64
|
|
65
65
|
package_metadatas.map do |d|
|
66
|
-
|
66
|
+
path = Dir.glob("#{Dir.home}/.nuget/packages/#{d.name.downcase}/#{d.version}").first
|
67
|
+
NugetPackage.new(d.name, d.version, spec_licenses: d.read_license_urls, install_path: path)
|
67
68
|
end
|
68
69
|
end
|
69
70
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module LicenseFinder
|
4
4
|
class Glide < PackageManager
|
5
5
|
def possible_package_paths
|
6
|
-
[project_path.join('
|
6
|
+
[project_path.join('glide.lock')]
|
7
7
|
end
|
8
8
|
|
9
9
|
def current_packages
|
@@ -11,12 +11,7 @@ module LicenseFinder
|
|
11
11
|
|
12
12
|
YAML.load_file(detected_path).fetch('imports').map do |package_hash|
|
13
13
|
import_path = package_hash.fetch('name')
|
14
|
-
license_path =
|
15
|
-
if detected_path == possible_package_paths.first
|
16
|
-
project_path.join('src', 'vendor', import_path)
|
17
|
-
else
|
18
|
-
project_path.join('vendor', import_path)
|
19
|
-
end
|
14
|
+
license_path = project_path.join('vendor', import_path)
|
20
15
|
|
21
16
|
GoPackage.from_dependency({
|
22
17
|
'ImportPath' => import_path,
|
@@ -21,12 +21,10 @@ module LicenseFinder
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def current_packages
|
24
|
-
info_output, _stderr, _status = Cmd.run("GO111MODULE=on go list -m -mod=vendor -f '{{.Path}},{{.Version}},{{.Dir}}' all")
|
25
|
-
packages_info = info_output.split("\n")
|
26
24
|
packages = packages_info.map do |package|
|
27
25
|
name, version, install_path = package.split(',')
|
28
|
-
read_package(install_path, name, version)
|
29
|
-
end
|
26
|
+
read_package(install_path, name, version) if install_path.to_s != ''
|
27
|
+
end.compact
|
30
28
|
packages.reject do |package|
|
31
29
|
Pathname(package.install_path).cleanpath == Pathname(project_path).cleanpath
|
32
30
|
end
|
@@ -34,6 +32,15 @@ module LicenseFinder
|
|
34
32
|
|
35
33
|
private
|
36
34
|
|
35
|
+
def packages_info
|
36
|
+
info_output, stderr, _status = Cmd.run("GO111MODULE=on go list -m -f '{{.Path}},{{.Version}},{{.Dir}}' all")
|
37
|
+
if stderr =~ Regexp.compile("can't compute 'all' using the vendor directory")
|
38
|
+
info_output, _stderr, _status = Cmd.run("GO111MODULE=on go list -m -mod=mod -f '{{.Path}},{{.Version}},{{.Dir}}' all")
|
39
|
+
end
|
40
|
+
|
41
|
+
info_output.split("\n")
|
42
|
+
end
|
43
|
+
|
37
44
|
def sum_files?
|
38
45
|
sum_file_paths.any?
|
39
46
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'json'
|
4
|
+
|
4
5
|
module LicenseFinder
|
5
6
|
class GoWorkspacePackageManagerError < ::StandardError
|
6
7
|
end
|
@@ -51,9 +52,10 @@ module LicenseFinder
|
|
51
52
|
return false if @strict_matching
|
52
53
|
|
53
54
|
godep = LicenseFinder::GoDep.new(project_path: Pathname(project_path))
|
55
|
+
dep = LicenseFinder::Dep.new(project_path: Pathname(project_path))
|
54
56
|
# go workspace is only active if GoDep wasn't. There are some projects
|
55
57
|
# that will use the .envrc and have a Godep folder as well.
|
56
|
-
!!(!godep.active? && envrc_path && ENVRC_REGEXP.match(IO.read(envrc_path)))
|
58
|
+
!!(!godep.active? && !dep.active? && envrc_path && ENVRC_REGEXP.match(IO.read(envrc_path)))
|
57
59
|
end
|
58
60
|
|
59
61
|
private
|
@@ -81,6 +83,8 @@ module LicenseFinder
|
|
81
83
|
orig_gopath = ENV['GOPATH']
|
82
84
|
ENV['GOPATH'] = nil
|
83
85
|
val, stderr, status = Cmd.run('go list -f "{{join .Deps \"\n\"}}" ./...')
|
86
|
+
ENV['GOPATH'] = project_path.to_s
|
87
|
+
val, stderr, status = Cmd.run('go list -f "{{join .Deps \"\n\"}}" ./...') unless status.success?
|
84
88
|
ENV['GOPATH'] = orig_gopath
|
85
89
|
raise GoWorkspacePackageManagerError, "go list failed:\n#{stderr}" unless status.success?
|
86
90
|
|
@@ -51,7 +51,9 @@ module LicenseFinder
|
|
51
51
|
def current_packages
|
52
52
|
dependencies.each_with_object({}) do |dep, memo|
|
53
53
|
licenses = license_urls(dep)
|
54
|
-
|
54
|
+
path = Dir.glob("#{Dir.home}/.nuget/packages/#{dep.name.downcase}/#{dep.version}").first
|
55
|
+
|
56
|
+
memo[dep.name] ||= NugetPackage.new(dep.name, dep.version, spec_licenses: licenses, install_path: path)
|
55
57
|
memo[dep.name].groups << dep.assembly unless memo[dep.name].groups.include? dep.assembly
|
56
58
|
end.values
|
57
59
|
end
|
@@ -71,10 +73,42 @@ module LicenseFinder
|
|
71
73
|
assemblies.flat_map(&:dependencies)
|
72
74
|
end
|
73
75
|
|
76
|
+
def nuget_binary
|
77
|
+
legacy_vcproj = Dir['**/*.vcproj'].any?
|
78
|
+
|
79
|
+
if legacy_vcproj
|
80
|
+
'/usr/local/bin/nugetv3.5.0.exe'
|
81
|
+
else
|
82
|
+
'/usr/local/bin/nuget.exe'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
74
86
|
def package_management_command
|
75
87
|
return 'nuget' if LicenseFinder::Platform.windows?
|
76
88
|
|
77
|
-
|
89
|
+
"mono #{nuget_binary}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def prepare
|
93
|
+
cmd = prepare_command
|
94
|
+
stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(cmd) }
|
95
|
+
return if status.success?
|
96
|
+
|
97
|
+
log_errors stderr
|
98
|
+
|
99
|
+
if stderr.include?('-PackagesDirectory')
|
100
|
+
logger.info cmd, 'trying fallback prepare command', color: :magenta
|
101
|
+
|
102
|
+
cmd = "#{cmd} -PackagesDirectory ."
|
103
|
+
stdout, stderr, status = Dir.chdir(project_path) { Cmd.run(cmd) }
|
104
|
+
return if status.success?
|
105
|
+
|
106
|
+
log_errors_with_cmd(cmd, stderr)
|
107
|
+
end
|
108
|
+
|
109
|
+
error_message = "Prepare command '#{cmd}' failed\n#{stderr}"
|
110
|
+
error_message += "\n#{stdout}\n" if !stdout.nil? && !stdout.empty?
|
111
|
+
raise error_message unless @prepare_no_fail
|
78
112
|
end
|
79
113
|
|
80
114
|
def prepare_command
|
@@ -94,7 +128,7 @@ module LicenseFinder
|
|
94
128
|
def nuget_check
|
95
129
|
return 'where nuget' if LicenseFinder::Platform.windows?
|
96
130
|
|
97
|
-
|
131
|
+
"which mono && ls #{nuget_binary}"
|
98
132
|
end
|
99
133
|
|
100
134
|
def self.nuspec_license_urls(specfile_content)
|
@@ -15,7 +15,7 @@ module LicenseFinder
|
|
15
15
|
begin
|
16
16
|
packages = {}
|
17
17
|
each_dependency(groups: allowed_groups) do |name, data, group|
|
18
|
-
version = canonicalize(data['version'])
|
18
|
+
version = canonicalize(data['version'] || 'unknown')
|
19
19
|
package = packages.fetch(key_for(name, version)) do |key|
|
20
20
|
packages[key] = build_package_for(name, version)
|
21
21
|
end
|
@@ -30,7 +30,9 @@ module LicenseFinder
|
|
30
30
|
'version' => version,
|
31
31
|
'licenses' => [{ 'name' => row['License'] }]
|
32
32
|
}
|
33
|
-
|
33
|
+
|
34
|
+
path = File.join("#{Dir.home}/.ivy2/cache", "#{spec['groupId']}/#{spec['artifactId']}")
|
35
|
+
SbtPackage.new(spec, logger: logger, include_groups: @include_groups, install_path: path)
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
@@ -72,11 +72,25 @@ module LicenseFinder
|
|
72
72
|
valid_packages = filter_yarn_internal_package(packages)
|
73
73
|
|
74
74
|
valid_packages.map do |package_hash|
|
75
|
-
YarnPackage.new(
|
76
|
-
|
75
|
+
YarnPackage.new(
|
76
|
+
package_hash['Name'],
|
77
|
+
package_hash['Version'],
|
78
|
+
spec_licenses: [package_hash['License']],
|
79
|
+
homepage: package_hash['VendorUrl'],
|
80
|
+
authors: package_hash['VendorName'],
|
81
|
+
install_path: project_path.join(modules_folder, package_hash['Name'])
|
82
|
+
)
|
77
83
|
end
|
78
84
|
end
|
79
85
|
|
86
|
+
def modules_folder
|
87
|
+
return @modules_folder if @modules_folder
|
88
|
+
|
89
|
+
stdout, _stderr, status = Cmd.run('yarn config get modules-folder')
|
90
|
+
@modules_folder = 'node_modules' if !status.success? || stdout.strip == 'undefined'
|
91
|
+
@modules_folder ||= stdout.strip
|
92
|
+
end
|
93
|
+
|
80
94
|
# remove fake package created by yarn [Yarn Bug]
|
81
95
|
def filter_yarn_internal_package(all_packages)
|
82
96
|
internal_package_pattern = /workspace-aggregator-[a-zA-z0-9]{8}-[a-zA-z0-9]{4}-[a-zA-z0-9]{4}-[a-zA-z0-9]{4}-[a-zA-z0-9]{12}/
|
@@ -4,7 +4,7 @@ require 'license_finder/package_utils/possible_license_file'
|
|
4
4
|
|
5
5
|
module LicenseFinder
|
6
6
|
class LicenseFiles
|
7
|
-
CANDIDATE_FILE_NAMES = %w[
|
7
|
+
CANDIDATE_FILE_NAMES = %w[License Licence COPYING README].freeze
|
8
8
|
CANDIDATE_PATH_WILDCARD = "*{#{CANDIDATE_FILE_NAMES.join(',')}}*"
|
9
9
|
|
10
10
|
def self.find(install_path, options = {})
|
@@ -35,7 +35,7 @@ module LicenseFinder
|
|
35
35
|
def candidate_files_and_dirs
|
36
36
|
return [] if install_path.nil?
|
37
37
|
|
38
|
-
Pathname.glob(install_path.join('**', CANDIDATE_PATH_WILDCARD))
|
38
|
+
Pathname.glob(install_path.join('**', CANDIDATE_PATH_WILDCARD), File::FNM_CASEFOLD)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'open-uri'
|
4
|
+
|
3
5
|
module LicenseFinder
|
4
6
|
class BowerPackage < Package
|
5
7
|
def initialize(bower_module, options = {})
|
@@ -31,5 +33,10 @@ module LicenseFinder
|
|
31
33
|
def package_manager
|
32
34
|
'Bower'
|
33
35
|
end
|
36
|
+
|
37
|
+
def package_url
|
38
|
+
meta = JSON.parse(open("https://registry.bower.io/packages/#{CGI.escape(name)}").read)
|
39
|
+
meta['url']
|
40
|
+
end
|
34
41
|
end
|
35
42
|
end
|