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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 188fefd78d80c7a9d36985fde025efada389711a
4
- data.tar.gz: 9cd69efe41165826cfeca9ba29ab930a9718afbd
3
+ metadata.gz: 6d5a1817146cc5f614b0e2a105173d7576822350
4
+ data.tar.gz: 9943ff25b44537ea166f43d7bcf129ac936bb0f2
5
5
  SHA512:
6
- metadata.gz: bf8b94250ef319e828bf0740056087057e744e3f460f841293c2cef95d8c31dc7f25a484f97b9fbf4a1f3af873a95e6f23f5ea653c9808e868d1a856fb946bb4
7
- data.tar.gz: 23f5f40eb1620bbae7370a0bde096becd916dd49f76703413939271509d975f612c1c22864f423b8d962934d5b91e54d49829d70e77d116ba3993476b61091f0
6
+ metadata.gz: 4ae78971d00c63a2fb9a623ea1fd80dfb16bcf9937f58d34c874c698f76af676729f6ce6dc11baaacd3542f8fc17d4c392f6ea87d2b3b2ec95ecd46dae51f869
7
+ data.tar.gz: fb06c9f7c7c1b367b836bbf1b122f964eca15138d356a4baf1dc6ff05aa8c98ead899f9283dc274b5f1fb75698e68c9ebaff51ea1dd5f17b3a999ff179ce9ec9
data/.gitignore CHANGED
@@ -9,4 +9,7 @@
9
9
  /tmp/
10
10
  test/fixtures/bower_components
11
11
  test/fixtures/node_modules
12
+ test/fixtures/go/src/*
13
+ !test/fixtures/go/src/test
14
+ test/**/.stack-work
12
15
  vendor/licenses
@@ -1,13 +1,71 @@
1
- # Contributor Code of Conduct
1
+ Contributor Covenant Code of Conduct
2
2
 
3
- As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
3
+ Our Pledge
4
4
 
5
- We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
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
- Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
12
+ Our Standards
8
13
 
9
- Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
10
16
 
11
- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
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
- This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
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 from Bundler, NPM, and Bower will be automatically detected. You can disable any of them in `vendor/licenses/config.yml`:
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
- # Install bower fixtures
11
- cd test/fixtures && npm install
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
@@ -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"
@@ -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
- Dir.glob(@config.path.join("#{source.type}/*.txt")).each do |file|
41
- FileUtils.rm(file) unless names.include?(File.basename(file, ".txt"))
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::NPM.new(self)
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
 
@@ -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
- files.uniq.map { |f| File.read(File.join(path, f)) }
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
@@ -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
- Dependency.new(File.dirname(file), {
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 "Gemfile"
40
+ @config.pwd.join ::Bundler.default_gemfile.basename.to_s
41
41
  end
42
42
 
43
43
  def lockfile_path
44
- @config.pwd.join "Gemfile.lock"
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
@@ -18,10 +18,18 @@ module Licensed
18
18
  def dependencies
19
19
  return @dependencies if defined?(@dependencies)
20
20
 
21
- packages = recursive_dependencies(JSON.parse(command)["dependencies"])
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
- Dependency.new(package["realPath"], {
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 command
35
- `npm list --json --production --long`
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
@@ -1,3 +1,3 @@
1
1
  module Licensed
2
- VERSION = "0.6.0"
2
+ VERSION = "0.10.0"
3
3
  end
@@ -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", "~> 8.0"
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.6.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: 2016-03-18 00:00:00.000000000 Z
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: '8.0'
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: '8.0'
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 from Bundler, NPM, and Bower will be automatically detected. You can disable any of them in `vendor/licenses/config.yml`:
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.4.5.1
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.