license_finder 6.2.0 → 6.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/CHANGELOG.md +61 -0
  4. data/Dockerfile +23 -15
  5. data/README.md +24 -2
  6. data/Rakefile +1 -1
  7. data/VERSION +1 -1
  8. data/ci/pipelines/release.yml.erb +15 -5
  9. data/ci/tasks/rubocop.yml +1 -1
  10. data/lib/license_finder/cli.rb +1 -0
  11. data/lib/license_finder/cli/base.rb +1 -0
  12. data/lib/license_finder/cli/inherited_decisions.rb +50 -0
  13. data/lib/license_finder/cli/main.rb +3 -1
  14. data/lib/license_finder/configuration.rb +4 -0
  15. data/lib/license_finder/decision_applier.rb +8 -4
  16. data/lib/license_finder/decisions.rb +83 -20
  17. data/lib/license_finder/license.rb +36 -0
  18. data/lib/license_finder/license/definitions.rb +48 -1
  19. data/lib/license_finder/license/templates/0BSD.txt +10 -0
  20. data/lib/license_finder/license/templates/OFL.txt +91 -0
  21. data/lib/license_finder/license/templates/SimplifiedBSD.txt +0 -4
  22. data/lib/license_finder/license/templates/WTFPL.txt +14 -0
  23. data/lib/license_finder/license/text.rb +24 -2
  24. data/lib/license_finder/logger.rb +2 -0
  25. data/lib/license_finder/package.rb +2 -1
  26. data/lib/license_finder/package_manager.rb +6 -2
  27. data/lib/license_finder/package_managers/bundler.rb +1 -3
  28. data/lib/license_finder/package_managers/cargo.rb +2 -1
  29. data/lib/license_finder/package_managers/composer.rb +5 -1
  30. data/lib/license_finder/package_managers/dotnet.rb +2 -1
  31. data/lib/license_finder/package_managers/go_15vendorexperiment.rb +1 -1
  32. data/lib/license_finder/package_managers/go_modules.rb +11 -4
  33. data/lib/license_finder/package_managers/nuget.rb +51 -4
  34. data/lib/license_finder/package_managers/pipenv.rb +1 -1
  35. data/lib/license_finder/package_managers/sbt.rb +3 -1
  36. data/lib/license_finder/package_managers/yarn.rb +16 -2
  37. data/lib/license_finder/package_utils/license_files.rb +2 -2
  38. data/lib/license_finder/packages/bower_package.rb +7 -0
  39. data/lib/license_finder/packages/bundler_package.rb +4 -0
  40. data/lib/license_finder/packages/cargo_package.rb +4 -0
  41. data/lib/license_finder/packages/cocoa_pods_package.rb +4 -0
  42. data/lib/license_finder/packages/composer_package.rb +4 -0
  43. data/lib/license_finder/packages/conan_package.rb +4 -0
  44. data/lib/license_finder/packages/go_package.rb +5 -1
  45. data/lib/license_finder/packages/gradle_package.rb +4 -0
  46. data/lib/license_finder/packages/maven_package.rb +6 -1
  47. data/lib/license_finder/packages/merged_package.rb +1 -1
  48. data/lib/license_finder/packages/mix_package.rb +4 -0
  49. data/lib/license_finder/packages/npm_package.rb +4 -0
  50. data/lib/license_finder/packages/nuget_package.rb +4 -0
  51. data/lib/license_finder/packages/pip_package.rb +13 -2
  52. data/lib/license_finder/packages/rebar_package.rb +4 -0
  53. data/lib/license_finder/packages/yarn_package.rb +4 -0
  54. data/lib/license_finder/reports/csv_report.rb +7 -3
  55. data/lib/license_finder/reports/json_report.rb +2 -0
  56. metadata +7 -3
@@ -17,7 +17,3 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
17
17
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18
18
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19
19
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20
-
21
- The views and conclusions contained in the software and documentation are those
22
- of the authors and should not be interpreted as representing official policies,
23
- either expressed or implied, of the FreeBSD Project.
@@ -0,0 +1,14 @@
1
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
+ Version 2, December 2004
3
+
4
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
5
+
6
+ Everyone is permitted to copy and distribute verbatim or modified
7
+ copies of this license document, and changing it is allowed as long
8
+ as the name is changed.
9
+
10
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
+
13
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
14
+
@@ -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.gsub(SPACES, ' ')
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).gsub(PLACEHOLDERS, '(.*)'))
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
@@ -36,6 +36,8 @@ module LicenseFinder
36
36
  "\e[31m#{string}\e[0m"
37
37
  when :green
38
38
  "\e[32m#{string}\e[0m"
39
+ when :magenta
40
+ "\e[35m#{string}\e[0m"
39
41
  else
40
42
  string
41
43
  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
- logger.info prepare_command, 'did not succeed.', color: :red
123
- logger.info prepare_command, stderr, color: :red
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
 
@@ -27,7 +27,7 @@ module LicenseFinder
27
27
  def prepare_command
28
28
  ignored_groups_argument = !ignored_groups.empty? ? "--without #{ignored_groups.to_a.join(' ')}" : ''
29
29
 
30
- gem_path = SecureRandom.uuid
30
+ gem_path = "lf-bundler-gems-#{SecureRandom.uuid}"
31
31
  logger.info self.class, "Running bundle install for #{Dir.pwd} with path #{gem_path}", color: :blue
32
32
 
33
33
  "bundle install #{ignored_groups_argument} --path #{gem_path}".strip
@@ -42,8 +42,6 @@ module LicenseFinder
42
42
  attr_reader :ignored_groups
43
43
 
44
44
  def definition
45
- # DI
46
- ENV['BUNDLE_PATH'] = project_path.to_s
47
45
  ENV['BUNDLE_GEMFILE'] = "#{project_path}/#{gemfile}"
48
46
 
49
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
- CargoPackage.new(package, logger: logger)
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
- ComposerPackage.new(name, dependency['version'], spec_licenses: dependency['license'])
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
 
@@ -63,7 +63,8 @@ module LicenseFinder
63
63
  .uniq { |d| [d.name, d.version] }
64
64
 
65
65
  package_metadatas.map do |d|
66
- NugetPackage.new(d.name, d.version, spec_licenses: d.read_license_urls)
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
 
@@ -14,7 +14,7 @@ module LicenseFinder
14
14
  end
15
15
 
16
16
  def go_files_exist?
17
- !Dir[project_path.join('**/*.go')].empty?
17
+ !Dir[project_path.join('**/*.go')].empty? && !Dir[project_path.join('vendor/**/*.go')].empty?
18
18
  end
19
19
 
20
20
  def possible_package_paths
@@ -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
@@ -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
- memo[dep.name] ||= NugetPackage.new(dep.name, dep.version, spec_licenses: licenses)
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,14 +73,59 @@ 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
- 'mono /usr/local/bin/nuget.exe'
89
+ "mono #{nuget_binary}"
90
+ end
91
+
92
+ def prepare
93
+ Dir.chdir(project_path) do
94
+ cmd = prepare_command
95
+ stdout, stderr, status = Cmd.run(cmd)
96
+ return if status.success?
97
+
98
+ log_errors stderr
99
+
100
+ if stderr.include?('-PackagesDirectory')
101
+ logger.info cmd, 'trying fallback prepare command', color: :magenta
102
+
103
+ cmd = "#{cmd} -PackagesDirectory /#{Dir.home}/.nuget/packages"
104
+ stdout, stderr, status = Cmd.run(cmd)
105
+ return if status.success?
106
+
107
+ log_errors_with_cmd(cmd, stderr)
108
+ end
109
+
110
+ error_message = "Prepare command '#{cmd}' failed\n#{stderr}"
111
+ error_message += "\n#{stdout}\n" if !stdout.nil? && !stdout.empty?
112
+ raise error_message unless @prepare_no_fail
113
+ end
78
114
  end
79
115
 
80
116
  def prepare_command
81
- "#{package_management_command} restore"
117
+ cmd = package_management_command
118
+ sln_files = Dir['*.sln']
119
+ cmds = []
120
+ if sln_files.count > 1
121
+ sln_files.each do |sln|
122
+ cmds << "#{cmd} restore #{sln}"
123
+ end
124
+ else
125
+ cmds << "#{cmd} restore"
126
+ end
127
+
128
+ cmds.join(' && ')
82
129
  end
83
130
 
84
131
  def installed?(logger = Core.default_logger)
@@ -94,7 +141,7 @@ module LicenseFinder
94
141
  def nuget_check
95
142
  return 'where nuget' if LicenseFinder::Platform.windows?
96
143
 
97
- 'which mono && ls /usr/local/bin/nuget.exe'
144
+ "which mono && ls #{nuget_binary}"
98
145
  end
99
146
 
100
147
  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
- SbtPackage.new(spec, logger: logger, include_groups: @include_groups)
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(package_hash['Name'], package_hash['Version'], spec_licenses: [package_hash['License']],
76
- homepage: package_hash['VendorUrl'])
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[LICENSE License LICENCE Licence COPYING README Readme ReadMe].freeze
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
@@ -25,5 +25,9 @@ module LicenseFinder
25
25
  def package_manager
26
26
  'Bundler'
27
27
  end
28
+
29
+ def package_url
30
+ "https://rubygems.org/gems/#{CGI.escape(name)}/versions/#{CGI.escape(version)}"
31
+ end
28
32
  end
29
33
  end
@@ -20,5 +20,9 @@ module LicenseFinder
20
20
  def package_manager
21
21
  'Cargo'
22
22
  end
23
+
24
+ def package_url
25
+ "https://crates.io/crates/#{CGI.escape(name)}/#{CGI.escape(version)}"
26
+ end
23
27
  end
24
28
  end
@@ -14,5 +14,9 @@ module LicenseFinder
14
14
  def package_manager
15
15
  'CocoaPods'
16
16
  end
17
+
18
+ def package_url
19
+ "https://cocoapods.org/pods/#{CGI.escape(name)}"
20
+ end
17
21
  end
18
22
  end
@@ -5,5 +5,9 @@ module LicenseFinder
5
5
  def package_manager
6
6
  'Composer'
7
7
  end
8
+
9
+ def package_url
10
+ "https://packagist.org/packages/#{CGI.escape(name)}##{CGI.escape(version)}"
11
+ end
8
12
  end
9
13
  end
@@ -15,5 +15,9 @@ module LicenseFinder
15
15
  def package_manager
16
16
  'Conan'
17
17
  end
18
+
19
+ def package_url
20
+ "https://conan.io/center/#{CGI.escape(name)}/#{CGI.escape(version)}"
21
+ end
18
22
  end
19
23
  end
@@ -8,12 +8,16 @@ module LicenseFinder
8
8
  'Go'
9
9
  end
10
10
 
11
+ def package_url
12
+ "https://pkg.go.dev/#{CGI.escape(name)}@#{CGI.escape(version)}"
13
+ end
14
+
11
15
  class << self
12
16
  def from_dependency(hash, prefix, full_version)
13
17
  name = hash['ImportPath']
14
18
  install_path = hash['InstallPath']
15
19
  install_path ||= install_path(prefix.join(name))
16
- version = full_version ? hash['Rev'] : hash['Rev'][0..6]
20
+ version = full_version ? hash['Rev'].gsub('+incompatible', '') : hash['Rev'][0..6]
17
21
  homepage = hash['Homepage']
18
22
  new(name, version, install_path: install_path, package_manager: 'Go', homepage: homepage)
19
23
  end
@@ -22,5 +22,9 @@ module LicenseFinder
22
22
  def package_manager
23
23
  'Gradle'
24
24
  end
25
+
26
+ def package_url
27
+ "https://plugins.gradle.org/plugin/#{CGI.escape(name)}/#{CGI.escape(version)}"
28
+ end
25
29
  end
26
30
  end