license_scout 1.3.16 → 2.0.2
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/README.md +195 -0
- data/bin/license_scout +3 -59
- data/bin/mix_lock_json +0 -0
- data/bin/rebar_lock_json +0 -0
- data/lib/license_scout/cli.rb +99 -0
- data/lib/license_scout/collector.rb +25 -77
- data/lib/license_scout/config.rb +94 -0
- data/lib/license_scout/data/dependeny_manifest_v2_schema.json +62 -0
- data/lib/license_scout/data/exceptions.json +306 -0
- data/lib/license_scout/data/licenses.json +4653 -0
- data/lib/license_scout/dependency.rb +79 -7
- data/lib/license_scout/dependency_manager/base.rb +74 -42
- data/lib/license_scout/dependency_manager/berkshelf.rb +25 -50
- data/lib/license_scout/dependency_manager/bundler/_bundler_script.rb +1 -1
- data/lib/license_scout/dependency_manager/bundler.rb +47 -69
- data/lib/license_scout/dependency_manager/cpanm.rb +62 -112
- data/lib/license_scout/dependency_manager/dep.rb +29 -36
- data/lib/license_scout/dependency_manager/glide.rb +25 -36
- data/lib/license_scout/dependency_manager/godep.rb +27 -26
- data/lib/license_scout/dependency_manager/habitat.rb +126 -0
- data/lib/license_scout/dependency_manager/mix.rb +105 -0
- data/lib/license_scout/dependency_manager/npm.rb +30 -86
- data/lib/license_scout/dependency_manager/rebar.rb +26 -45
- data/lib/license_scout/dependency_manager.rb +19 -5
- data/lib/license_scout/exceptions.rb +2 -43
- data/lib/license_scout/license.rb +126 -0
- data/lib/license_scout/{license_file_analyzer.rb → log.rb} +4 -6
- data/lib/license_scout/reporter.rb +149 -55
- data/lib/license_scout/spdx.rb +123 -0
- data/lib/license_scout/version.rb +1 -1
- data/lib/license_scout.rb +2 -0
- data/native_parsers/mix_lock_json/README.md +21 -0
- data/native_parsers/mix_lock_json/lib/mix_lock_json.ex +20 -0
- data/native_parsers/mix_lock_json/mix.exs +31 -0
- data/native_parsers/mix_lock_json/mix.lock +3 -0
- data/{erl_src → native_parsers}/rebar_lock_json/rebar.lock +2 -2
- metadata +144 -67
- data/lib/license_scout/canonical_licenses/BSD-2-Clause.txt +0 -19
- data/lib/license_scout/canonical_licenses/BSD-3-Clause.txt +0 -27
- data/lib/license_scout/canonical_licenses/BSD-4-Clause.txt +0 -31
- data/lib/license_scout/canonical_licenses/Chef-MLSA.txt +0 -5
- data/lib/license_scout/canonical_licenses/ISC.txt +0 -14
- data/lib/license_scout/canonical_licenses/MIT.txt +0 -20
- data/lib/license_scout/dependency_manager/bundler/LICENSE.md +0 -23
- data/lib/license_scout/dependency_manager/json/README.md +0 -392
- data/lib/license_scout/dependency_manager/manual.rb +0 -67
- data/lib/license_scout/license_file_analyzer/any_matcher.rb +0 -37
- data/lib/license_scout/license_file_analyzer/definitions.rb +0 -219
- data/lib/license_scout/license_file_analyzer/header_matcher.rb +0 -34
- data/lib/license_scout/license_file_analyzer/matcher.rb +0 -46
- data/lib/license_scout/license_file_analyzer/template.rb +0 -45
- data/lib/license_scout/license_file_analyzer/templates/Apache2-short.txt +0 -11
- data/lib/license_scout/license_file_analyzer/templates/Apache2.txt +0 -170
- data/lib/license_scout/license_file_analyzer/templates/BSD-2-Clause-bullets.txt +0 -18
- data/lib/license_scout/license_file_analyzer/templates/BSD-2-Clause.txt +0 -19
- data/lib/license_scout/license_file_analyzer/templates/BSD-3-Clause-alt-format.txt +0 -24
- data/lib/license_scout/license_file_analyzer/templates/BSD-3-Clause.txt +0 -21
- data/lib/license_scout/license_file_analyzer/templates/BSD.txt +0 -24
- data/lib/license_scout/license_file_analyzer/templates/Chef-MLSA.txt +0 -5
- data/lib/license_scout/license_file_analyzer/templates/EPLICENSE.txt +0 -286
- data/lib/license_scout/license_file_analyzer/templates/GPL-2.0.txt +0 -339
- data/lib/license_scout/license_file_analyzer/templates/GPL-3.0.txt +0 -674
- data/lib/license_scout/license_file_analyzer/templates/ISC.txt +0 -2
- data/lib/license_scout/license_file_analyzer/templates/LGPL-3.0.txt +0 -165
- data/lib/license_scout/license_file_analyzer/templates/MIT.txt +0 -9
- data/lib/license_scout/license_file_analyzer/templates/MPL2.txt +0 -373
- data/lib/license_scout/license_file_analyzer/templates/Python-2.0.txt +0 -47
- data/lib/license_scout/license_file_analyzer/templates/Ruby.txt +0 -52
- data/lib/license_scout/license_file_analyzer/text.rb +0 -46
- data/lib/license_scout/net_fetcher.rb +0 -106
- data/lib/license_scout/options.rb +0 -47
- data/lib/license_scout/overrides.rb +0 -1123
- /data/{erl_src → native_parsers}/rebar_lock_json/README.md +0 -0
- /data/{erl_src → native_parsers}/rebar_lock_json/rebar.config +0 -0
- /data/{erl_src → native_parsers}/rebar_lock_json/src/rebar_lock_json.app.src +0 -0
- /data/{erl_src → native_parsers}/rebar_lock_json/src/rebar_lock_json.erl +0 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright 2016, Chef Software Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require "license_scout/dependency_manager/base"
|
19
|
+
require "license_scout/exceptions"
|
20
|
+
|
21
|
+
require "mixlib/shellout"
|
22
|
+
require "ffi_yajl"
|
23
|
+
|
24
|
+
module LicenseScout
|
25
|
+
module DependencyManager
|
26
|
+
class Mix < Base
|
27
|
+
|
28
|
+
attr_reader :packaged_dependencies
|
29
|
+
|
30
|
+
def initialize(directory)
|
31
|
+
super(directory)
|
32
|
+
|
33
|
+
@packaged_dependencies = {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def name
|
37
|
+
"elixir_mix"
|
38
|
+
end
|
39
|
+
|
40
|
+
def type
|
41
|
+
"elixir"
|
42
|
+
end
|
43
|
+
|
44
|
+
def signature
|
45
|
+
"mix.lock file"
|
46
|
+
end
|
47
|
+
|
48
|
+
def install_command
|
49
|
+
"mix deps.get"
|
50
|
+
end
|
51
|
+
|
52
|
+
def detected?
|
53
|
+
File.exist?(mix_lock_path)
|
54
|
+
end
|
55
|
+
|
56
|
+
def dependencies
|
57
|
+
parse_packaged_dependencies
|
58
|
+
|
59
|
+
# Some dependencies are obtained via 'pkg' identifier of rebar. These
|
60
|
+
# dependencies include their version in the rebar.lock file. Here we
|
61
|
+
# parse the rebar.lock and remember all the versions we find.
|
62
|
+
packaged_dependencies.map do |dep_name, dep_version|
|
63
|
+
dep_path = Dir.glob(File.join(directory, "**", "deps", dep_name)).first
|
64
|
+
|
65
|
+
dependency = new_dependency(dep_name, dep_version, dep_path)
|
66
|
+
|
67
|
+
Array(hex_info(dep_name).dig("meta", "licenses")).each do |license|
|
68
|
+
dependency.add_license(license, "https://hex.pm/api/packages/#{dep_name}")
|
69
|
+
end
|
70
|
+
|
71
|
+
dependency
|
72
|
+
end.compact
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def parse_packaged_dependencies
|
78
|
+
mix_lock_to_json_path = File.expand_path("../../../bin/mix_lock_json", File.dirname(__FILE__))
|
79
|
+
s = Mixlib::ShellOut.new("#{LicenseScout::Config.escript_bin} #{mix_lock_to_json_path} #{mix_lock_path}", environment: LicenseScout::Config.environment)
|
80
|
+
s.run_command
|
81
|
+
s.error!
|
82
|
+
|
83
|
+
mix_lock_content = FFI_Yajl::Parser.parse(s.stdout)
|
84
|
+
|
85
|
+
mix_lock_content.each do |dep|
|
86
|
+
name = dep.keys.first
|
87
|
+
version = dep.values.first
|
88
|
+
|
89
|
+
@packaged_dependencies[name] = version
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def mix_lock_path
|
94
|
+
File.join(directory, "mix.lock")
|
95
|
+
end
|
96
|
+
|
97
|
+
def hex_info(package_name)
|
98
|
+
FFI_Yajl::Parser.parse(open("https://hex.pm/api/packages/#{package_name}").read)
|
99
|
+
rescue OpenURI::HTTPError
|
100
|
+
LicenseScout::Log.debug("[elixir] Unable to download hex.pm info for #{package_name}")
|
101
|
+
{}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -15,16 +15,28 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
#
|
17
17
|
|
18
|
-
require "set"
|
19
|
-
require "ffi_yajl"
|
18
|
+
require "set"
|
19
|
+
require "ffi_yajl"
|
20
20
|
require "license_scout/dependency_manager/base"
|
21
21
|
|
22
22
|
module LicenseScout
|
23
23
|
module DependencyManager
|
24
|
-
class
|
24
|
+
class Npm < Base
|
25
25
|
|
26
26
|
def name
|
27
|
-
"
|
27
|
+
"nodejs_npm"
|
28
|
+
end
|
29
|
+
|
30
|
+
def type
|
31
|
+
"nodejs"
|
32
|
+
end
|
33
|
+
|
34
|
+
def signature
|
35
|
+
"node_modules directory"
|
36
|
+
end
|
37
|
+
|
38
|
+
def install_command
|
39
|
+
"npm install"
|
28
40
|
end
|
29
41
|
|
30
42
|
def detected?
|
@@ -32,33 +44,26 @@ module LicenseScout
|
|
32
44
|
end
|
33
45
|
|
34
46
|
def dependencies
|
35
|
-
|
47
|
+
all_package_json_files.inject(Set.new) do |uniq_deps, package_json_file|
|
36
48
|
pkg_info = File.open(package_json_file) do |f|
|
37
49
|
FFI_Yajl::Parser.parse(f)
|
38
50
|
end
|
39
51
|
|
40
|
-
|
41
|
-
|
42
|
-
|
52
|
+
dep_name = pkg_info["name"]
|
53
|
+
dep_version = pkg_info["version"]
|
54
|
+
dep_path = File.dirname(package_json_file)
|
43
55
|
|
44
|
-
|
45
|
-
normalize_license_data(pkg_info["license"] || pkg_info["licence"] || pkg_info["licenses"])
|
56
|
+
dependency = new_dependency(dep_name, dep_version, dep_path)
|
46
57
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
58
|
+
case pkg_info["license"]
|
59
|
+
when String
|
60
|
+
dependency.add_license(pkg_info["license"], "package.json")
|
61
|
+
when Hash
|
62
|
+
dependency.add_license(pkg_info["license"]["type"], "package.json", pkg_info["license"]["url"])
|
52
63
|
end
|
53
64
|
|
54
|
-
|
55
|
-
|
56
|
-
pkg_version,
|
57
|
-
license,
|
58
|
-
license_files
|
59
|
-
)
|
60
|
-
end
|
61
|
-
packages.to_a
|
65
|
+
uniq_deps << dependency
|
66
|
+
end.to_a
|
62
67
|
end
|
63
68
|
|
64
69
|
private
|
@@ -79,7 +84,7 @@ module LicenseScout
|
|
79
84
|
# package metadata is removed).
|
80
85
|
def all_package_json_files
|
81
86
|
all_files = []
|
82
|
-
package_dirs = [
|
87
|
+
package_dirs = [directory]
|
83
88
|
loop do
|
84
89
|
break if package_dirs.empty?
|
85
90
|
|
@@ -98,70 +103,9 @@ module LicenseScout
|
|
98
103
|
all_files
|
99
104
|
end
|
100
105
|
|
101
|
-
def find_license_files_in(dir)
|
102
|
-
root_files = Dir["#{dir}/*"]
|
103
|
-
root_files.select { |f| POSSIBLE_LICENSE_FILES.include?(File.basename(f)) }
|
104
|
-
end
|
105
|
-
|
106
|
-
def normalize_license_data(license_metadata)
|
107
|
-
license_string =
|
108
|
-
case license_metadata
|
109
|
-
when nil
|
110
|
-
nil
|
111
|
-
when String
|
112
|
-
license_metadata
|
113
|
-
when Hash
|
114
|
-
license_metadata["type"]
|
115
|
-
when Array
|
116
|
-
if (map = license_metadata.first) && map.is_a?(Hash) && (type = map["type"])
|
117
|
-
type
|
118
|
-
else
|
119
|
-
nil
|
120
|
-
end
|
121
|
-
end
|
122
|
-
select_best_license(license_string)
|
123
|
-
end
|
124
|
-
|
125
|
-
# npm packages use SPDX "expressions" for their licenses; Thus far we've
|
126
|
-
# only seen a single license, optional multiple licenses like "(MIT OR Apache-2.0)"
|
127
|
-
# or mandatory multiple licenses like "(MIT AND CC-BY-3.0)"
|
128
|
-
#
|
129
|
-
# If there are multiple options, we want to pick just one to keep it simple.
|
130
|
-
def select_best_license(license_string)
|
131
|
-
return nil if license_string.nil?
|
132
|
-
|
133
|
-
options = license_string.tr("(", "").tr(")", "").split(" OR ")
|
134
|
-
options.inject do |selected_license, license|
|
135
|
-
if license_rank(selected_license) < license_rank(license)
|
136
|
-
selected_license
|
137
|
-
else
|
138
|
-
license
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
# Rank licenses when selecting one of multiple options. Licenses are
|
144
|
-
# converted to integer scores, the lower the better.
|
145
|
-
#
|
146
|
-
# We prefer Apache-2.0 since it matches our own projects, then MIT, then
|
147
|
-
# BSDs. Everything else is considered equal.
|
148
|
-
def license_rank(license)
|
149
|
-
case license
|
150
|
-
when "Apache-2.0"
|
151
|
-
0
|
152
|
-
when "MIT"
|
153
|
-
1
|
154
|
-
when /bsd/i
|
155
|
-
2
|
156
|
-
else
|
157
|
-
3
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
106
|
def root_node_modules_path
|
162
|
-
File.join(
|
107
|
+
File.join(directory, "node_modules")
|
163
108
|
end
|
164
|
-
|
165
109
|
end
|
166
110
|
end
|
167
111
|
end
|
@@ -16,12 +16,10 @@
|
|
16
16
|
#
|
17
17
|
|
18
18
|
require "license_scout/dependency_manager/base"
|
19
|
-
require "license_scout/net_fetcher"
|
20
19
|
require "license_scout/exceptions"
|
21
|
-
require "license_scout/license_file_analyzer"
|
22
20
|
|
23
|
-
require "mixlib/shellout"
|
24
|
-
require "ffi_yajl"
|
21
|
+
require "mixlib/shellout"
|
22
|
+
require "ffi_yajl"
|
25
23
|
|
26
24
|
module LicenseScout
|
27
25
|
module DependencyManager
|
@@ -29,8 +27,8 @@ module LicenseScout
|
|
29
27
|
|
30
28
|
attr_reader :packaged_dependencies
|
31
29
|
|
32
|
-
def initialize(
|
33
|
-
super(
|
30
|
+
def initialize(directory)
|
31
|
+
super(directory)
|
34
32
|
|
35
33
|
@packaged_dependencies = {}
|
36
34
|
end
|
@@ -39,19 +37,29 @@ module LicenseScout
|
|
39
37
|
"erlang_rebar"
|
40
38
|
end
|
41
39
|
|
40
|
+
def type
|
41
|
+
"erlang"
|
42
|
+
end
|
43
|
+
|
44
|
+
def signature
|
45
|
+
"rebar.config file"
|
46
|
+
end
|
47
|
+
|
48
|
+
def install_command
|
49
|
+
"rebar get-deps"
|
50
|
+
end
|
51
|
+
|
42
52
|
def detected?
|
43
53
|
File.exist?(rebar_config_path)
|
44
54
|
end
|
45
55
|
|
46
56
|
def dependencies
|
47
|
-
dependencies = []
|
48
|
-
|
49
57
|
# Some dependencies are obtained via 'pkg' identifier of rebar. These
|
50
58
|
# dependencies include their version in the rebar.lock file. Here we
|
51
59
|
# parse the rebar.lock and remember all the versions we find.
|
52
60
|
parse_packaged_dependencies
|
53
61
|
|
54
|
-
Dir.glob("#{project_deps_dir}/*").
|
62
|
+
Dir.glob("#{project_deps_dir}/*").map do |dep_dir|
|
55
63
|
next unless File.directory?(dep_dir)
|
56
64
|
|
57
65
|
dep_name = File.basename(dep_dir)
|
@@ -59,10 +67,10 @@ module LicenseScout
|
|
59
67
|
# First check if this dependency is coming from the parent software.
|
60
68
|
# If so we do not need to worry about its version or licenses because
|
61
69
|
# it will be covered under the parent software's license.
|
62
|
-
next if File.directory?(File.join(
|
70
|
+
next if File.directory?(File.join(directory, "apps", dep_name))
|
63
71
|
|
64
72
|
# Or skip if the dep name is the project name
|
65
|
-
next if File.exist?(File.join(
|
73
|
+
next if File.exist?(File.join(directory, "_build/default/rel", dep_name))
|
66
74
|
|
67
75
|
# While determining the dependency version we first check the cache we
|
68
76
|
# built from rebar.lock for the dependencies that come via 'pkg'
|
@@ -74,22 +82,8 @@ module LicenseScout
|
|
74
82
|
git_rev_parse(dep_dir)
|
75
83
|
end
|
76
84
|
|
77
|
-
|
78
|
-
|
79
|
-
if override_license_files.empty?
|
80
|
-
Dir.glob("#{dep_dir}/*").select { |f| POSSIBLE_LICENSE_FILES.include?(File.basename(f)) }
|
81
|
-
else
|
82
|
-
override_license_files.resolve_locations(dep_dir)
|
83
|
-
end
|
84
|
-
|
85
|
-
license_name = options.overrides.license_for(name, dep_name, dep_version) || scan_licenses(license_files)
|
86
|
-
|
87
|
-
dep = create_dependency(dep_name, dep_version, license_name, license_files)
|
88
|
-
|
89
|
-
dependencies << dep
|
90
|
-
end
|
91
|
-
|
92
|
-
dependencies
|
85
|
+
new_dependency(dep_name, dep_version, dep_dir)
|
86
|
+
end.compact
|
93
87
|
end
|
94
88
|
|
95
89
|
private
|
@@ -99,12 +93,12 @@ module LicenseScout
|
|
99
93
|
# determine the version of them via git, we try to parse the rebar.lock
|
100
94
|
# file and remember their versions to use it later.
|
101
95
|
def parse_packaged_dependencies
|
102
|
-
rebar_lock_path = File.join(
|
96
|
+
rebar_lock_path = File.join(directory, "rebar.lock")
|
103
97
|
|
104
98
|
return unless File.exist?(rebar_lock_path)
|
105
99
|
|
106
100
|
rebar_lock_to_json_path = File.expand_path("../../../bin/rebar_lock_json", File.dirname(__FILE__))
|
107
|
-
s = Mixlib::ShellOut.new("#{rebar_lock_to_json_path} #{rebar_lock_path}", environment:
|
101
|
+
s = Mixlib::ShellOut.new("#{LicenseScout::Config.escript_bin} #{rebar_lock_to_json_path} #{rebar_lock_path}", environment: LicenseScout::Config.environment)
|
108
102
|
s.run_command
|
109
103
|
s.error!
|
110
104
|
|
@@ -115,7 +109,7 @@ module LicenseScout
|
|
115
109
|
source_name = source_info["pkg_name"]
|
116
110
|
source_version = source_info["pkg_version"]
|
117
111
|
|
118
|
-
packaged_dependencies[source_name] = source_version
|
112
|
+
@packaged_dependencies[source_name] = source_version
|
119
113
|
end
|
120
114
|
end
|
121
115
|
rescue Mixlib::ShellOut::ShellCommandFailed
|
@@ -139,27 +133,14 @@ module LicenseScout
|
|
139
133
|
def project_deps_dir
|
140
134
|
# rebar dependencies can be found in one of these two directories.
|
141
135
|
["deps", "_build/default/lib"].each do |dir|
|
142
|
-
dep_dir = File.join(
|
136
|
+
dep_dir = File.join(directory, dir)
|
143
137
|
return dep_dir if File.exist?(dep_dir)
|
144
138
|
end
|
145
139
|
end
|
146
140
|
|
147
141
|
def rebar_config_path
|
148
|
-
File.join(
|
149
|
-
end
|
150
|
-
|
151
|
-
def scan_licenses(license_files)
|
152
|
-
if license_files.empty?
|
153
|
-
nil
|
154
|
-
else
|
155
|
-
license_names = license_files.map do |license_file|
|
156
|
-
found_license = LicenseScout::LicenseFileAnalyzer.find_by_text(IO.read(license_file))
|
157
|
-
found_license ? found_license.short_name : nil
|
158
|
-
end
|
159
|
-
license_names.find { |x| x }
|
160
|
-
end
|
142
|
+
File.join(directory, "rebar.config")
|
161
143
|
end
|
162
|
-
|
163
144
|
end
|
164
145
|
end
|
165
146
|
end
|
@@ -15,20 +15,34 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
#
|
17
17
|
|
18
|
+
require "license_scout/dependency_manager/base"
|
19
|
+
|
20
|
+
require "license_scout/dependency_manager/berkshelf"
|
18
21
|
require "license_scout/dependency_manager/bundler"
|
19
|
-
require "license_scout/dependency_manager/rebar"
|
20
22
|
require "license_scout/dependency_manager/cpanm"
|
21
|
-
require "license_scout/dependency_manager/godep"
|
22
23
|
require "license_scout/dependency_manager/dep"
|
23
24
|
require "license_scout/dependency_manager/glide"
|
24
|
-
require "license_scout/dependency_manager/
|
25
|
+
require "license_scout/dependency_manager/godep"
|
26
|
+
require "license_scout/dependency_manager/habitat"
|
27
|
+
require "license_scout/dependency_manager/mix"
|
28
|
+
require "license_scout/dependency_manager/rebar"
|
25
29
|
require "license_scout/dependency_manager/npm"
|
26
|
-
require "license_scout/dependency_manager/manual"
|
27
30
|
|
28
31
|
module LicenseScout
|
29
32
|
module DependencyManager
|
30
33
|
def self.implementations
|
31
|
-
[
|
34
|
+
[
|
35
|
+
Berkshelf,
|
36
|
+
Bundler,
|
37
|
+
Cpanm,
|
38
|
+
Dep,
|
39
|
+
Glide,
|
40
|
+
Godep,
|
41
|
+
Habitat,
|
42
|
+
Mix,
|
43
|
+
Rebar,
|
44
|
+
Npm,
|
45
|
+
]
|
32
46
|
end
|
33
47
|
end
|
34
48
|
end
|
@@ -18,48 +18,7 @@
|
|
18
18
|
module LicenseScout
|
19
19
|
module Exceptions
|
20
20
|
class Error < RuntimeError; end
|
21
|
-
|
22
|
-
class
|
23
|
-
def initialize(project_dir)
|
24
|
-
@project_dir = project_dir
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_s
|
28
|
-
"Could not locate or access the provided project directory '#{@project_dir}'."
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class UnsupportedProjectType < Error
|
33
|
-
def initialize(project_dir)
|
34
|
-
@project_dir = project_dir
|
35
|
-
end
|
36
|
-
|
37
|
-
def to_s
|
38
|
-
"Could not find a supported dependency manager for the project in the provided directory '#{@project_dir}'."
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
class InaccessibleDependency < Error; end
|
43
|
-
class InvalidOverride < Error; end
|
44
|
-
class InvalidOutputReport < Error; end
|
45
|
-
class InvalidManualDependency < Error; end
|
46
|
-
|
47
|
-
class NetworkError < Error
|
48
|
-
|
49
|
-
attr_reader :from_url
|
50
|
-
attr_reader :network_error
|
51
|
-
|
52
|
-
def initialize(from_url, network_error)
|
53
|
-
@from_url = from_url
|
54
|
-
@network_error = network_error
|
55
|
-
end
|
56
|
-
|
57
|
-
def to_s
|
58
|
-
[
|
59
|
-
"Network error while fetching '#{from_url}'",
|
60
|
-
network_error.to_s,
|
61
|
-
].join("\n")
|
62
|
-
end
|
63
|
-
end
|
21
|
+
class ConfigError < Error; end
|
22
|
+
class MissingSourceDirectory < Error; end
|
64
23
|
end
|
65
24
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright 2018, Chef Software Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require "license_scout/spdx"
|
19
|
+
|
20
|
+
module LicenseScout
|
21
|
+
class License
|
22
|
+
# A class that represents the components that make up a license.
|
23
|
+
class Record
|
24
|
+
attr_reader :id
|
25
|
+
attr_reader :parsed_expression
|
26
|
+
attr_reader :source
|
27
|
+
attr_reader :content
|
28
|
+
attr_reader :spdx_license_data
|
29
|
+
|
30
|
+
def initialize(license_id = nil, source = nil, content = nil, options = {})
|
31
|
+
@id = LicenseScout::SPDX.find(license_id, options[:force])
|
32
|
+
@parsed_expression = LicenseScout::SPDX.parse(id)
|
33
|
+
@source = source
|
34
|
+
@content = content
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_h
|
38
|
+
{
|
39
|
+
id: id,
|
40
|
+
source: source,
|
41
|
+
content: content,
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :project
|
47
|
+
attr_reader :records
|
48
|
+
|
49
|
+
# @param path [String, nil] A path to give to Licensee to search for the license. Could be local path or GitHub URL.
|
50
|
+
def initialize(path = nil)
|
51
|
+
if path.nil?
|
52
|
+
@project = nil
|
53
|
+
@records = []
|
54
|
+
else
|
55
|
+
@project = Licensee.project(path, detect_readme: true)
|
56
|
+
@records = []
|
57
|
+
|
58
|
+
project.licenses.each_index do |i|
|
59
|
+
record = Record.new(
|
60
|
+
project.licenses[i].spdx_id,
|
61
|
+
project.matched_files[i].filename,
|
62
|
+
project.matched_files[i].content
|
63
|
+
)
|
64
|
+
|
65
|
+
# Favor records that have identified a license
|
66
|
+
record.id.nil? ? @records.push(record) : @records.unshift(record)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Capture a license that was specified in metadata
|
72
|
+
#
|
73
|
+
# @param license_id [String] The license as specified in the metadata file
|
74
|
+
# @param source [String] Where we found the license info
|
75
|
+
# @param contents_url [String] Where we can find the contents of the license
|
76
|
+
# @param options [Hash] Options to control various behavior
|
77
|
+
#
|
78
|
+
# @return [void]
|
79
|
+
def add_license(license_id, source, contents_url, options)
|
80
|
+
content = license_content(license_id, contents_url)
|
81
|
+
@records.push(Record.new(license_id, source, content, options))
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [Boolean] Whether or not the license(s) are allowed
|
85
|
+
def is_allowed?
|
86
|
+
(records.map(&:parsed_expression).flatten.compact & LicenseScout::Config.allowed_licenses).any?
|
87
|
+
end
|
88
|
+
|
89
|
+
# @return [Boolean] Whether or not the license(s) are flagged
|
90
|
+
def is_flagged?
|
91
|
+
(records.map(&:parsed_expression).flatten.compact & LicenseScout::Config.flagged_licenses).any?
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return [Boolean] Whether we were unable to determine a license
|
95
|
+
def undetermined?
|
96
|
+
(records.map(&:parsed_expression).flatten.compact).empty?
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def license_content(license_id, contents_url)
|
102
|
+
if contents_url.nil?
|
103
|
+
nil
|
104
|
+
else
|
105
|
+
new_url = raw_github_url(contents_url)
|
106
|
+
|
107
|
+
begin
|
108
|
+
LicenseScout::Log.debug("[license] Pulling license content for #{license_id} from #{new_url}")
|
109
|
+
open(new_url).read
|
110
|
+
rescue OpenURI::HTTPError
|
111
|
+
LicenseScout::Log.warn("[license] Unable to download license for #{license_id} from #{new_url}")
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def raw_github_url(url)
|
118
|
+
case url
|
119
|
+
when /github.com\/(.+)\/blob\/(.+)/
|
120
|
+
"https://raw.githubusercontent.com/#{$1}/#{$2}"
|
121
|
+
else
|
122
|
+
url
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright:: Copyright
|
2
|
+
# Copyright:: Copyright 2018, Chef Software Inc.
|
3
3
|
# License:: Apache License, Version 2.0
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -15,12 +15,10 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
#
|
17
17
|
|
18
|
-
require "
|
18
|
+
require "mixlib/log"
|
19
19
|
|
20
20
|
module LicenseScout
|
21
|
-
|
22
|
-
|
23
|
-
Definitions.all.detect { |l| l.matches_text? text }
|
24
|
-
end
|
21
|
+
class Log
|
22
|
+
extend Mixlib::Log
|
25
23
|
end
|
26
24
|
end
|