licensed 0.6.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|