licensed 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.licensed.yml +7 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +14 -0
- data/Rakefile +2 -5
- data/docker/Dockerfile.build-linux +4 -1
- data/docs/adding_a_new_source.md +11 -0
- data/docs/sources/gradle.md +16 -0
- data/lib/licensed/commands/cache.rb +5 -0
- data/lib/licensed/dependency.rb +28 -47
- data/lib/licensed/migrations/v2.rb +3 -1
- data/lib/licensed/sources.rb +1 -0
- data/lib/licensed/sources/bundler.rb +56 -2
- data/lib/licensed/sources/gradle.rb +183 -0
- data/lib/licensed/version.rb +1 -1
- data/licensed.gemspec +2 -1
- data/script/packages/build +92 -0
- data/script/packages/linux +8 -6
- data/script/packages/mac +7 -5
- metadata +26 -3
- data/script/build-rubyc-exe +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7f39c048283d853075674325f0d371edaf124a8
|
4
|
+
data.tar.gz: 60530129f47ed34f51cac3152be83aab27e32a01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b2bc431aea2a64f3f12139d533914ad2de740cc5eb00310166dbfa6160fc5a6821d73faf214ceb49fcb6207d9c695561fc44a9ff21e146d88cc4f4eb7de0d38
|
7
|
+
data.tar.gz: 53db8e3e0272e976428471bbe0f5a2c6e54cdb7743b2e309ac8b2d839a352073fb8a81026e8bc19838f155a09d0b2a74097736ee6e68bc4152eb2124177ceb7e
|
data/.licensed.yml
ADDED
data/.travis.yml
CHANGED
@@ -93,5 +93,10 @@ matrix:
|
|
93
93
|
script: ./script/test git_submodule
|
94
94
|
env: NAME="git_submodule"
|
95
95
|
|
96
|
+
- language: java
|
97
|
+
before_script: ./test/fixtures/gradle/gradlew --quiet --version
|
98
|
+
script: ./script/test gradle
|
99
|
+
env: NAME="gradle"
|
100
|
+
|
96
101
|
notifications:
|
97
102
|
disable: true
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## 2.1.0 - 2019-04-16
|
10
|
+
|
11
|
+
### Added
|
12
|
+
- New Gradle dependency source enumerator (:tada: @dbussink https://github.com/github/licensed/pull/150, @jandersson-svt https://github.com/github/licensed/pull/159)
|
13
|
+
- Metadata added to distributed packages (https://github.com/github/licensed/pull/160)
|
14
|
+
|
15
|
+
### Changes
|
16
|
+
- Bundler dependency source loads license key from a gem's cached gemspec file as a fallback (https://github.com/github/licensed/pull/154)
|
17
|
+
- Licensed will only raise errors on an empty dependency path when caching records (https://github.com/github/licensed/pull/149)
|
18
|
+
|
19
|
+
### Fixed
|
20
|
+
- Migrating to v2 will no longer crash trying to migrate cached records that don't exist (https://github.com/github/licensed/pull/148)
|
21
|
+
- Reported warnings will no longer crash licensed when caching records (https://github.com/github/licensed/pull/147)
|
22
|
+
|
9
23
|
## 2.0.1 - 2019-02-14
|
10
24
|
|
11
25
|
### Changes
|
data/Rakefile
CHANGED
@@ -44,11 +44,7 @@ namespace :test do
|
|
44
44
|
t.description = "Run #{source} tests"
|
45
45
|
t.libs << "test"
|
46
46
|
t.libs << "lib"
|
47
|
-
|
48
|
-
# use negative lookahead to exclude all source tests except
|
49
|
-
# the tests for `source`
|
50
|
-
t.test_files = FileList["test/**/*_test.rb"].exclude(/test\/sources\/(?!#{source}).*?_test.rb/,
|
51
|
-
"test/fixtures/**/*_test.rb")
|
47
|
+
t.test_files = FileList["test/commands/*_test.rb", "test/sources/#{source}_test.rb"]
|
52
48
|
end
|
53
49
|
end
|
54
50
|
end
|
@@ -61,6 +57,7 @@ end
|
|
61
57
|
|
62
58
|
packages_search = File.expand_path("script/packages/*", __dir__)
|
63
59
|
platforms = Dir[packages_search].map { |f| File.basename(f, ".*") }
|
60
|
+
.reject { |f| f == "build" }
|
64
61
|
|
65
62
|
namespace :package do
|
66
63
|
platforms.each do |platform|
|
@@ -1,11 +1,14 @@
|
|
1
1
|
FROM ruby:2.4-slim-stretch
|
2
2
|
|
3
3
|
RUN apt-get update \
|
4
|
-
&& apt-get install -y --no-install-recommends cmake make gcc pkg-config squashfs-tools git curl bison \
|
4
|
+
&& apt-get install -y --no-install-recommends cmake make gcc pkg-config squashfs-tools git curl bison rsync \
|
5
5
|
&& rm -rf /var/lib/apt/lists/*
|
6
6
|
|
7
7
|
RUN curl -L http://enclose.io/rubyc/rubyc-linux-x64.gz | gunzip > /usr/local/bin/rubyc \
|
8
8
|
&& chmod +x /usr/local/bin/rubyc
|
9
9
|
|
10
|
+
RUN gem update --system && gem update bundler
|
11
|
+
|
10
12
|
ENV CPPFLAGS="-P"
|
11
13
|
ENV RUBYC="/usr/local/bin/rubyc"
|
14
|
+
ENV LANG=C.UTF-8
|
data/docs/adding_a_new_source.md
CHANGED
@@ -71,6 +71,17 @@ Creating a new `Licensed::Dependency` object requires name, version, and path ar
|
|
71
71
|
6. errors (optional)
|
72
72
|
- Any errors found when loading dependency information.
|
73
73
|
|
74
|
+
##### Creating specialized Dependency objects
|
75
|
+
|
76
|
+
`Licensed::Dependency` objects inherit from `Licensee::Projects::FsProject` and can override or extend the default `Licensee` behavior to find files for a dependency.
|
77
|
+
|
78
|
+
If a dependency source requires customized logic when finding or loading license or legal content, the source should define and use a `Licensed::Dependency` subclass to implement the required logic.
|
79
|
+
|
80
|
+
For examples of this see:
|
81
|
+
|
82
|
+
- [Manifest::Dependency](../../lib/licensed/sources/manifest.rb) which finds license text from C-style comments
|
83
|
+
- [Gradle::Dependency](../../lib/licensed/sources/gradle.rb) which loads license text from a URI
|
84
|
+
|
74
85
|
#### Finding licenses
|
75
86
|
|
76
87
|
In some cases, license content will be in a parent directory of the specified location. For instance, this can happen with Golang packages
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Gradle
|
2
|
+
|
3
|
+
The gradle source will detect dependencies when a `build.gradle` file is found along with either `gradle` or `gradlew` executables being available. The source uses the [Gradle-License-Report](https://github.com/jk1/Gradle-License-Report) plugin to enumerate dependencies and locate their licensing information.
|
4
|
+
|
5
|
+
An active network connection is required when running the `licensed cache` command with the gradle source. Gradle packages generally do not include license text or other legal notices, and additional network requests are needed to find and pull the necessary license content.
|
6
|
+
|
7
|
+
### Setting dependency configurations to load
|
8
|
+
|
9
|
+
The `gradle.configurations` property is used to determine which dependencies are fetched to load license information. The default configurations are `"runtime"` and `"runtimeClassPath"`.
|
10
|
+
|
11
|
+
```yml
|
12
|
+
gradle:
|
13
|
+
configurations:
|
14
|
+
- runtime
|
15
|
+
- runtimeClassPath
|
16
|
+
```
|
@@ -32,6 +32,11 @@ module Licensed
|
|
32
32
|
#
|
33
33
|
# Returns true.
|
34
34
|
def evaluate_dependency(app, source, dependency, report)
|
35
|
+
if dependency.path.empty?
|
36
|
+
report.errors << "dependency path not found"
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
|
35
40
|
filename = app.cache_path.join(source.class.type, "#{dependency.name}.#{DependencyRecord::EXTENSION}")
|
36
41
|
cached_record = Licensed::DependencyRecord.read(filename)
|
37
42
|
if options[:force] || save_dependency_record?(dependency, cached_record)
|
data/lib/licensed/dependency.rb
CHANGED
@@ -8,6 +8,7 @@ module Licensed
|
|
8
8
|
attr_reader :name
|
9
9
|
attr_reader :version
|
10
10
|
attr_reader :errors
|
11
|
+
attr_reader :path
|
11
12
|
|
12
13
|
# Create a new project dependency
|
13
14
|
#
|
@@ -21,23 +22,16 @@ module Licensed
|
|
21
22
|
# Returns a new dependency object. Dependency metadata and license contents
|
22
23
|
# are available if no errors are set on the dependency.
|
23
24
|
def initialize(name:, version:, path:, search_root: nil, metadata: {}, errors: [])
|
24
|
-
# check the path for default errors if no other errors
|
25
|
-
# were found when loading the dependency
|
26
|
-
if errors.empty? && path.to_s.empty?
|
27
|
-
errors.push("dependency path not found")
|
28
|
-
end
|
29
|
-
|
30
25
|
@name = name
|
31
26
|
@version = version
|
32
27
|
@metadata = metadata
|
33
28
|
@errors = errors
|
34
|
-
|
35
|
-
|
36
|
-
return if errors.any?
|
29
|
+
path = path.to_s
|
30
|
+
@path = path
|
37
31
|
|
38
32
|
# enforcing absolute paths makes life much easier when determining
|
39
33
|
# an absolute file path in #notices
|
40
|
-
if !Pathname.new(path).absolute?
|
34
|
+
if File.exist?(path) && !Pathname.new(path).absolute?
|
41
35
|
# this is an internal error related to source implementation and
|
42
36
|
# should be raised, not stored to be handled by reporters
|
43
37
|
raise ArgumentError, "dependency path #{path} must be absolute"
|
@@ -52,13 +46,7 @@ module Licensed
|
|
52
46
|
# but they can still find license contents between the given path and
|
53
47
|
# the search root
|
54
48
|
# @root is defined
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
# Returns the location of this dependency on the local disk
|
59
|
-
def path
|
60
|
-
# exposes the private method Licensee::Projects::FSProject#dir_path
|
61
|
-
dir_path
|
49
|
+
File.exist?(path) || File.exist?(@root)
|
62
50
|
end
|
63
51
|
|
64
52
|
# Returns true if the dependency has any errors, false otherwise
|
@@ -68,7 +56,6 @@ module Licensed
|
|
68
56
|
|
69
57
|
# Returns a record for this dependency including metadata and legal contents
|
70
58
|
def record
|
71
|
-
return nil if errors?
|
72
59
|
@record ||= DependencyRecord.new(
|
73
60
|
metadata: license_metadata,
|
74
61
|
licenses: license_contents,
|
@@ -78,62 +65,56 @@ module Licensed
|
|
78
65
|
|
79
66
|
# Returns a string representing the dependencys license
|
80
67
|
def license_key
|
81
|
-
return "none"
|
68
|
+
return "none" unless license
|
82
69
|
license.key
|
83
70
|
end
|
84
71
|
|
85
72
|
# Returns the license text content from all matched sources
|
86
73
|
# except the package file, which doesn't contain license text.
|
87
74
|
def license_contents
|
88
|
-
return [] if errors?
|
89
75
|
matched_files.reject { |f| f == package_file }
|
90
76
|
.group_by(&:content)
|
91
|
-
.map { |content, files| { "sources" =>
|
77
|
+
.map { |content, files| { "sources" => license_content_sources(files), "text" => content } }
|
92
78
|
end
|
93
79
|
|
94
80
|
# Returns legal notices found at the dependency path
|
95
81
|
def notice_contents
|
96
|
-
return [] if errors?
|
97
|
-
notice_files.sort # sorted by the path
|
98
|
-
.map { |file| { "sources" => content_sources(file), "text" => File.read(file).rstrip } }
|
99
|
-
.select { |text| text.length > 0 } # files with content only
|
100
|
-
end
|
101
|
-
|
102
|
-
# Returns an array of file paths used to locate legal notices
|
103
|
-
def notice_files
|
104
|
-
return [] if errors?
|
105
|
-
|
106
82
|
Dir.glob(dir_path.join("*"))
|
107
83
|
.grep(LEGAL_FILES_PATTERN)
|
108
84
|
.select { |path| File.file?(path) }
|
85
|
+
.sort # sorted by the path
|
86
|
+
.map { |path| { "sources" => normalize_source_path(path), "text" => File.read(path).rstrip } }
|
87
|
+
.select { |notice| notice["text"].length > 0 } # files with content only
|
109
88
|
end
|
110
89
|
|
111
90
|
private
|
112
91
|
|
113
|
-
# Returns the sources for a group of license
|
92
|
+
# Returns the sources for a group of license file contents
|
114
93
|
#
|
115
94
|
# Sources are returned as a single string with sources separated by ", "
|
116
|
-
def
|
95
|
+
def license_content_sources(files)
|
117
96
|
paths = Array(files).map do |file|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
if path.fnmatch?(dir_path.join("**").to_path)
|
125
|
-
# files under the dependency path return the relative path to the file
|
126
|
-
path.relative_path_from(dir_path).to_path
|
127
|
-
else
|
128
|
-
# otherwise return the source_path as the immediate parent folder name
|
129
|
-
# joined with the file name
|
130
|
-
path.dirname.basename.join(path.basename).to_path
|
131
|
-
end
|
97
|
+
next file[:uri] if file[:uri]
|
98
|
+
|
99
|
+
path = dir_path.join(file[:dir], file[:name])
|
100
|
+
normalize_source_path(path)
|
132
101
|
end
|
133
102
|
|
134
103
|
paths.join(", ")
|
135
104
|
end
|
136
105
|
|
106
|
+
def normalize_source_path(path)
|
107
|
+
path = Pathname.new(path) unless path.is_a?(Pathname)
|
108
|
+
if path.fnmatch?(dir_path.join("**").to_path)
|
109
|
+
# files under the dependency path return the relative path to the file
|
110
|
+
path.relative_path_from(dir_path).to_path
|
111
|
+
else
|
112
|
+
# otherwise return the source_path as the immediate parent folder name
|
113
|
+
# joined with the file name
|
114
|
+
path.dirname.basename.join(path.basename).to_path
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
137
118
|
# Returns the metadata that represents this dependency. This metadata
|
138
119
|
# is written to YAML in the dependencys cached text file
|
139
120
|
def license_metadata
|
@@ -28,7 +28,9 @@ module Licensed
|
|
28
28
|
end
|
29
29
|
|
30
30
|
app.sources.each do |source|
|
31
|
-
|
31
|
+
cache_path = app.cache_path.join(source.class.type)
|
32
|
+
next unless File.exist?(cache_path)
|
33
|
+
Dir.chdir cache_path do
|
32
34
|
# licensed v1 cached records were stored as .txt files with YAML frontmatter
|
33
35
|
Dir["**/*.txt"].each do |file|
|
34
36
|
yaml, licenses, notices = parse_file(file)
|
data/lib/licensed/sources.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "delegate"
|
2
3
|
begin
|
3
4
|
require "bundler"
|
4
5
|
rescue LoadError
|
@@ -36,6 +37,43 @@ module Licensed
|
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
40
|
+
class BundlerSpecification < ::SimpleDelegator
|
41
|
+
def gem_dir
|
42
|
+
dir = super
|
43
|
+
return dir if File.exist?(dir)
|
44
|
+
|
45
|
+
File.join(Gem.dir, "gems", full_name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Dependency < Licensed::Dependency
|
50
|
+
attr_reader :loaded_from
|
51
|
+
|
52
|
+
def initialize(name:, version:, path:, loaded_from:, errors: [], metadata: {})
|
53
|
+
@loaded_from = loaded_from
|
54
|
+
super name: name, version: version, path: path, errors: errors, metadata: metadata
|
55
|
+
end
|
56
|
+
|
57
|
+
# Load a package manager file from the base Licensee::Projects::FsProject
|
58
|
+
# or from a gem specification file.
|
59
|
+
def package_file
|
60
|
+
super || spec_file
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# Find a package manager file from the given bundler specification's
|
66
|
+
# `loaded_from` if available.
|
67
|
+
def spec_file
|
68
|
+
return @spec_file if defined?(@spec_file)
|
69
|
+
return @spec_file = nil unless loaded_from && File.exist?(loaded_from)
|
70
|
+
@spec_file = begin
|
71
|
+
file = { name: File.basename(loaded_from), dir: File.dirname(loaded_from) }
|
72
|
+
Licensee::ProjectFiles::PackageManagerFile.new(File.read(loaded_from), file)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
39
77
|
GEMFILES = %w{Gemfile gems.rb}.freeze
|
40
78
|
DEFAULT_WITHOUT_GROUPS = %i{development test}
|
41
79
|
|
@@ -50,10 +88,11 @@ module Licensed
|
|
50
88
|
with_local_configuration do
|
51
89
|
specs.map do |spec|
|
52
90
|
error = spec.error if spec.respond_to?(:error)
|
53
|
-
|
91
|
+
Dependency.new(
|
54
92
|
name: spec.name,
|
55
93
|
version: spec.version.to_s,
|
56
94
|
path: spec.gem_dir,
|
95
|
+
loaded_from: spec.loaded_from,
|
57
96
|
errors: Array(error),
|
58
97
|
metadata: {
|
59
98
|
"type" => Bundler.type,
|
@@ -112,7 +151,7 @@ module Licensed
|
|
112
151
|
spec = definition.resolve.find { |s| s.satisfies?(dependency) }
|
113
152
|
|
114
153
|
# a nil spec should be rare, generally only seen from bundler
|
115
|
-
return bundle_exec_gem_spec(dependency.name) if spec.nil?
|
154
|
+
return matching_spec(dependency) || bundle_exec_gem_spec(dependency.name) if spec.nil?
|
116
155
|
|
117
156
|
# try to find a non-lazy specification that matches `spec`
|
118
157
|
# spec.source.specs gives access to specifications with more
|
@@ -184,6 +223,21 @@ module Licensed
|
|
184
223
|
end
|
185
224
|
end
|
186
225
|
|
226
|
+
# Loads a dependency specification using rubygems' built-in
|
227
|
+
# `Dependency#matching_specs` and `Dependency#to_spec`, from the original
|
228
|
+
# gem environment
|
229
|
+
def matching_spec(dependency)
|
230
|
+
begin
|
231
|
+
::Bundler.with_original_env do
|
232
|
+
::Bundler.rubygems.clear_paths
|
233
|
+
return unless dependency.matching_specs(true).any?
|
234
|
+
BundlerSpecification.new(dependency.to_spec)
|
235
|
+
end
|
236
|
+
ensure
|
237
|
+
::Bundler.configure
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
187
241
|
# Build the bundler definition
|
188
242
|
def definition
|
189
243
|
@definition ||= ::Bundler::Definition.build(gemfile_path, lockfile_path, nil)
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "tempfile"
|
3
|
+
require "csv"
|
4
|
+
require "uri"
|
5
|
+
require "json"
|
6
|
+
require "net/http"
|
7
|
+
require "fileutils"
|
8
|
+
|
9
|
+
module Licensed
|
10
|
+
module Sources
|
11
|
+
class Gradle < Source
|
12
|
+
|
13
|
+
DEFAULT_CONFIGURATIONS = ["runtime", "runtimeClasspath"].freeze
|
14
|
+
GRADLE_LICENSES_PATH = ".gradle-licenses".freeze
|
15
|
+
|
16
|
+
class Dependency < Licensed::Dependency
|
17
|
+
GRADLE_LICENSES_CSV_NAME = "licenses.csv".freeze
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# Returns a key to uniquely identify a name and version in the obtained CSV content
|
21
|
+
def csv_key(name:, version:)
|
22
|
+
"#{name}-#{version}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Loads and caches license report CSV data as a hash of :name-:version => :url pairs
|
26
|
+
#
|
27
|
+
# executable - The gradle executable to run to generate the license report
|
28
|
+
# configurations - The gradle configurations to generate license report for
|
29
|
+
#
|
30
|
+
# Returns a hash of dependency identifiers to their license content URL
|
31
|
+
def load_csv(path, executable, configurations)
|
32
|
+
@csv ||= begin
|
33
|
+
gradle_licenses_dir = File.join(path, GRADLE_LICENSES_PATH)
|
34
|
+
Licensed::Sources::Gradle.gradle_command("generateLicenseReport", path: path, executable: executable, configurations: configurations)
|
35
|
+
CSV.foreach(File.join(gradle_licenses_dir, GRADLE_LICENSES_CSV_NAME), headers: true).each_with_object({}) do |row, hsh|
|
36
|
+
name, _, version = row["artifact"].rpartition(":")
|
37
|
+
key = csv_key(name: name, version: version)
|
38
|
+
hsh[key] = row["moduleLicenseUrl"]
|
39
|
+
end
|
40
|
+
ensure
|
41
|
+
FileUtils.rm_rf(gradle_licenses_dir)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the cached url for the given dependency
|
46
|
+
def url_for(dependency)
|
47
|
+
@csv[csv_key(name: dependency.name, version: dependency.version)]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Cache and return the results of getting the license content.
|
51
|
+
def retrieve_license(url)
|
52
|
+
(@licenses ||= {})[url] ||= Net::HTTP.get(URI(url))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(name:, version:, path:, executable:, configurations:, metadata: {})
|
57
|
+
@configurations = configurations
|
58
|
+
@executable = executable
|
59
|
+
super(name: name, version: version, path: path, metadata: metadata)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns whether the dependency content exists
|
63
|
+
def exist?
|
64
|
+
# shouldn't force network connections just to check if content exists
|
65
|
+
# only check that the path is not empty
|
66
|
+
!path.to_s.empty?
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns a Licensee::ProjectFiles::LicenseFile for the dependency
|
70
|
+
def project_files
|
71
|
+
self.class.load_csv(path, @executable, @configurations)
|
72
|
+
url = self.class.url_for(self)
|
73
|
+
|
74
|
+
return [] if url.nil?
|
75
|
+
|
76
|
+
license_data = self.class.retrieve_license(url)
|
77
|
+
|
78
|
+
Array(Licensee::ProjectFiles::LicenseFile.new(license_data, { uri: url }))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def enabled?
|
83
|
+
!gradle_executable.to_s.empty? && File.exist?(config.pwd.join("build.gradle"))
|
84
|
+
end
|
85
|
+
|
86
|
+
def enumerate_dependencies
|
87
|
+
JSON.parse(self.class.gradle_command("printDependencies", path: config.pwd, executable: gradle_executable, configurations: configurations)).map do |package|
|
88
|
+
name = "#{package["group"]}:#{package["name"]}"
|
89
|
+
Dependency.new(
|
90
|
+
name: name,
|
91
|
+
version: package["version"],
|
92
|
+
path: config.pwd,
|
93
|
+
executable: gradle_executable,
|
94
|
+
configurations: configurations,
|
95
|
+
metadata: {
|
96
|
+
"type" => Gradle.type
|
97
|
+
}
|
98
|
+
)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def gradle_executable
|
105
|
+
return @gradle_executable if defined?(@gradle_executable)
|
106
|
+
@gradle_executable = begin
|
107
|
+
gradlew = File.join(config.pwd, "gradlew")
|
108
|
+
return gradlew if File.executable?(gradlew)
|
109
|
+
"gradle" if Licensed::Shell.tool_available?("gradle")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns the configurations to include in license generation.
|
114
|
+
# Defaults to ["runtime", "runtimeClasspath"]
|
115
|
+
def configurations
|
116
|
+
@configurations ||= begin
|
117
|
+
if configurations = config.dig("gradle", "configurations")
|
118
|
+
Array(configurations)
|
119
|
+
else
|
120
|
+
DEFAULT_CONFIGURATIONS
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.add_gradle_license_report_plugins_block(gradle_build_file)
|
126
|
+
|
127
|
+
if gradle_build_file.include? "plugins"
|
128
|
+
gradle_build_file.gsub(/(?<=plugins)\s+{/, " { id 'com.github.jk1.dependency-license-report' version '1.6'")
|
129
|
+
else
|
130
|
+
|
131
|
+
gradle_build_file = " plugins { id 'com.github.jk1.dependency-license-report' version '1.6' }" + gradle_build_file
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.gradle_command(*args, path:, executable:, configurations:)
|
136
|
+
gradle_build_file = File.read("build.gradle")
|
137
|
+
|
138
|
+
if !gradle_build_file.include? "dependency-license-report"
|
139
|
+
gradle_build_file = Licensed::Sources::Gradle.add_gradle_license_report_plugins_block(gradle_build_file)
|
140
|
+
end
|
141
|
+
|
142
|
+
Dir.chdir(path) do
|
143
|
+
Tempfile.create(["license-", ".gradle"], path) do |f|
|
144
|
+
f.write(gradle_build_file)
|
145
|
+
f.write gradle_file(configurations)
|
146
|
+
f.close
|
147
|
+
Licensed::Shell.execute(executable, "-q", "-b", f.path, *args)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.gradle_file(configurations)
|
153
|
+
<<~EOF
|
154
|
+
|
155
|
+
import com.github.jk1.license.render.CsvReportRenderer
|
156
|
+
import com.github.jk1.license.filter.LicenseBundleNormalizer
|
157
|
+
|
158
|
+
final configs = #{configurations.inspect}
|
159
|
+
|
160
|
+
licenseReport {
|
161
|
+
configurations = configs
|
162
|
+
outputDir = "$projectDir/#{GRADLE_LICENSES_PATH}"
|
163
|
+
renderers = [new CsvReportRenderer()]
|
164
|
+
filters = [new LicenseBundleNormalizer()]
|
165
|
+
}
|
166
|
+
|
167
|
+
task printDependencies {
|
168
|
+
doLast {
|
169
|
+
def dependencies = []
|
170
|
+
configs.each {
|
171
|
+
configurations[it].resolvedConfiguration.resolvedArtifacts.each { artifact ->
|
172
|
+
def id = artifact.moduleVersion.id
|
173
|
+
dependencies << " { \\"group\\": \\"${id.group}\\", \\"name\\": \\"${id.name}\\", \\"version\\": \\"${id.version}\\" }"
|
174
|
+
}
|
175
|
+
}
|
176
|
+
println "[\\n${dependencies.join(", ")}\\n]"
|
177
|
+
}
|
178
|
+
}
|
179
|
+
EOF
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
data/lib/licensed/version.rb
CHANGED
data/licensed.gemspec
CHANGED
@@ -31,7 +31,8 @@ Gem::Specification.new do |spec|
|
|
31
31
|
|
32
32
|
spec.add_development_dependency "rake", "~> 10.0"
|
33
33
|
spec.add_development_dependency "minitest", "~> 5.8"
|
34
|
-
spec.add_development_dependency "
|
34
|
+
spec.add_development_dependency "mocha", "~> 1.0"
|
35
|
+
spec.add_development_dependency "rubocop", "~> 0.49", "< 0.67"
|
35
36
|
spec.add_development_dependency "rubocop-github", "~> 0.6"
|
36
37
|
spec.add_development_dependency "byebug", "~> 10.0.0"
|
37
38
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
#/ Usage: script/packages/build <RUBYC> [VERSION]
|
3
|
+
#/
|
4
|
+
#/ WARNING: Do not call this directly. Please create packages using
|
5
|
+
#/ `script/package [platform]` or `bundle exec rake package[platform]`
|
6
|
+
#/
|
7
|
+
#/ Builds a distributable package for licensed for a given RUBYC compiler and licensed VERSION.
|
8
|
+
#/ Packages are of the form licensed-$VERSION-$PLATFORM-x64.tar.gz and contain a `./licensed` executable
|
9
|
+
#/ Built Packages are placed in the <root>/pkg/$VERSION directory.
|
10
|
+
#/
|
11
|
+
#/ OPTIONS:
|
12
|
+
#/ <RUBYC> The path to a rubyc compiler that should be used to compile the target executable
|
13
|
+
#/ [VERSION] (optional, default to current git branch or SHA1) version of licensed to build exe at
|
14
|
+
#/
|
15
|
+
#/ EXAMPLES:
|
16
|
+
#/
|
17
|
+
#/ Builds a package for version 1.1.0 using a local rubyc compiler
|
18
|
+
#/ $ script/packages/build RUBYC="./rubyc-darwin" VERSION="1.1.0"
|
19
|
+
#/
|
20
|
+
|
21
|
+
set -euo pipefail
|
22
|
+
|
23
|
+
BASE_DIR="$(cd "$(dirname $0)/../.." && pwd)"
|
24
|
+
RUBYC=${RUBYC:=""}
|
25
|
+
if [ ! -f "$RUBYC" ]; then
|
26
|
+
echo "Specify a rubyc compiler using the RUBYC environment variable" >&2
|
27
|
+
exit 127
|
28
|
+
fi
|
29
|
+
|
30
|
+
# if a version is not provided, get an identifier from the current HEAD
|
31
|
+
VERSION=${VERSION:="$(git rev-parse --abbrev-ref HEAD)"}
|
32
|
+
|
33
|
+
BUILD_DIR="$(mktemp -d)"
|
34
|
+
COPY_DIR="$(mktemp -d)"
|
35
|
+
trap "rm -rf $BUILD_DIR; rm -rf $COPY_DIR" EXIT
|
36
|
+
|
37
|
+
# copy the repo to a separate directory. determining license metadata
|
38
|
+
# will require a clean environment with no Gemfile.lock. using a work location
|
39
|
+
# is preferred to messing with a development repository
|
40
|
+
rsync -r --exclude="test/" --exclude=".licenses/" --exclude="vendor/" --exclude="Gemfile.lock" --exclude="pkg/" $BASE_DIR/ $COPY_DIR
|
41
|
+
cd $COPY_DIR
|
42
|
+
|
43
|
+
# ensure repo is at $VERSION and build executable, restoring the repo to previous
|
44
|
+
# state after build.
|
45
|
+
(
|
46
|
+
# run in a subshell for ease of returning to the current branch after building
|
47
|
+
# the executable
|
48
|
+
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
49
|
+
if [[ "$VERSION" != "$CURRENT_BRANCH" ]]; then
|
50
|
+
git checkout "$VERSION"
|
51
|
+
trap "git checkout $CURRENT_BRANCH" EXIT
|
52
|
+
fi
|
53
|
+
|
54
|
+
# build the licensed rubyc executable
|
55
|
+
"$RUBYC" --clean-tmpdir -o "$BUILD_DIR/licensed" "$COPY_DIR/exe/licensed"
|
56
|
+
chmod +x $BUILD_DIR/licensed
|
57
|
+
)
|
58
|
+
|
59
|
+
# non-executable content will be stored in a `meta` directory
|
60
|
+
mkdir -p "$BUILD_DIR/meta"
|
61
|
+
|
62
|
+
# include dependency license data in package; run bundle update in temp work dir
|
63
|
+
# and then run licensed on itself in that directory to grab license data
|
64
|
+
# NOTE: this does not produce accurate license information if any licensed
|
65
|
+
# depends on any platform-specific gems.
|
66
|
+
(
|
67
|
+
# run in a subshell so that `unset BUNDLER_VERSION` is contained. the ENV var
|
68
|
+
# is required to successfully build a distributable executable on
|
69
|
+
# dockerized linux
|
70
|
+
unset BUNDLER_VERSION
|
71
|
+
|
72
|
+
# determining dependency license data needs to be done from a clean environment
|
73
|
+
# without previous dependencies or a Gemfile.lock so as to pull in the latest
|
74
|
+
# bundler version, which is what the distributed executable uses
|
75
|
+
script/bootstrap
|
76
|
+
bundle exec exe/licensed cache
|
77
|
+
cp -R "$COPY_DIR/.licenses" "$BUILD_DIR/meta"
|
78
|
+
)
|
79
|
+
|
80
|
+
# copy static metadata to build directory
|
81
|
+
mkdir -p "$BUILD_DIR/meta/ruby"
|
82
|
+
curl -o "$BUILD_DIR/meta/ruby/license.txt" "https://www.ruby-lang.org/en/about/license.txt"
|
83
|
+
cp "$BASE_DIR/LICENSE" "$BUILD_DIR/meta"
|
84
|
+
cp "$BASE_DIR/README.md" "$BUILD_DIR/meta"
|
85
|
+
|
86
|
+
# create release archive
|
87
|
+
PLATFORM="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
88
|
+
TARGET="$BASE_DIR/pkg/$VERSION/licensed-$VERSION-$PLATFORM-x64.tar.gz"
|
89
|
+
mkdir -p "$(dirname $TARGET)"
|
90
|
+
tar -C "$BUILD_DIR" -czf "$TARGET" .
|
91
|
+
|
92
|
+
echo "licensed package built to $TARGET"
|
data/script/packages/linux
CHANGED
@@ -27,21 +27,23 @@ build_linux_docker() {
|
|
27
27
|
-v "$BASE_DIR":/var/licensed \
|
28
28
|
-w /var/licensed \
|
29
29
|
"$IMAGE" \
|
30
|
-
"script/build
|
30
|
+
"script/packages/build"
|
31
31
|
}
|
32
32
|
|
33
33
|
build_linux_local() {
|
34
34
|
sudo apt-get update && \
|
35
35
|
apt-get install -y --no-install-recommends cmake make gcc pkg-config squashfs-tools curl bison git
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
RUBYC="$BASE_DIR/bin/rubyc-linux"
|
38
|
+
if [ ! -f "$RUBYC" ]; then
|
39
|
+
mkdir -p "$(dirname "$RUBYC")"
|
40
|
+
curl -L http://enclose.io/rubyc/rubyc-linux-x64.gz | gunzip > "$RUBYC"
|
41
|
+
chmod +x "$RUBYC"
|
41
42
|
fi
|
42
43
|
|
43
44
|
export CPPFLAGS="-P"
|
44
|
-
RUBYC
|
45
|
+
export RUBYC
|
46
|
+
"$BASE_DIR"/script/packages/build
|
45
47
|
}
|
46
48
|
|
47
49
|
if [[ "$(uname -s)" != "Linux" ]]; then
|
data/script/packages/mac
CHANGED
@@ -22,14 +22,16 @@ if [[ "$(uname -s)" != "Darwin" ]]; then
|
|
22
22
|
fi
|
23
23
|
|
24
24
|
BASE_DIR="$(cd "$(dirname $0)/../.." && pwd)"
|
25
|
+
RUBYC="$BASE_DIR/bin/rubyc-darwin"
|
25
26
|
|
26
27
|
brew update
|
27
28
|
brew list "squashfs" &>/dev/null || brew install "squashfs"
|
28
29
|
|
29
|
-
if [ ! -f "$
|
30
|
-
mkdir -p "$
|
31
|
-
curl -L http://enclose.io/rubyc/rubyc-darwin-x64.gz | gunzip > "$
|
32
|
-
chmod +x "$
|
30
|
+
if [ ! -f "$RUBYC" ]; then
|
31
|
+
mkdir -p "$(dirname "$RUBYC")"
|
32
|
+
curl -L http://enclose.io/rubyc/rubyc-darwin-x64.gz | gunzip > "$RUBYC"
|
33
|
+
chmod +x "$RUBYC"
|
33
34
|
fi
|
34
35
|
|
35
|
-
RUBYC
|
36
|
+
export RUBYC
|
37
|
+
"$BASE_DIR"/script/packages/build
|
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: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: licensee
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '5.8'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: mocha
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.0'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: rubocop
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,6 +129,9 @@ dependencies:
|
|
115
129
|
- - "~>"
|
116
130
|
- !ruby/object:Gem::Version
|
117
131
|
version: '0.49'
|
132
|
+
- - "<"
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0.67'
|
118
135
|
type: :development
|
119
136
|
prerelease: false
|
120
137
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -122,6 +139,9 @@ dependencies:
|
|
122
139
|
- - "~>"
|
123
140
|
- !ruby/object:Gem::Version
|
124
141
|
version: '0.49'
|
142
|
+
- - "<"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0.67'
|
125
145
|
- !ruby/object:Gem::Dependency
|
126
146
|
name: rubocop-github
|
127
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -159,6 +179,7 @@ extensions: []
|
|
159
179
|
extra_rdoc_files: []
|
160
180
|
files:
|
161
181
|
- ".gitignore"
|
182
|
+
- ".licensed.yml"
|
162
183
|
- ".rubocop.yml"
|
163
184
|
- ".ruby-version"
|
164
185
|
- ".travis.yml"
|
@@ -182,6 +203,7 @@ files:
|
|
182
203
|
- docs/sources/dep.md
|
183
204
|
- docs/sources/git_submodule.md
|
184
205
|
- docs/sources/go.md
|
206
|
+
- docs/sources/gradle.md
|
185
207
|
- docs/sources/manifests.md
|
186
208
|
- docs/sources/npm.md
|
187
209
|
- docs/sources/pip.md
|
@@ -213,6 +235,7 @@ files:
|
|
213
235
|
- lib/licensed/sources/dep.rb
|
214
236
|
- lib/licensed/sources/git_submodule.rb
|
215
237
|
- lib/licensed/sources/go.rb
|
238
|
+
- lib/licensed/sources/gradle.rb
|
216
239
|
- lib/licensed/sources/manifest.rb
|
217
240
|
- lib/licensed/sources/npm.rb
|
218
241
|
- lib/licensed/sources/pip.rb
|
@@ -221,10 +244,10 @@ files:
|
|
221
244
|
- lib/licensed/version.rb
|
222
245
|
- licensed.gemspec
|
223
246
|
- script/bootstrap
|
224
|
-
- script/build-rubyc-exe
|
225
247
|
- script/cibuild
|
226
248
|
- script/console
|
227
249
|
- script/package
|
250
|
+
- script/packages/build
|
228
251
|
- script/packages/linux
|
229
252
|
- script/packages/mac
|
230
253
|
- script/setup
|
data/script/build-rubyc-exe
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
#!/bin/bash
|
2
|
-
#/ Usage: script/build-rubyc-exe <RUBYC> [VERSION]
|
3
|
-
#/
|
4
|
-
#/ WARNING: You should not need to call this directly. Please create packages using
|
5
|
-
#/ `script/package [platform]` or `bundle exec rake package[platform]`
|
6
|
-
#/
|
7
|
-
#/ Builds a distributable package for licensed for a given RUBYC compiler and licensed VERSION.
|
8
|
-
#/ Packages are of the form licensed-$VERSION-$PLATFORM-x64.tar.gz and contain a `./licensed` executable
|
9
|
-
#/ Built Packages are placed in the <root>/pkg directory.
|
10
|
-
#/
|
11
|
-
#/ OPTIONS:
|
12
|
-
#/ <RUBYC> The path to a rubyc compiler that should be used to compile the target executable
|
13
|
-
#/ [VERSION] (optional, default to current git branch or SHA1) version of licensed to build exe at
|
14
|
-
#/
|
15
|
-
#/ EXAMPLES:
|
16
|
-
#/
|
17
|
-
#/ Builds a package for version 1.1.0 using a local rubyc compiler
|
18
|
-
#/ $ build-rubyc-exe RUBYC="./rubyc-darwin" VERSION="1.1.0"
|
19
|
-
#/
|
20
|
-
|
21
|
-
set -euo pipefail
|
22
|
-
|
23
|
-
usage(){
|
24
|
-
grep "^#/" <"$0" | cut -c3-
|
25
|
-
}
|
26
|
-
|
27
|
-
BASE_DIR="$(cd "$(dirname $0)/.." && pwd)"
|
28
|
-
VERSION=${VERSION:=""}
|
29
|
-
RUBYC=${RUBYC:=""}
|
30
|
-
if [ ! -f "$RUBYC" ]; then
|
31
|
-
echo "Please specify a rubyc compiler" >&2
|
32
|
-
usage
|
33
|
-
exit 127
|
34
|
-
fi
|
35
|
-
|
36
|
-
BUILD_DEST="$(mktemp -d)"
|
37
|
-
trap "rm -rf $BUILD_DEST" EXIT
|
38
|
-
|
39
|
-
if [ -n "$VERSION" ]; then
|
40
|
-
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
41
|
-
git checkout "$VERSION"
|
42
|
-
trap "rm -rf $BUILD_DEST; git checkout $CURRENT_BRANCH" EXIT
|
43
|
-
else
|
44
|
-
VERSION="$(git rev-parse --abbrev-ref HEAD)"
|
45
|
-
fi
|
46
|
-
|
47
|
-
PACKAGE_DEST="$BASE_DIR/pkg"
|
48
|
-
mkdir -p "$PACKAGE_DEST"
|
49
|
-
|
50
|
-
PLATFORM="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
51
|
-
TARGET="licensed-$VERSION-$PLATFORM-x64.tar.gz"
|
52
|
-
|
53
|
-
"$RUBYC" --clean-tmpdir -o "$BUILD_DEST/licensed" "$BASE_DIR/exe/licensed"
|
54
|
-
|
55
|
-
chmod +x $BUILD_DEST/licensed
|
56
|
-
tar -C "$BUILD_DEST" -czf "$PACKAGE_DEST/$TARGET" "./licensed"
|
57
|
-
|
58
|
-
echo "licensed built to $PACKAGE_DEST/$TARGET"
|