licensed 0.6.0 → 0.10.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/.gitignore +3 -0
- data/CODE_OF_CONDUCT.md +65 -7
- data/README.md +9 -2
- data/bin/setup +15 -2
- data/lib/licensed.rb +3 -0
- data/lib/licensed/cli.rb +5 -1
- data/lib/licensed/command/cache.rb +5 -2
- data/lib/licensed/configuration.rb +11 -3
- data/lib/licensed/dependency.rb +22 -4
- data/lib/licensed/license.rb +1 -1
- data/lib/licensed/source/bower.rb +5 -4
- data/lib/licensed/source/bundler.rb +2 -2
- data/lib/licensed/source/go.rb +147 -0
- data/lib/licensed/source/manifest.rb +70 -0
- data/lib/licensed/source/npm.rb +16 -4
- data/lib/licensed/source/stack.rb +66 -0
- data/lib/licensed/version.rb +1 -1
- data/licensed.gemspec +2 -1
- metadata +31 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d5a1817146cc5f614b0e2a105173d7576822350
|
4
|
+
data.tar.gz: 9943ff25b44537ea166f43d7bcf129ac936bb0f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4ae78971d00c63a2fb9a623ea1fd80dfb16bcf9937f58d34c874c698f76af676729f6ce6dc11baaacd3542f8fc17d4c392f6ea87d2b3b2ec95ecd46dae51f869
|
7
|
+
data.tar.gz: fb06c9f7c7c1b367b836bbf1b122f964eca15138d356a4baf1dc6ff05aa8c98ead899f9283dc274b5f1fb75698e68c9ebaff51ea1dd5f17b3a999ff179ce9ec9
|
data/.gitignore
CHANGED
data/CODE_OF_CONDUCT.md
CHANGED
@@ -1,13 +1,71 @@
|
|
1
|
-
|
1
|
+
Contributor Covenant Code of Conduct
|
2
2
|
|
3
|
-
|
3
|
+
Our Pledge
|
4
4
|
|
5
|
-
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
6
11
|
|
7
|
-
|
12
|
+
Our Standards
|
8
13
|
|
9
|
-
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
10
16
|
|
11
|
-
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
12
22
|
|
13
|
-
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at opensource+licensed@github.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
|
71
|
+
available at http://contributor-covenant.org/version/1/4/
|
data/README.md
CHANGED
@@ -72,13 +72,20 @@ reviewed:
|
|
72
72
|
|
73
73
|
### Sources
|
74
74
|
|
75
|
-
Dependencies
|
75
|
+
Dependencies will be automatically detected for
|
76
|
+
1. Bundler
|
77
|
+
2. NPM
|
78
|
+
3. Bower
|
79
|
+
4. HaskellStack
|
80
|
+
|
81
|
+
You can disable any of them in `vendor/licenses/config.yml`:
|
76
82
|
|
77
83
|
```yml
|
78
84
|
sources:
|
79
85
|
rubygem: false
|
80
86
|
npm: false
|
81
87
|
bower: false
|
88
|
+
stack: false
|
82
89
|
```
|
83
90
|
|
84
91
|
## Development
|
@@ -89,7 +96,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
89
96
|
|
90
97
|
## Contributing
|
91
98
|
|
92
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/github/licensed. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
99
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/github/licensed. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org/) code of conduct.
|
93
100
|
|
94
101
|
## License
|
95
102
|
|
data/bin/setup
CHANGED
@@ -7,5 +7,18 @@ bundle install
|
|
7
7
|
# Install bower fixtures
|
8
8
|
bower install
|
9
9
|
|
10
|
-
|
11
|
-
cd test/fixtures
|
10
|
+
|
11
|
+
cd test/fixtures
|
12
|
+
|
13
|
+
# Install npm fixtures
|
14
|
+
npm install
|
15
|
+
|
16
|
+
# Install stack fixtures
|
17
|
+
stack build
|
18
|
+
|
19
|
+
if [ -n $(which go) ]; then
|
20
|
+
export GOPATH="`pwd`/go"
|
21
|
+
|
22
|
+
cd go/src/test
|
23
|
+
go get
|
24
|
+
fi
|
data/lib/licensed.rb
CHANGED
@@ -4,7 +4,10 @@ require "licensed/license"
|
|
4
4
|
require "licensed/dependency"
|
5
5
|
require "licensed/source/bundler"
|
6
6
|
require "licensed/source/bower"
|
7
|
+
require "licensed/source/manifest"
|
7
8
|
require "licensed/source/npm"
|
9
|
+
require "licensed/source/stack"
|
10
|
+
require "licensed/source/go"
|
8
11
|
require "licensed/command/cache"
|
9
12
|
require "licensed/command/verify"
|
10
13
|
require "licensed/ui/shell"
|
data/lib/licensed/cli.rb
CHANGED
@@ -9,12 +9,16 @@ module Licensed
|
|
9
9
|
:desc => "Overwrite licenses even if version has not changed."
|
10
10
|
method_option :offline, :type => :boolean,
|
11
11
|
:desc => "Do not make network calls."
|
12
|
+
method_option "license-dir", :type => :string,
|
13
|
+
:desc => "Path to license storage directory (defaults to vendor/licenses)"
|
12
14
|
def cache
|
13
15
|
Licensed.use_github = false if options[:offline]
|
14
16
|
run Licensed::Command::Cache.new(config), force: options[:force]
|
15
17
|
end
|
16
18
|
|
17
19
|
desc "verify", "Verify licenses of dependencies"
|
20
|
+
method_option "license-dir", :type => :string,
|
21
|
+
:desc => "Path to license storage directory (defaults to vendor/licenses)"
|
18
22
|
def verify
|
19
23
|
run Licensed::Command::Verify.new(config)
|
20
24
|
end
|
@@ -22,7 +26,7 @@ module Licensed
|
|
22
26
|
private
|
23
27
|
|
24
28
|
def config
|
25
|
-
@config ||= Configuration.new
|
29
|
+
@config ||= Configuration.new(options)
|
26
30
|
end
|
27
31
|
|
28
32
|
def run(command, *args)
|
@@ -37,8 +37,11 @@ module Licensed
|
|
37
37
|
dependency["name"] unless @config.ignored?(dependency)
|
38
38
|
end.compact
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
license_source_path = @config.path.join(source.type)
|
41
|
+
Dir.glob(license_source_path.join("**/*.txt")).each do |file|
|
42
|
+
file_path = Pathname.new(file)
|
43
|
+
relative_path = file_path.relative_path_from(license_source_path).to_s
|
44
|
+
FileUtils.rm(file) unless names.include?(relative_path.chomp(".txt"))
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
@@ -4,8 +4,9 @@ module Licensed
|
|
4
4
|
class Configuration < Hash
|
5
5
|
attr_accessor :ui
|
6
6
|
|
7
|
-
def initialize
|
7
|
+
def initialize(options = {})
|
8
8
|
super()
|
9
|
+
self.path = options["license-dir"] if options["license-dir"]
|
9
10
|
update config_path.exist? ? YAML.load_file(config_path) : {}
|
10
11
|
|
11
12
|
self["sources"] ||= {}
|
@@ -17,7 +18,11 @@ module Licensed
|
|
17
18
|
end
|
18
19
|
|
19
20
|
def path
|
20
|
-
Pathname.new("vendor/licenses")
|
21
|
+
@path ||= Pathname.new("vendor/licenses")
|
22
|
+
end
|
23
|
+
|
24
|
+
def path=(value)
|
25
|
+
@path = Pathname.new(value)
|
21
26
|
end
|
22
27
|
|
23
28
|
def config_path
|
@@ -32,7 +37,10 @@ module Licensed
|
|
32
37
|
@sources ||= [
|
33
38
|
Source::Bundler.new(self),
|
34
39
|
Source::Bower.new(self),
|
35
|
-
Source::
|
40
|
+
Source::Manifest.new(self),
|
41
|
+
Source::NPM.new(self),
|
42
|
+
Source::Stack.new(self),
|
43
|
+
Source::Go.new(self)
|
36
44
|
].select(&:enabled?)
|
37
45
|
end
|
38
46
|
|
data/lib/licensed/dependency.rb
CHANGED
@@ -2,17 +2,27 @@ require "licensee"
|
|
2
2
|
|
3
3
|
module Licensed
|
4
4
|
class Dependency < License
|
5
|
-
LEGAL_FILES = /\A(COPYING|NOTICE|LEGAL)(?:\..*)?\z/i
|
5
|
+
LEGAL_FILES = /\A(AUTHORS|COPYING|NOTICE|LEGAL)(?:\..*)?\z/i
|
6
6
|
|
7
7
|
attr_reader :path
|
8
|
+
attr_reader :search_root
|
8
9
|
|
9
10
|
def initialize(path, metadata = {})
|
10
11
|
@path = path
|
12
|
+
@search_root = metadata.delete("search_root")
|
13
|
+
|
14
|
+
# with licensee now providing license_file[:dir],
|
15
|
+
# enforcing absolute paths makes life much easier when determining
|
16
|
+
# an absolute file path in notices\
|
17
|
+
unless Pathname.new(path).absolute?
|
18
|
+
raise "Dependency path #{path} must be absolute"
|
19
|
+
end
|
20
|
+
|
11
21
|
super metadata
|
12
22
|
end
|
13
23
|
|
14
24
|
def project
|
15
|
-
@project ||= Licensee::FSProject.new(path, detect_packages: true, detect_readme: true)
|
25
|
+
@project ||= Licensee::Projects::FSProject.new(path, search_root: search_root, detect_packages: true, detect_readme: true)
|
16
26
|
end
|
17
27
|
|
18
28
|
def detect_license!
|
@@ -39,12 +49,20 @@ module Licensed
|
|
39
49
|
|
40
50
|
# Extract legal notices from the dependency source
|
41
51
|
def notices
|
52
|
+
return [] unless Dir.exist? path
|
53
|
+
|
42
54
|
files = Dir.foreach(path).select do |file|
|
43
55
|
File.file?(File.join(path, file)) && file.match(LEGAL_FILES)
|
44
56
|
end
|
45
|
-
files.unshift project.license_file.filename if project.license_file
|
46
57
|
|
47
|
-
|
58
|
+
if license_file = project.license_file
|
59
|
+
files.unshift File.join(license_file[:dir], license_file.filename)
|
60
|
+
end
|
61
|
+
|
62
|
+
files.uniq.map do |f|
|
63
|
+
absolute_path = Pathname.new(f).absolute? ? f : File.join(path, f)
|
64
|
+
File.read(absolute_path)
|
65
|
+
end
|
48
66
|
end
|
49
67
|
end
|
50
68
|
end
|
data/lib/licensed/license.rb
CHANGED
@@ -13,7 +13,7 @@ module Licensed
|
|
13
13
|
#
|
14
14
|
# Returns a Licensed::License
|
15
15
|
def self.read(filename)
|
16
|
-
match = File.read(filename).match(YAML_FRONTMATTER_PATTERN)
|
16
|
+
match = File.read(filename).scrub.match(YAML_FRONTMATTER_PATTERN)
|
17
17
|
new(YAML.load(match[1]), match[2])
|
18
18
|
end
|
19
19
|
|
@@ -13,7 +13,7 @@ module Licensed
|
|
13
13
|
|
14
14
|
def enabled?
|
15
15
|
return false unless @config.enabled?(type)
|
16
|
-
|
16
|
+
|
17
17
|
[@config.pwd.join(".bowerrc"), @config.pwd.join("bower.json")].any? do |path|
|
18
18
|
File.exist?(path)
|
19
19
|
end
|
@@ -22,10 +22,11 @@ module Licensed
|
|
22
22
|
def dependencies
|
23
23
|
@dependencies ||= Dir.glob(bower_path.join("*/.bower.json")).map do |file|
|
24
24
|
package = JSON.parse(File.read(file))
|
25
|
-
|
25
|
+
path = bower_path.join(file).dirname.to_path
|
26
|
+
Dependency.new(path, {
|
26
27
|
"type" => type,
|
27
28
|
"name" => package["name"],
|
28
|
-
"version" => package["version"],
|
29
|
+
"version" => package["version"] || package["_release"],
|
29
30
|
"summary" => package["description"],
|
30
31
|
"homepage" => package["homepage"]
|
31
32
|
})
|
@@ -40,7 +41,7 @@ module Licensed
|
|
40
41
|
end
|
41
42
|
|
42
43
|
def bower_path
|
43
|
-
pwd = bower_config["cwd"] ? Pathname.new(bower_config["cwd"]) : @config.pwd
|
44
|
+
pwd = bower_config["cwd"] ? Pathname.new(bower_config["cwd"]).expand_path : @config.pwd
|
44
45
|
pwd.join bower_config["directory"] || "bower_components"
|
45
46
|
end
|
46
47
|
end
|
@@ -37,11 +37,11 @@ module Licensed
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def gemfile_path
|
40
|
-
@config.pwd.join
|
40
|
+
@config.pwd.join ::Bundler.default_gemfile.basename.to_s
|
41
41
|
end
|
42
42
|
|
43
43
|
def lockfile_path
|
44
|
-
@config.pwd.join
|
44
|
+
@config.pwd.join ::Bundler.default_lockfile.basename.to_s
|
45
45
|
end
|
46
46
|
|
47
47
|
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'English'
|
3
|
+
|
4
|
+
module Licensed
|
5
|
+
module Source
|
6
|
+
class Go
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
def type
|
12
|
+
"go"
|
13
|
+
end
|
14
|
+
|
15
|
+
def enabled?
|
16
|
+
@config.enabled?(type) && go_source?
|
17
|
+
end
|
18
|
+
|
19
|
+
def dependencies
|
20
|
+
@dependencies ||= packages.map do |package_name|
|
21
|
+
package = package_info(package_name)
|
22
|
+
import_path = non_vendored_import_path(package_name)
|
23
|
+
|
24
|
+
if package.empty?
|
25
|
+
next if @config.ignored?('type' => type, 'name' => package_name)
|
26
|
+
raise "couldn't find package for #{import_path}"
|
27
|
+
end
|
28
|
+
|
29
|
+
Dependency.new(package["Dir"], {
|
30
|
+
"type" => type,
|
31
|
+
"name" => import_path,
|
32
|
+
"summary" => package["Doc"],
|
33
|
+
"homepage" => homepage(import_path),
|
34
|
+
"search_root" => search_root(package),
|
35
|
+
"version" => package_version(package["Dir"])
|
36
|
+
})
|
37
|
+
end.compact
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the homepage for a package import_path. Assumes that the
|
41
|
+
# import path itself is a url domain and path
|
42
|
+
def homepage(import_path)
|
43
|
+
return unless import_path
|
44
|
+
|
45
|
+
# hacky but generally works due to go packages looking like
|
46
|
+
# "github.com/..." or "golang.org/..."
|
47
|
+
"https://#{import_path}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns an array of dependency package import paths
|
51
|
+
def packages
|
52
|
+
return [] unless root_package["Deps"]
|
53
|
+
|
54
|
+
# don't include go std packages
|
55
|
+
# don't include packages under the root project that aren't vendored
|
56
|
+
root_package["Deps"]
|
57
|
+
.uniq
|
58
|
+
.select { |d| !go_std_packages.include?(d) }
|
59
|
+
.select { |d| !d.start_with?(root_package["ImportPath"]) || vendored_package?(d) }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the root directory to search for a package license
|
63
|
+
#
|
64
|
+
# package - package object obtained from package_info
|
65
|
+
def search_root(package)
|
66
|
+
# search root choices:
|
67
|
+
# 1. vendor folder if package is vendored
|
68
|
+
# 2. GOPATH
|
69
|
+
# 3. nil (no search up directory hierarchy)
|
70
|
+
return vendor_dir if vendored_package?(package["ImportPath"])
|
71
|
+
ENV.fetch("GOPATH", nil)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the most recent git SHA for a package, or nil if SHA is
|
75
|
+
# not available
|
76
|
+
#
|
77
|
+
# package_directory - package location
|
78
|
+
def package_version(package_directory)
|
79
|
+
return unless git? && package_directory
|
80
|
+
|
81
|
+
`cd #{package_directory} && git rev-list -1 HEAD -- .`.strip
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns whether a package is vendored or not based on the package
|
85
|
+
# import_path
|
86
|
+
#
|
87
|
+
# import_path - Package import path to test
|
88
|
+
def vendored_package?(import_path)
|
89
|
+
import_path && import_path.start_with?(vendor_import_path)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns the import path parameter without the vendor component
|
93
|
+
#
|
94
|
+
# import_path - Package import path with vendor component
|
95
|
+
def non_vendored_import_path(import_path)
|
96
|
+
return unless import_path
|
97
|
+
import_path.gsub(vendor_import_path, "")
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns package information, or {} if package isn't found
|
101
|
+
#
|
102
|
+
# package - Go package import path
|
103
|
+
def package_info(package = nil)
|
104
|
+
info = package_info_command(package)
|
105
|
+
return {} if info.empty?
|
106
|
+
JSON.parse(info)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns package information as a JSON string
|
110
|
+
#
|
111
|
+
# package - Go package import path
|
112
|
+
def package_info_command(package)
|
113
|
+
`go list -json #{package}`
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns the root directory for vendored packages
|
117
|
+
def vendor_dir
|
118
|
+
"#{root_package["Dir"]}/vendor"
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns the import path for vendored packages
|
122
|
+
def vendor_import_path
|
123
|
+
"#{root_package["ImportPath"]}/vendor/"
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns the info for the package under test
|
127
|
+
def root_package
|
128
|
+
@root_package ||= package_info
|
129
|
+
end
|
130
|
+
|
131
|
+
# Returns whether go source is found
|
132
|
+
def go_source?
|
133
|
+
@go_source ||= `go doc 2>/dev/null` && $CHILD_STATUS.success?
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns a list of go standard packages
|
137
|
+
def go_std_packages
|
138
|
+
@std_packages ||= `go list std`.lines.map(&:strip)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns whether git commands are available
|
142
|
+
def git?
|
143
|
+
@git ||= `which git 2>/dev/null` && $CHILD_STATUS.success?
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'pathname/common_prefix'
|
2
|
+
|
3
|
+
module Licensed
|
4
|
+
module Source
|
5
|
+
class Manifest
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def enabled?
|
11
|
+
@config.enabled?(type) && File.exist?(manifest_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def type
|
15
|
+
'manifest'
|
16
|
+
end
|
17
|
+
|
18
|
+
def dependencies
|
19
|
+
@dependencies ||= packages.map do |package_name, sources|
|
20
|
+
Dependency.new(common_dir(sources), {
|
21
|
+
'type' => type,
|
22
|
+
'name' => package_name,
|
23
|
+
'version' => package_version(sources)
|
24
|
+
})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def common_dir(sources)
|
29
|
+
common_prefix = Pathname.common_prefix(*sources)
|
30
|
+
|
31
|
+
# if there's no common prefix, use the directory of the first source
|
32
|
+
common_prefix = Pathname.new(sources[0]).dirname unless common_prefix
|
33
|
+
|
34
|
+
Pathname.new(@config.path).join(common_prefix).expand_path.to_path
|
35
|
+
end
|
36
|
+
|
37
|
+
def package_version(sources)
|
38
|
+
return if sources.nil? || sources.empty?
|
39
|
+
|
40
|
+
# return the latest version from the sources
|
41
|
+
sources.map { |s| source_version_command(s) }
|
42
|
+
.max_by { |sha| commit_date_command(sha) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def commit_date_command(sha)
|
46
|
+
`git show -s -1 --format=%ct #{sha}`.strip
|
47
|
+
end
|
48
|
+
|
49
|
+
def source_version_command(source)
|
50
|
+
`git rev-list -1 HEAD -- #{source}`.strip
|
51
|
+
end
|
52
|
+
|
53
|
+
def packages
|
54
|
+
manifest.each_with_object({}) do |(src, package_name), hsh|
|
55
|
+
next if src.nil? || src.empty?
|
56
|
+
hsh[package_name] ||= []
|
57
|
+
hsh[package_name] << src
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def manifest
|
62
|
+
JSON.parse(File.read(manifest_path))
|
63
|
+
end
|
64
|
+
|
65
|
+
def manifest_path
|
66
|
+
@config.path.join('manifest.json')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/licensed/source/npm.rb
CHANGED
@@ -18,10 +18,18 @@ module Licensed
|
|
18
18
|
def dependencies
|
19
19
|
return @dependencies if defined?(@dependencies)
|
20
20
|
|
21
|
-
|
21
|
+
locations = {}
|
22
|
+
package_location_command.lines.each do |line|
|
23
|
+
path, id = line.split(":")[0, 2]
|
24
|
+
locations[id] ||= path
|
25
|
+
end
|
26
|
+
|
27
|
+
packages = recursive_dependencies(JSON.parse(package_metadata_command)["dependencies"])
|
22
28
|
|
23
29
|
@dependencies = packages.map do |name, package|
|
24
|
-
|
30
|
+
path = package["realPath"] || locations["#{package["name"]}@#{package["version"]}"]
|
31
|
+
fail "couldn't locate #{name} under node_modules/" unless path
|
32
|
+
Dependency.new(path, {
|
25
33
|
"type" => type,
|
26
34
|
"name" => package["name"],
|
27
35
|
"version" => package["version"],
|
@@ -31,8 +39,12 @@ module Licensed
|
|
31
39
|
end
|
32
40
|
end
|
33
41
|
|
34
|
-
def
|
35
|
-
`npm list --
|
42
|
+
def package_location_command
|
43
|
+
`npm list --parseable --production --long 2>/dev/null`
|
44
|
+
end
|
45
|
+
|
46
|
+
def package_metadata_command
|
47
|
+
`npm list --json --production --long 2>/dev/null`
|
36
48
|
end
|
37
49
|
|
38
50
|
def recursive_dependencies(dependencies, result = {})
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Licensed
|
2
|
+
module Source
|
3
|
+
class Stack
|
4
|
+
def initialize(config)
|
5
|
+
@config = config
|
6
|
+
end
|
7
|
+
|
8
|
+
def type
|
9
|
+
"stack"
|
10
|
+
end
|
11
|
+
|
12
|
+
def enabled?
|
13
|
+
@config.enabled?(type) && File.exist?(@config.pwd.join("stack.yaml"))
|
14
|
+
end
|
15
|
+
|
16
|
+
def dependencies
|
17
|
+
@dependencies ||= packages.map do |(name, version)|
|
18
|
+
package_id = "#{name}-#{version}"
|
19
|
+
package = package_info package_id
|
20
|
+
|
21
|
+
if package.empty?
|
22
|
+
next if @config.ignored?('type' => type, 'name' => name)
|
23
|
+
raise "couldn't locate #{package_id} with ghc-pkg"
|
24
|
+
end
|
25
|
+
|
26
|
+
path = package["haddock-html"] || File.join(@config.pwd, "vendor", name)
|
27
|
+
Dependency.new(path, {
|
28
|
+
"type" => type,
|
29
|
+
"name" => package["name"] || name,
|
30
|
+
"version" => package["version"] || version,
|
31
|
+
"summary" => package["synopsis"],
|
32
|
+
"homepage" => safe_homepage(package["homepage"])
|
33
|
+
})
|
34
|
+
end.compact
|
35
|
+
end
|
36
|
+
|
37
|
+
def safe_homepage(homepage)
|
38
|
+
return unless homepage
|
39
|
+
# use https and remove url fragment
|
40
|
+
homepage.gsub(/http:/, "https:")
|
41
|
+
.gsub(/#[^?]*\z/, "")
|
42
|
+
end
|
43
|
+
|
44
|
+
def packages
|
45
|
+
list_packages_command.lines.map(&:split)
|
46
|
+
end
|
47
|
+
|
48
|
+
def list_packages_command
|
49
|
+
`stack list-dependencies --no-include-base`
|
50
|
+
end
|
51
|
+
|
52
|
+
def package_info(package_id)
|
53
|
+
package_info_command(package_id).lines.each_with_object({}) do |line, info|
|
54
|
+
key, value = line.split(':', 2).map(&:strip)
|
55
|
+
next unless key && value
|
56
|
+
|
57
|
+
info[key] = value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def package_info_command(package_id)
|
62
|
+
`stack exec -- ghc-pkg field #{package_id} name,version,synopsis,homepage,haddock-html 2>/dev/null`
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/licensed/version.rb
CHANGED
data/licensed.gemspec
CHANGED
@@ -19,9 +19,10 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_dependency "licensee", "~>
|
22
|
+
spec.add_dependency "licensee", "~> 9.0"
|
23
23
|
spec.add_dependency "thor", "~>0.19"
|
24
24
|
spec.add_dependency "octokit", "~>4.0"
|
25
|
+
spec.add_dependency "pathname-common_prefix", "~>0.0.1"
|
25
26
|
|
26
27
|
spec.add_development_dependency "bundler", "~> 1.10"
|
27
28
|
spec.add_development_dependency "rake", "~> 10.0"
|
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: 0.
|
4
|
+
version: 0.10.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: 2017-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: licensee
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '9.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '9.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: thor
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '4.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pathname-common_prefix
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.0.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.0.1
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: bundler
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -197,13 +211,20 @@ description: |
|
|
197
211
|
|
198
212
|
### Sources
|
199
213
|
|
200
|
-
Dependencies
|
214
|
+
Dependencies will be automatically detected for
|
215
|
+
1. Bundler
|
216
|
+
2. NPM
|
217
|
+
3. Bower
|
218
|
+
4. HaskellStack
|
219
|
+
|
220
|
+
You can disable any of them in `vendor/licenses/config.yml`:
|
201
221
|
|
202
222
|
```yml
|
203
223
|
sources:
|
204
224
|
rubygem: false
|
205
225
|
npm: false
|
206
226
|
bower: false
|
227
|
+
stack: false
|
207
228
|
```
|
208
229
|
|
209
230
|
## Development
|
@@ -214,7 +235,7 @@ description: |
|
|
214
235
|
|
215
236
|
## Contributing
|
216
237
|
|
217
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/github/licensed. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
238
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/github/licensed. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org/) code of conduct.
|
218
239
|
|
219
240
|
## License
|
220
241
|
|
@@ -248,7 +269,10 @@ files:
|
|
248
269
|
- lib/licensed/license.rb
|
249
270
|
- lib/licensed/source/bower.rb
|
250
271
|
- lib/licensed/source/bundler.rb
|
272
|
+
- lib/licensed/source/go.rb
|
273
|
+
- lib/licensed/source/manifest.rb
|
251
274
|
- lib/licensed/source/npm.rb
|
275
|
+
- lib/licensed/source/stack.rb
|
252
276
|
- lib/licensed/ui/shell.rb
|
253
277
|
- lib/licensed/version.rb
|
254
278
|
- licensed.gemspec
|
@@ -272,7 +296,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
272
296
|
version: '0'
|
273
297
|
requirements: []
|
274
298
|
rubyforge_project:
|
275
|
-
rubygems_version: 2.
|
299
|
+
rubygems_version: 2.6.8
|
276
300
|
signing_key:
|
277
301
|
specification_version: 4
|
278
302
|
summary: extract and validate the licenses of dependencies.
|