licensed 2.14.3 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +125 -29
- data/.github/workflows/test.yml +42 -42
- data/.gitignore +1 -0
- data/CHANGELOG.md +45 -3
- data/README.md +14 -3
- data/docker/Dockerfile.build-linux +1 -0
- data/docs/{migrating_to_newer_versions.md → migrations/v2.md} +1 -1
- data/docs/migrations/v3.md +109 -0
- data/docs/sources/bundler.md +1 -11
- data/docs/sources/npm.md +1 -1
- data/lib/licensed/cli.rb +12 -3
- data/lib/licensed/commands/list.rb +7 -0
- data/lib/licensed/reporters/list_reporter.rb +3 -1
- data/lib/licensed/sources/bundler.rb +33 -206
- data/lib/licensed/sources/bundler/missing_specification.rb +54 -0
- data/lib/licensed/sources/cabal.rb +17 -6
- data/lib/licensed/sources/manifest.rb +1 -1
- data/lib/licensed/sources/npm.rb +57 -7
- data/lib/licensed/sources/pip.rb +1 -1
- data/lib/licensed/version.rb +1 -1
- data/script/packages/build +4 -1
- data/script/packages/linux +4 -0
- data/script/packages/mac +3 -0
- data/script/source-setup/npm +18 -1
- metadata +6 -4
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/match_platform"
|
4
|
+
|
5
|
+
# Bundler normally raises a "GemNotFound" error when a specification
|
6
|
+
# can't be materialized which halts bundler dependency enumeration.
|
7
|
+
|
8
|
+
# This monkey patch instead creates MissingSpecification objects to
|
9
|
+
# identify missing specs without raising errors and halting enumeration.
|
10
|
+
# It was the most minimal-touch solution I could think of that should reliably
|
11
|
+
# work across many bundler versions
|
12
|
+
|
13
|
+
module Licensed
|
14
|
+
module Bundler
|
15
|
+
class MissingSpecification < Gem::BasicSpecification
|
16
|
+
include ::Bundler::MatchPlatform
|
17
|
+
|
18
|
+
attr_reader :name, :version, :platform, :source
|
19
|
+
def initialize(name:, version:, platform:, source:)
|
20
|
+
@name = name
|
21
|
+
@version = version
|
22
|
+
@platform = platform
|
23
|
+
@source = source
|
24
|
+
end
|
25
|
+
|
26
|
+
def dependencies
|
27
|
+
[]
|
28
|
+
end
|
29
|
+
|
30
|
+
def gem_dir; end
|
31
|
+
def gems_dir
|
32
|
+
Gem.dir
|
33
|
+
end
|
34
|
+
def summary; end
|
35
|
+
def homepage; end
|
36
|
+
|
37
|
+
def error
|
38
|
+
"could not find #{name} (#{version}) in any sources"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module Bundler
|
45
|
+
class LazySpecification
|
46
|
+
alias_method :orig_materialize, :__materialize__
|
47
|
+
def __materialize__
|
48
|
+
spec = orig_materialize
|
49
|
+
return spec if spec
|
50
|
+
|
51
|
+
Licensed::Bundler:: MissingSpecification.new(name: name, version: version, platform: platform, source: source)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -222,14 +222,25 @@ module Licensed
|
|
222
222
|
|
223
223
|
# Returns a package info structure with an error set
|
224
224
|
def missing_package(id)
|
225
|
-
name,
|
226
|
-
id.rpartition("-") # e.g. to match the right-most dash from ipid fused-effects-1.0.0.0
|
227
|
-
else
|
228
|
-
id.partition(/\s/) # e.g. to match the left-most space from constraint fused-effects > 1.0.0.0
|
229
|
-
end
|
230
|
-
|
225
|
+
name, version = package_id_name_version(id)
|
231
226
|
{ "name" => name, "version" => version, "error" => "package not found" }
|
232
227
|
end
|
228
|
+
|
229
|
+
# Parses the name and version pieces from an id or package requirement string
|
230
|
+
def package_id_name_version(id)
|
231
|
+
name, version = id.split(" ", 2)
|
232
|
+
return [name, version] if version
|
233
|
+
|
234
|
+
# split by dashes, find the rightmost thing that looks like an
|
235
|
+
parts = id.split("-")
|
236
|
+
version_start_index = parts.rindex { |part| part.match?(/^[\d\.]+$/) }
|
237
|
+
return [id, nil] if version_start_index.nil?
|
238
|
+
|
239
|
+
[
|
240
|
+
parts[0...version_start_index].join("-"),
|
241
|
+
parts[version_start_index..-1].join("-")
|
242
|
+
]
|
243
|
+
end
|
233
244
|
end
|
234
245
|
end
|
235
246
|
end
|
@@ -170,7 +170,7 @@ module Licensed
|
|
170
170
|
def all_files
|
171
171
|
# remove files if they are tracked but don't exist on the file system
|
172
172
|
@all_files ||= Set.new(Licensed::Git.files || [])
|
173
|
-
.delete_if { |f| !File.exist?(f) }
|
173
|
+
.delete_if { |f| !File.exist?(File.join(Licensed::Git.repository_root, f)) }
|
174
174
|
end
|
175
175
|
|
176
176
|
class Dependency < Licensed::Dependency
|
data/lib/licensed/sources/npm.rb
CHANGED
@@ -4,6 +4,25 @@ require "json"
|
|
4
4
|
module Licensed
|
5
5
|
module Sources
|
6
6
|
class NPM < Source
|
7
|
+
class Dependency < ::Licensed::Dependency
|
8
|
+
# override license_metadata to pull homepage and summary information
|
9
|
+
# from a packages package.json file, if it exists
|
10
|
+
# this accounts for the lack of this information in npm 7's `npm list` output
|
11
|
+
def license_metadata
|
12
|
+
data = super
|
13
|
+
return data if !data["homepage"].to_s.empty? && !data["summary"].to_s.empty?
|
14
|
+
|
15
|
+
package_json_path = File.join(path, "package.json")
|
16
|
+
return data unless File.exist?(package_json_path)
|
17
|
+
|
18
|
+
package_json = JSON.parse(File.read(package_json_path))
|
19
|
+
data["homepage"] = package_json["homepage"]
|
20
|
+
data["summary"] = package_json["description"]
|
21
|
+
|
22
|
+
data
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
7
26
|
def self.type
|
8
27
|
"npm"
|
9
28
|
end
|
@@ -50,6 +69,9 @@ module Licensed
|
|
50
69
|
dependencies.each do |name, dependency|
|
51
70
|
next if dependency["peerMissing"]
|
52
71
|
next if yarn_lock_present && dependency["missing"]
|
72
|
+
next if dependency["extraneous"] && dependency["missing"]
|
73
|
+
|
74
|
+
dependency["name"] = name
|
53
75
|
(result[name] ||= []) << dependency
|
54
76
|
recursive_dependencies(dependency["dependencies"] || {}, result)
|
55
77
|
end
|
@@ -59,22 +81,50 @@ module Licensed
|
|
59
81
|
# Returns parsed package metadata returned from `npm list`
|
60
82
|
def package_metadata
|
61
83
|
return @package_metadata if defined?(@package_metadata)
|
84
|
+
@package_metadata = JSON.parse(package_metadata_command)
|
85
|
+
rescue JSON::ParserError => e
|
86
|
+
message = "Licensed was unable to parse the output from 'npm list'. JSON Error: #{e.message}"
|
87
|
+
npm_error = package_metadata_error
|
88
|
+
message = "#{message}. npm Error: #{npm_error}" if npm_error
|
89
|
+
raise Licensed::Sources::Source::Error, message
|
90
|
+
end
|
62
91
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
92
|
+
# Returns an error, if one exists, from running `npm list` to get package metadata
|
93
|
+
def package_metadata_error
|
94
|
+
Licensed::Shell.execute("npm", "list", *package_metadata_args)
|
95
|
+
return ""
|
96
|
+
rescue Licensed::Shell::Error => e
|
97
|
+
return e.message
|
69
98
|
end
|
70
99
|
|
71
100
|
# Returns the output from running `npm list` to get package metadata
|
72
101
|
def package_metadata_command
|
73
102
|
args = %w(--json --long)
|
74
|
-
args
|
103
|
+
args.concat(package_metadata_args)
|
104
|
+
|
75
105
|
Licensed::Shell.execute("npm", "list", *args, allow_failure: true)
|
76
106
|
end
|
77
107
|
|
108
|
+
# Returns an array of arguments that should be used for all `npm list`
|
109
|
+
# calls, regardless of how the output is formatted
|
110
|
+
def package_metadata_args
|
111
|
+
args = []
|
112
|
+
args << "--production" unless include_non_production?
|
113
|
+
|
114
|
+
# on npm 7+, the --all argument is necessary to evaluate the project's
|
115
|
+
# full dependency tree
|
116
|
+
args << "--all" if npm_version >= Gem::Version.new("7.0.0")
|
117
|
+
|
118
|
+
return args
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns the currently installed version of npm as a Gem::Version object
|
122
|
+
def npm_version
|
123
|
+
@npm_version ||= begin
|
124
|
+
Gem::Version.new(Licensed::Shell.execute("npm", "-v").strip)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
78
128
|
# Returns true if a yarn.lock file exists in the current directory
|
79
129
|
def yarn_lock_present
|
80
130
|
@yarn_lock_present ||= File.exist?(config.pwd.join("yarn.lock"))
|
data/lib/licensed/sources/pip.rb
CHANGED
@@ -8,7 +8,7 @@ module Licensed
|
|
8
8
|
module Sources
|
9
9
|
class Pip < Source
|
10
10
|
VERSION_OPERATORS = %w(< > <= >= == !=).freeze
|
11
|
-
PACKAGE_REGEX = /^([\w
|
11
|
+
PACKAGE_REGEX = /^([\w\.-]+)(#{VERSION_OPERATORS.join("|")})?/
|
12
12
|
|
13
13
|
def enabled?
|
14
14
|
return unless virtual_env_pip && Licensed::Shell.tool_available?(virtual_env_pip)
|
data/lib/licensed/version.rb
CHANGED
data/script/packages/build
CHANGED
@@ -51,8 +51,11 @@ cd $COPY_DIR
|
|
51
51
|
trap "git checkout $CURRENT_BRANCH" EXIT
|
52
52
|
fi
|
53
53
|
|
54
|
+
# get the openssl dir to use when building based on ruby's default ssl cert dir
|
55
|
+
OPENSSL_DIR="$(cd "$(ruby -e 'require "net/https"; puts OpenSSL::X509::DEFAULT_CERT_DIR')/.." && pwd)"
|
56
|
+
|
54
57
|
# build the licensed rubyc executable
|
55
|
-
"$RUBYC" --clean-tmpdir -o "$BUILD_DIR/licensed" "$COPY_DIR/exe/licensed"
|
58
|
+
"$RUBYC" --openssl-dir "$OPENSSL_DIR" --clean-tmpdir -o "$BUILD_DIR/licensed" "$COPY_DIR/exe/licensed"
|
56
59
|
chmod +x $BUILD_DIR/licensed
|
57
60
|
)
|
58
61
|
|
data/script/packages/linux
CHANGED
@@ -34,6 +34,9 @@ build_linux_local() {
|
|
34
34
|
sudo apt-get update
|
35
35
|
sudo apt-get install -y --no-install-recommends cmake make gcc pkg-config squashfs-tools curl bison git rsync
|
36
36
|
|
37
|
+
sudo gem update --system
|
38
|
+
sudo gem update bundler
|
39
|
+
|
37
40
|
RUBYC="$BASE_DIR/bin/rubyc-linux"
|
38
41
|
if [ ! -f "$RUBYC" ]; then
|
39
42
|
mkdir -p "$(dirname "$RUBYC")"
|
@@ -42,6 +45,7 @@ build_linux_local() {
|
|
42
45
|
fi
|
43
46
|
|
44
47
|
export CPPFLAGS="-P"
|
48
|
+
export SSL_CERT_DIR="/etc/ssl/certs"
|
45
49
|
export RUBYC
|
46
50
|
"$BASE_DIR"/script/packages/build
|
47
51
|
}
|
data/script/packages/mac
CHANGED
@@ -28,6 +28,9 @@ brew update
|
|
28
28
|
brew list "squashfs" &>/dev/null || brew install "squashfs"
|
29
29
|
brew list "pkg-config" &>/dev/null || brew install "pkg-config"
|
30
30
|
|
31
|
+
gem update --system
|
32
|
+
gem update bundler
|
33
|
+
|
31
34
|
if [ ! -f "$RUBYC" ]; then
|
32
35
|
mkdir -p "$(dirname "$RUBYC")"
|
33
36
|
curl -L https://github.com/kontena/ruby-packer/releases/download/2.6.0-0.6.0/rubyc-2.6.0-0.6.0-osx-amd64.gz | gunzip > "$RUBYC"
|
data/script/source-setup/npm
CHANGED
@@ -10,8 +10,25 @@ fi
|
|
10
10
|
BASE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
11
11
|
cd $BASE_PATH/test/fixtures/npm
|
12
12
|
|
13
|
+
FORCE=""
|
13
14
|
if [ "$1" == "-f" ]; then
|
14
|
-
|
15
|
+
FORCE=1
|
16
|
+
fi
|
17
|
+
|
18
|
+
NPM_MAJOR_VERSION="$(npm -v | cut -d'.' -f1)"
|
19
|
+
if [ "$NPM_MAJOR_VERSION" -ge "7" ]; then
|
20
|
+
PACKAGE_JSON_SRC="package.json.npm7"
|
21
|
+
else
|
22
|
+
PACKAGE_JSON_SRC="package.json.npm6"
|
23
|
+
fi
|
24
|
+
|
25
|
+
if [ ! -f "package.json" ] || [ "$(cat package.json | md5sum )" != "$(cat "$PACKAGE_JSON_SRC" | md5sum)" ]; then
|
26
|
+
FORCE=1
|
27
|
+
cp -f "$PACKAGE_JSON_SRC" package.json
|
28
|
+
fi
|
29
|
+
|
30
|
+
if [ -n "$FORCE" ]; then
|
31
|
+
find . -not -regex "\.*" -and -not -name "package\.json*" -print0 | xargs -0 rm -rf
|
15
32
|
fi
|
16
33
|
|
17
34
|
npm install
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: licensed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: licensee
|
@@ -243,7 +243,8 @@ files:
|
|
243
243
|
- docs/adding_a_new_source.md
|
244
244
|
- docs/commands.md
|
245
245
|
- docs/configuration.md
|
246
|
-
- docs/
|
246
|
+
- docs/migrations/v2.md
|
247
|
+
- docs/migrations/v3.md
|
247
248
|
- docs/packaging.md
|
248
249
|
- docs/reporters.md
|
249
250
|
- docs/sources/bower.md
|
@@ -290,6 +291,7 @@ files:
|
|
290
291
|
- lib/licensed/sources.rb
|
291
292
|
- lib/licensed/sources/bower.rb
|
292
293
|
- lib/licensed/sources/bundler.rb
|
294
|
+
- lib/licensed/sources/bundler/missing_specification.rb
|
293
295
|
- lib/licensed/sources/cabal.rb
|
294
296
|
- lib/licensed/sources/composer.rb
|
295
297
|
- lib/licensed/sources/dep.rb
|
@@ -348,7 +350,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
348
350
|
- !ruby/object:Gem::Version
|
349
351
|
version: '0'
|
350
352
|
requirements: []
|
351
|
-
rubygems_version: 3.0.3
|
353
|
+
rubygems_version: 3.0.3.1
|
352
354
|
signing_key:
|
353
355
|
specification_version: 4
|
354
356
|
summary: Extract and validate the licenses of dependencies.
|