license_scout 0.1.0 → 0.1.1
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 +6 -0
- data/bin/config_to_json +0 -0
- data/bin/license_scout +4 -2
- data/lib/license_scout/collector.rb +2 -24
- data/lib/license_scout/dependency_manager/berkshelf.rb +102 -0
- data/lib/license_scout/dependency_manager/bundler/_bundler_script.rb +2 -3
- data/lib/license_scout/dependency_manager/bundler.rb +15 -9
- data/lib/license_scout/dependency_manager/cpan.rb +321 -0
- data/lib/license_scout/dependency_manager/json/README.md +392 -0
- data/lib/license_scout/dependency_manager/rebar.rb +101 -2
- data/lib/license_scout/dependency_manager.rb +3 -1
- data/lib/license_scout/exceptions.rb +1 -11
- data/lib/license_scout/net_fetcher.rb +1 -1
- data/lib/license_scout/options.rb +2 -1
- data/lib/license_scout/overrides.rb +164 -0
- data/lib/license_scout/reporter.rb +90 -0
- data/lib/license_scout/version.rb +1 -1
- data/license_scout.gemspec +1 -0
- metadata +21 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20de647a9029e60eee95ccfdd6af26ca23f68943
|
4
|
+
data.tar.gz: 4d39bfea2c9974e8af4cd400eccfca1bbec4f4bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f554b77a3215ce07597d48a64daa48844dc23463372ca5ec5bfda0726418836c25b7b53eb4e123942b5ffdf858a503e14e59d7aa196b6fa27fce0513ed985e8d
|
7
|
+
data.tar.gz: 990fd0c28d0f003e72f0cc1840198b0453c8a9f8c52c45f3e7aff9bae145e645b2a46a83901159a97de45d9e8f056bef92fe41ae3da42014350cdeffbdd6f30f
|
data/README.md
CHANGED
@@ -7,9 +7,15 @@ Currently supported project types are:
|
|
7
7
|
|
8
8
|
* Ruby - bundler
|
9
9
|
* Erlang - rebar
|
10
|
+
* CPAN - perl
|
11
|
+
* Berkshelf - chef
|
10
12
|
|
11
13
|
## Usage
|
12
14
|
|
15
|
+
## Thanks
|
16
|
+
|
17
|
+
Thanks to https://github.com/basho for `config_to_json` binary which helps with parsing Erlang config files. From: https://github.com/basho/erlang_template_helper
|
18
|
+
|
13
19
|
## Contributing
|
14
20
|
|
15
21
|
This project is maintained by the contribution guidelines identified for
|
data/bin/config_to_json
ADDED
Binary file
|
data/bin/license_scout
CHANGED
@@ -22,10 +22,12 @@ require "license_scout/collector"
|
|
22
22
|
require "license_scout/overrides"
|
23
23
|
require "license_scout/options"
|
24
24
|
|
25
|
-
project_dir = File.expand_path(Dir.pwd)
|
25
|
+
project_dir = ARGV[0] || File.expand_path(Dir.pwd)
|
26
26
|
project_name = File.basename(project_dir)
|
27
27
|
|
28
|
-
|
28
|
+
# Create the output files under a specific directory in order not to pollute the
|
29
|
+
# project_dir too much.
|
30
|
+
output_dir = File.join(project_dir, "license-cache")
|
29
31
|
|
30
32
|
overrides = LicenseScout::Overrides.new
|
31
33
|
|
@@ -17,6 +17,7 @@
|
|
17
17
|
|
18
18
|
require "license_scout/exceptions"
|
19
19
|
require "license_scout/dependency_manager"
|
20
|
+
require "license_scout/reporter"
|
20
21
|
|
21
22
|
require "ffi_yajl"
|
22
23
|
|
@@ -59,30 +60,7 @@ module LicenseScout
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def issue_report
|
62
|
-
report
|
63
|
-
license_report = FFI_Yajl::Parser.parse(File.read(license_manifest_path))
|
64
|
-
|
65
|
-
license_report["dependency_managers"].each do |dependency_manager, dependencies|
|
66
|
-
dependencies.each do |dependency|
|
67
|
-
if dependency["name"].nil? || dependency["name"].empty?
|
68
|
-
report << "There is a dependency with a missing name in '#{dependency_manager}'."
|
69
|
-
end
|
70
|
-
|
71
|
-
if dependency["version"].nil? || dependency["version"].empty?
|
72
|
-
report << "Dependency '#{dependency["name"]}' under '#{dependency_manager}' is missing version information."
|
73
|
-
end
|
74
|
-
|
75
|
-
if dependency["license"].nil? || dependency["license"].empty?
|
76
|
-
report << "Dependency '#{dependency["name"]}' version '#{dependency["version"]}' under '#{dependency_manager}' is missing license information."
|
77
|
-
end
|
78
|
-
|
79
|
-
if dependency["license_files"].empty?
|
80
|
-
report << "Dependency '#{dependency["name"]}' version '#{dependency["version"]}' under '#{dependency_manager}' is missing license files information."
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
report
|
63
|
+
Reporter.new(output_dir).report
|
86
64
|
end
|
87
65
|
|
88
66
|
private
|
@@ -0,0 +1,102 @@
|
|
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 "berkshelf"
|
19
|
+
|
20
|
+
require "license_scout/dependency_manager/base"
|
21
|
+
|
22
|
+
module LicenseScout
|
23
|
+
module DependencyManager
|
24
|
+
class Berkshelf < Base
|
25
|
+
|
26
|
+
def name
|
27
|
+
"chef_berkshelf"
|
28
|
+
end
|
29
|
+
|
30
|
+
def detected?
|
31
|
+
File.exists?(berksfile_path) && File.exists?(lockfile_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def dependencies
|
35
|
+
dependencies = []
|
36
|
+
cookbook_dependencies = nil
|
37
|
+
|
38
|
+
Dir.chdir(project_dir) do
|
39
|
+
berksfile = ::Berkshelf::Berksfile.from_file("./Berksfile")
|
40
|
+
|
41
|
+
# Berkshelf should not give an error when there are cookbooks in the
|
42
|
+
# lockfile that are no longer in the berksfile. It handles this case in
|
43
|
+
# the Installer class which we are not using here. So we handle this
|
44
|
+
# case in the same way Installer does.
|
45
|
+
berksfile.lockfile.reduce!
|
46
|
+
|
47
|
+
cookbook_dependencies = berksfile.list
|
48
|
+
end
|
49
|
+
|
50
|
+
cookbook_dependencies.each do |dep|
|
51
|
+
dependency_name = dep.name
|
52
|
+
dependency_version = dep.cached_cookbook.version
|
53
|
+
|
54
|
+
dependency_license_files = auto_detect_license_files(dep.cached_cookbook.path.to_s)
|
55
|
+
|
56
|
+
# Check license override and license_files override separately since
|
57
|
+
# only one might be set in the overrides.
|
58
|
+
dependency_license = options.overrides.license_for(name, dependency_name, dependency_version) || dep.cached_cookbook.license
|
59
|
+
|
60
|
+
override_license_files = options.overrides.license_files_for(name, dependency_name, dependency_version)
|
61
|
+
cookbook_path = dep.cached_cookbook.path.to_s
|
62
|
+
|
63
|
+
if override_license_files.empty?
|
64
|
+
dependency_license_files = auto_detect_license_files(cookbook_path)
|
65
|
+
else
|
66
|
+
dependency_license_files = override_license_files.resolve_locations(cookbook_path)
|
67
|
+
end
|
68
|
+
|
69
|
+
dependencies << Dependency.new(
|
70
|
+
dependency_name,
|
71
|
+
dependency_version,
|
72
|
+
dependency_license,
|
73
|
+
dependency_license_files
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
dependencies
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def berksfile_path
|
83
|
+
File.join(project_dir, "Berksfile")
|
84
|
+
end
|
85
|
+
|
86
|
+
def lockfile_path
|
87
|
+
File.join(project_dir, "Berksfile.lock")
|
88
|
+
end
|
89
|
+
|
90
|
+
def auto_detect_license_files(cookbook_path)
|
91
|
+
unless File.exist?(cookbook_path)
|
92
|
+
raise LicenseScout::Exceptions::InaccessibleDependency.new "Autodetected cookbook path '#{cookbook_path}' does not exist"
|
93
|
+
end
|
94
|
+
|
95
|
+
Dir.glob("#{cookbook_path}/*").select do |f|
|
96
|
+
POSSIBLE_LICENSE_FILES.include?(File.basename(f))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -32,13 +32,12 @@ require "bundler/setup"
|
|
32
32
|
# We're only using things that are in the stdlib.
|
33
33
|
require "json"
|
34
34
|
|
35
|
-
definition = ::Bundler::Definition.build("./Gemfile", "./Gemfile.lock", nil)
|
36
35
|
dependencies = []
|
37
36
|
|
38
|
-
|
37
|
+
Bundler.load.specs.each do |gem_spec|
|
39
38
|
dependencies << {
|
40
39
|
name: gem_spec.name,
|
41
|
-
version: gem_spec.version,
|
40
|
+
version: gem_spec.version.to_s,
|
42
41
|
license: gem_spec.license,
|
43
42
|
path: gem_spec.full_gem_path,
|
44
43
|
}
|
@@ -33,11 +33,13 @@ module LicenseScout
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def detected?
|
36
|
-
# We
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
|
36
|
+
# We check the existence of both Gemfile and Gemfile.lock. We need both
|
37
|
+
# of them to be able to get a concrete set of dependencies which we can
|
38
|
+
# search. We used to raise an error when Gemfile.lock did not exist but
|
39
|
+
# that created issues with projects like oc_bifrost which is a rebar
|
40
|
+
# project but have a Gemfile at its root to be able to run some rake
|
41
|
+
# commands.
|
42
|
+
File.exists?(gemfile_path) && File.exists?(lockfile_path)
|
41
43
|
end
|
42
44
|
|
43
45
|
def dependency_data
|
@@ -56,10 +58,6 @@ module LicenseScout
|
|
56
58
|
end
|
57
59
|
|
58
60
|
def dependencies
|
59
|
-
if !File.exists?(lockfile_path)
|
60
|
-
raise LicenseScout::Exceptions::DependencyManagerNotRun.new(project_dir, name)
|
61
|
-
end
|
62
|
-
|
63
61
|
dependencies = []
|
64
62
|
dependency_data.each do |gem_data|
|
65
63
|
dependency_name = gem_data["name"]
|
@@ -74,6 +72,14 @@ module LicenseScout
|
|
74
72
|
# bundler's lib/ dir, so we have to munge it.
|
75
73
|
dependency_license = "MIT"
|
76
74
|
dependency_license_files = [File.join(File.dirname(__FILE__), "bundler/LICENSE.md")]
|
75
|
+
elsif dependency_name == "json"
|
76
|
+
# json is different weird. When project is using the json that is prepackaged with
|
77
|
+
# Ruby, its included not as a full fledged gem but an *.rb file at:
|
78
|
+
# /opt/opscode/embedded/lib/ruby/2.2.0/json.rb
|
79
|
+
# Because of this its license is reported as nil and its license files can not be
|
80
|
+
# found. That is why we need to provide them manually here.
|
81
|
+
dependency_license = "Ruby"
|
82
|
+
dependency_license_files = [File.join(File.dirname(__FILE__), "json/README.md")]
|
77
83
|
else
|
78
84
|
# Check license override and license_files override separately since
|
79
85
|
# only one might be set in the overrides.
|
@@ -0,0 +1,321 @@
|
|
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 "rexml/document"
|
19
|
+
|
20
|
+
require "ffi_yajl"
|
21
|
+
require "psych"
|
22
|
+
require "mixlib/shellout"
|
23
|
+
|
24
|
+
require "license_scout/dependency_manager/base"
|
25
|
+
require "license_scout/net_fetcher"
|
26
|
+
require "license_scout/exceptions"
|
27
|
+
require "license_scout/dependency"
|
28
|
+
|
29
|
+
module LicenseScout
|
30
|
+
module DependencyManager
|
31
|
+
class CPAN < Base
|
32
|
+
|
33
|
+
class CPANDependency
|
34
|
+
|
35
|
+
LICENSE_TYPE_MAP = {
|
36
|
+
"perl_5" => "Perl-5",
|
37
|
+
"perl" => "Perl-5",
|
38
|
+
"apache_2_0" => "Apache-2.0",
|
39
|
+
"artistic_2" => "Artistic-2.0",
|
40
|
+
"gpl_3" => "GPL-3.0",
|
41
|
+
}.freeze
|
42
|
+
|
43
|
+
attr_reader :module_name
|
44
|
+
attr_reader :dist
|
45
|
+
attr_reader :version
|
46
|
+
attr_reader :cpanfile
|
47
|
+
|
48
|
+
attr_reader :license_files
|
49
|
+
attr_reader :license
|
50
|
+
|
51
|
+
attr_reader :cache_root
|
52
|
+
|
53
|
+
attr_reader :overrides
|
54
|
+
|
55
|
+
def initialize(module_name:, dist:, version:, cpanfile:, cache_root:, overrides:)
|
56
|
+
@module_name = module_name
|
57
|
+
@dist = dist
|
58
|
+
@version = version
|
59
|
+
@cpanfile = cpanfile
|
60
|
+
@cache_root = cache_root
|
61
|
+
@overrides = overrides
|
62
|
+
|
63
|
+
@deps_list = nil
|
64
|
+
|
65
|
+
@license = nil
|
66
|
+
@license_files = []
|
67
|
+
end
|
68
|
+
|
69
|
+
def desc
|
70
|
+
"#{module_name} in #{dist} (#{version}) [#{license}]"
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_dep
|
74
|
+
Dependency.new(
|
75
|
+
# we use dist for the name because there can be multiple modules in
|
76
|
+
# a dist, but the dist is the unit of packaging and licensing
|
77
|
+
dist,
|
78
|
+
version,
|
79
|
+
license,
|
80
|
+
license_files
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
def collect_licenses
|
85
|
+
ensure_cached
|
86
|
+
Dir.mktmpdir do |tmpdir|
|
87
|
+
FileUtils.cp(distribution_fullpath, tmpdir)
|
88
|
+
Dir.chdir(tmpdir) do
|
89
|
+
untar!
|
90
|
+
distribution_unpack_fullpath = File.join(tmpdir, distribution_unpack_relpath)
|
91
|
+
collect_licenses_in(distribution_unpack_fullpath)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def ensure_cached
|
97
|
+
cache_path = File.join(dist_cache_root, cpanfile)
|
98
|
+
|
99
|
+
# CPAN download URL is like:
|
100
|
+
# http://www.cpan.org/authors/id/R/RJ/RJBS/Sub-Install-0.928.tar.gz
|
101
|
+
# cpanfile is like:
|
102
|
+
# R/RJ/RJBS/Sub-Install-0.928.tar.gz
|
103
|
+
unless File.exist?(cache_path)
|
104
|
+
|
105
|
+
url = "http://www.cpan.org/authors/id/#{cpanfile}"
|
106
|
+
tmp_path = NetFetcher.cache(url)
|
107
|
+
|
108
|
+
FileUtils.mkdir_p(File.dirname(cache_path))
|
109
|
+
FileUtils.cp(tmp_path, cache_path)
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def distribution_filename
|
115
|
+
File.basename(cpanfile)
|
116
|
+
end
|
117
|
+
|
118
|
+
def distribution_unpack_relpath
|
119
|
+
# Most packages have tar.gz extension but some have .tgz like
|
120
|
+
# IO-Pager-0.36.tgz
|
121
|
+
[".tar.gz", ".tgz"].each do |ext|
|
122
|
+
if distribution_filename.end_with?(ext)
|
123
|
+
return File.basename(distribution_filename, ext)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def distribution_fullpath
|
129
|
+
File.join(dist_cache_root, cpanfile)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Untar the distribution.
|
133
|
+
#
|
134
|
+
# NOTE: On some platforms, you only get a usable version of tar as
|
135
|
+
# `gtar`, and on windows, symlinks break a lot of stuff. We (Chef
|
136
|
+
# Software) currently only use perl in server products, which we only
|
137
|
+
# build for a handful of Linux distros, so this is sufficient.
|
138
|
+
def untar!
|
139
|
+
s = Mixlib::ShellOut.new("tar zxf #{distribution_filename}")
|
140
|
+
s.run_command
|
141
|
+
s.error!
|
142
|
+
s.stdout
|
143
|
+
end
|
144
|
+
|
145
|
+
def collect_licenses_in(unpack_path)
|
146
|
+
collect_license_info_in(unpack_path)
|
147
|
+
collect_license_files_info_in(unpack_path)
|
148
|
+
end
|
149
|
+
|
150
|
+
def collect_license_info_in(unpack_path)
|
151
|
+
# Notice that we use "dist" as the dependency name
|
152
|
+
# See #to_dep for details.
|
153
|
+
@license = overrides.license_for("perl_cpan", dist, version) || begin
|
154
|
+
metadata = if File.exist?(meta_json_in(unpack_path))
|
155
|
+
slurp_meta_json_in(unpack_path)
|
156
|
+
elsif File.exist?(meta_yaml_in(unpack_path))
|
157
|
+
slurp_meta_yaml_in(unpack_path)
|
158
|
+
end
|
159
|
+
|
160
|
+
if metadata && metadata.key?("license")
|
161
|
+
given_type = Array(metadata["license"]).reject { |l| l == "unknown" }.first
|
162
|
+
normalize_license_type(given_type)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def collect_license_files_info_in(unpack_path)
|
168
|
+
override_license_files = overrides.license_files_for("perl_cpan", dist, version)
|
169
|
+
|
170
|
+
license_files = if override_license_files.empty?
|
171
|
+
find_license_files_in(unpack_path)
|
172
|
+
else
|
173
|
+
override_license_files.resolve_locations(unpack_path)
|
174
|
+
end
|
175
|
+
|
176
|
+
license_files.each do |f|
|
177
|
+
@license_files << cache_license_file(f)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Copy license file to the cache. We unpack the CPAN dists in a tempdir
|
182
|
+
# and throw it away after we've inspected the contents, so we need to
|
183
|
+
# put the license file somewhere it can be copied from later.
|
184
|
+
def cache_license_file(unpacked_file)
|
185
|
+
basename = File.basename(unpacked_file)
|
186
|
+
license_cache_path = File.join(license_cache_root, "#{dist}-#{basename}")
|
187
|
+
FileUtils.mkdir_p(license_cache_root)
|
188
|
+
FileUtils.cp(unpacked_file, license_cache_path)
|
189
|
+
# In some cases, the license files get unpacked with 0444
|
190
|
+
# permissions which could make a re-run fail on the `cp` step.
|
191
|
+
FileUtils.chmod(0644, license_cache_path)
|
192
|
+
license_cache_path
|
193
|
+
end
|
194
|
+
|
195
|
+
def slurp_meta_yaml_in(unpack_path)
|
196
|
+
Psych.safe_load(File.read(meta_yaml_in(unpack_path)))
|
197
|
+
end
|
198
|
+
|
199
|
+
def slurp_meta_json_in(unpack_path)
|
200
|
+
FFI_Yajl::Parser.parse(File.read(meta_json_in(unpack_path)))
|
201
|
+
end
|
202
|
+
|
203
|
+
def license_cache_root
|
204
|
+
File.join(cache_root, "cpan-licenses")
|
205
|
+
end
|
206
|
+
|
207
|
+
def dist_cache_root
|
208
|
+
File.join(cache_root, "cpan-dists")
|
209
|
+
end
|
210
|
+
|
211
|
+
def normalize_license_type(given_type)
|
212
|
+
LICENSE_TYPE_MAP[given_type] || given_type
|
213
|
+
end
|
214
|
+
|
215
|
+
def meta_json_in(unpack_path)
|
216
|
+
File.join(unpack_path, "META.json")
|
217
|
+
end
|
218
|
+
|
219
|
+
def mymeta_json_in(unpack_path)
|
220
|
+
File.join(unpack_path, "MYMETA.json")
|
221
|
+
end
|
222
|
+
|
223
|
+
def meta_yaml_in(unpack_path)
|
224
|
+
File.join(unpack_path, "META.yml")
|
225
|
+
end
|
226
|
+
|
227
|
+
def find_license_files_in(unpack_path)
|
228
|
+
Dir["#{unpack_path}/*"].select do |f|
|
229
|
+
CPAN::POSSIBLE_LICENSE_FILES.include?(File.basename(f))
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
def initialize(*args, &block)
|
236
|
+
super
|
237
|
+
@dependencies = nil
|
238
|
+
end
|
239
|
+
|
240
|
+
def name
|
241
|
+
"perl_cpan"
|
242
|
+
end
|
243
|
+
|
244
|
+
def dependencies
|
245
|
+
return @dependencies if @dependencies
|
246
|
+
@dependencies = deps_list.map do |d|
|
247
|
+
d.collect_licenses
|
248
|
+
d.to_dep
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def deps_list
|
253
|
+
return @deps_list if @deps_list
|
254
|
+
|
255
|
+
xml_doc = REXML::Document.new(dependency_graph_xml)
|
256
|
+
|
257
|
+
root = xml_doc.root
|
258
|
+
|
259
|
+
deps = root.get_elements("//dependency")
|
260
|
+
|
261
|
+
@deps_list = []
|
262
|
+
|
263
|
+
deps.each do |dep|
|
264
|
+
dep_module_name = dep.get_text("module").to_s
|
265
|
+
next if dep_module_name == module_name
|
266
|
+
@deps_list << CPANDependency.new(
|
267
|
+
module_name: dep_module_name,
|
268
|
+
dist: dep.get_text("dist").to_s,
|
269
|
+
version: dep.get_text("distversion").to_s,
|
270
|
+
cpanfile: dep.get_text("cpanfile").to_s,
|
271
|
+
cache_root: options.cpan_cache,
|
272
|
+
overrides: options.overrides
|
273
|
+
)
|
274
|
+
end
|
275
|
+
|
276
|
+
@deps_list
|
277
|
+
end
|
278
|
+
|
279
|
+
def dependency_graph_xml
|
280
|
+
@dependency_graph_xml ||=
|
281
|
+
begin
|
282
|
+
dependency_graph_xml_file = NetFetcher.cache(dependency_graph_url)
|
283
|
+
raw_xml = File.read(dependency_graph_xml_file)
|
284
|
+
FileUtils.rm_f(dependency_graph_xml_file)
|
285
|
+
raw_xml
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
# NOTE: there's no SSL version available. Take care handling any
|
290
|
+
# data/code referenced in responses from this site.
|
291
|
+
def dependency_graph_url
|
292
|
+
"http://deps.cpantesters.org/?xml=1;module=#{module_name};perl=5.24.0;os=any%20OS;pureperl=0"
|
293
|
+
end
|
294
|
+
|
295
|
+
# Infers the module name from the directory name. For Chef Server, the
|
296
|
+
# two perl packages we use are:
|
297
|
+
# * "App-Sqitch-VERSION" => "App::Sqitch"
|
298
|
+
# * "DBD-Pg-VERSION" => "DBD::Pg"
|
299
|
+
#
|
300
|
+
# NOTE: Distributions may contain multiple modules that would each have
|
301
|
+
# their own dependency graphs and it's possible to get a perl project
|
302
|
+
# that doesn't obey this convention (e.g., if you git clone it). But this
|
303
|
+
# meets our immediate needs.
|
304
|
+
def module_name
|
305
|
+
File.basename(project_dir).split("-")[0...-1].join("::")
|
306
|
+
end
|
307
|
+
|
308
|
+
# NOTE: it's possible that projects won't have a META.yml, but the two
|
309
|
+
# that we care about for Chef Server do have one. As of 2015, 84% of perl
|
310
|
+
# distribution packages have one: http://neilb.org/2015/10/18/spotters-guide.html
|
311
|
+
def detected?
|
312
|
+
File.exist?(meta_yml_path)
|
313
|
+
end
|
314
|
+
|
315
|
+
def meta_yml_path
|
316
|
+
File.join(project_dir, "META.yml")
|
317
|
+
end
|
318
|
+
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|