license_scout 1.3.11 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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 -1120
- /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
|