licensed 2.14.3 → 3.0.0
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/.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.
|