license_finder 0.9.1-java → 0.9.2-java

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.
Files changed (34) hide show
  1. data/CHANGELOG.rdoc +11 -1
  2. data/features/node_dependencies.feature +9 -0
  3. data/features/python_dependencies.feature +9 -0
  4. data/features/step_definitions/html_report_steps.rb +3 -1
  5. data/features/step_definitions/node_steps.rb +8 -0
  6. data/features/step_definitions/python_steps.rb +8 -0
  7. data/features/step_definitions/shared_steps.rb +48 -0
  8. data/lib/data/licenses/Python.txt +47 -0
  9. data/lib/license_finder.rb +4 -2
  10. data/lib/license_finder/bundle.rb +15 -9
  11. data/lib/license_finder/dependency_manager.rb +14 -1
  12. data/lib/license_finder/license/apache2.rb +1 -1
  13. data/lib/license_finder/license/bsd.rb +1 -1
  14. data/lib/license_finder/license/mit.rb +1 -1
  15. data/lib/license_finder/license/python.rb +8 -0
  16. data/lib/license_finder/npm.rb +56 -0
  17. data/lib/license_finder/{bundled_gem.rb → package.rb} +45 -3
  18. data/lib/license_finder/{bundled_gem_saver.rb → package_saver.rb} +15 -13
  19. data/lib/license_finder/pip.rb +59 -0
  20. data/lib/license_finder/reports/html_report.rb +10 -1
  21. data/lib/templates/html_report.erb +14 -12
  22. data/license_finder.gemspec +3 -1
  23. data/readme.md +10 -4
  24. data/release/manual_instructions.md +7 -6
  25. data/spec/lib/license_finder/bundle_spec.rb +24 -0
  26. data/spec/lib/license_finder/dependency_manager_spec.rb +4 -4
  27. data/spec/lib/license_finder/license/python_spec.rb +7 -0
  28. data/spec/lib/license_finder/npm_spec.rb +79 -0
  29. data/spec/lib/license_finder/{bundled_gem_saver_spec.rb → package_saver_spec.rb} +17 -17
  30. data/spec/lib/license_finder/{bundled_gem_spec.rb → package_spec.rb} +20 -2
  31. data/spec/lib/license_finder/pip_spec.rb +89 -0
  32. data/spec/spec_helper.rb +1 -0
  33. data/spec/support/license_examples.rb +1 -1
  34. metadata +58 -8
data/CHANGELOG.rdoc CHANGED
@@ -1,4 +1,14 @@
1
- === TBD
1
+ === 0.9.2 / 2013-08-17
2
+
3
+ * Features
4
+
5
+ * Support for python and node.js projects
6
+
7
+ * Bugfixes
8
+
9
+ * Fix HTML output in firefox
10
+
11
+ === 0.9.1 / 2013-07-30
2
12
 
3
13
  * Features
4
14
 
@@ -0,0 +1,9 @@
1
+ Feature: Tracking Node Dependencies
2
+ So that I can track Node dependencies
3
+ As an application developer using license finder
4
+ I want to be able to manage Node dependencies
5
+
6
+ Scenario: See the dependencies from the package file
7
+ Given A package file with dependencies
8
+ When I run license_finder
9
+ Then I should see a Node dependency with a license
@@ -0,0 +1,9 @@
1
+ Feature: Tracking Python Dependencies
2
+ So that I can track Python dependencies
3
+ As an application developer using license finder
4
+ I want to be able to manage Python dependencies
5
+
6
+ Scenario: See the dependencies from the requirements file
7
+ Given A requirements file with dependencies
8
+ When I run license_finder
9
+ Then I should see a Python dependency with a license
@@ -49,9 +49,11 @@ end
49
49
  Then(/^I should see only see GPL liceneses as unapproved in the html$/) do
50
50
  html = File.read(@user.dependencies_html_path)
51
51
  page = Capybara.string(html)
52
- page.should have_content '9 total'
52
+ page.should have_content '12 total'
53
53
  page.should have_content '1 unapproved'
54
54
  page.should have_content '1 GPL'
55
+ page.should have_content '1 other'
56
+ page.should have_content '9 MIT'
55
57
  end
56
58
 
57
59
  def is_html_status?(gem, approval)
@@ -0,0 +1,8 @@
1
+ Given(/^A package file with dependencies$/) do
2
+ @user = ::DSL::User.new
3
+ @user.create_node_app
4
+ end
5
+
6
+ Then(/^I should see a Node dependency with a license$/) do
7
+ @output.should =~ /^jshint, 2.1.9, MIT$/
8
+ end
@@ -0,0 +1,8 @@
1
+ Given(/^A requirements file with dependencies$/) do
2
+ @user = ::DSL::User.new
3
+ @user.create_python_app
4
+ end
5
+
6
+ Then(/^I should see a Python dependency with a license$/) do
7
+ @output.should =~ /^argparse, 1.2.1, Python Software Foundation License$/
8
+ end
@@ -30,6 +30,28 @@ end
30
30
 
31
31
  module DSL
32
32
  class User
33
+ def create_python_app
34
+ reset_projects!
35
+
36
+ `mkdir -p #{app_path}`
37
+ `cd #{app_path} && touch requirements.txt`
38
+
39
+ add_pip_dependency('argparse==1.2.1')
40
+
41
+ pip_install
42
+ end
43
+
44
+ def create_node_app
45
+ reset_projects!
46
+
47
+ `mkdir -p #{app_path}`
48
+ `cd #{app_path} && touch package.json`
49
+
50
+ add_npm_dependency('jshint', '2.1.9')
51
+
52
+ npm_install
53
+ end
54
+
33
55
  def create_nonrails_app
34
56
  reset_projects!
35
57
 
@@ -160,12 +182,30 @@ module DSL
160
182
  add_to_gemfile(line)
161
183
  end
162
184
 
185
+ def add_pip_dependency(dependency)
186
+ add_to_requirements(dependency)
187
+ end
188
+
189
+ def add_npm_dependency(dependency, version)
190
+ line = "{\"dependencies\" : {\"#{dependency}\": \"#{version}\"}}"
191
+
192
+ add_to_package(line)
193
+ end
194
+
163
195
  def bundle_app
164
196
  Bundler.with_clean_env do
165
197
  `bundle install --gemfile=#{File.join(app_path, "Gemfile")} --path=#{bundle_path}`
166
198
  end
167
199
  end
168
200
 
201
+ def pip_install
202
+ `cd #{app_path} && pip install -r requirements.txt`
203
+ end
204
+
205
+ def npm_install
206
+ `cd #{app_path} && npm install 2>/dev/null`
207
+ end
208
+
169
209
  def modifying_dependencies_file
170
210
  FileUtils.mkdir_p(File.dirname(dependencies_file_path))
171
211
  File.open(dependencies_file_path, 'w+') { |f| yield f }
@@ -181,6 +221,14 @@ module DSL
181
221
  `echo #{line.inspect} >> #{File.join(app_path, "Rakefile")}`
182
222
  end
183
223
 
224
+ def add_to_requirements(line)
225
+ `echo #{line.inspect} >> #{File.join(app_path, "requirements.txt")}`
226
+ end
227
+
228
+ def add_to_package(line)
229
+ `echo #{line.inspect} >> #{File.join(app_path, "package.json")}`
230
+ end
231
+
184
232
  def app_name
185
233
  "my_app"
186
234
  end
@@ -0,0 +1,47 @@
1
+ PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
2
+ --------------------------------------------
3
+
4
+ 1. This LICENSE AGREEMENT is between the Python Software Foundation
5
+ ("PSF"), and the Individual or Organization ("Licensee") accessing and
6
+ otherwise using this software ("Python") in source or binary form and
7
+ its associated documentation.
8
+
9
+ 2. Subject to the terms and conditions of this License Agreement, PSF hereby
10
+ grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
11
+ analyze, test, perform and/or display publicly, prepare derivative works,
12
+ distribute, and otherwise use Python alone or in any derivative version,
13
+ provided, however, that PSF's License Agreement and PSF's notice of copyright,
14
+ i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
15
+ 2011, 2012, 2013 Python Software Foundation; All Rights Reserved" are retained
16
+ in Python alone or in any derivative version prepared by Licensee.
17
+
18
+ 3. In the event Licensee prepares a derivative work that is based on
19
+ or incorporates Python or any part thereof, and wants to make
20
+ the derivative work available to others as provided herein, then
21
+ Licensee hereby agrees to include in any such work a brief summary of
22
+ the changes made to Python.
23
+
24
+ 4. PSF is making Python available to Licensee on an "AS IS"
25
+ basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
26
+ IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
27
+ DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
28
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
29
+ INFRINGE ANY THIRD PARTY RIGHTS.
30
+
31
+ 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
32
+ FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
33
+ A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
34
+ OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
35
+
36
+ 6. This License Agreement will automatically terminate upon a material
37
+ breach of its terms and conditions.
38
+
39
+ 7. Nothing in this License Agreement shall be deemed to create any
40
+ relationship of agency, partnership, or joint venture between PSF and
41
+ Licensee. This License Agreement does not grant permission to use PSF
42
+ trademarks or trade name in a trademark sense to endorse or promote
43
+ products or services of Licensee, or any third party.
44
+
45
+ 8. By copying, installing or otherwise using Python, Licensee
46
+ agrees to be bound by the terms and conditions of this License
47
+ Agreement.
@@ -8,13 +8,15 @@ module LicenseFinder
8
8
  Error = Class.new(StandardError)
9
9
 
10
10
  autoload :Bundle, 'license_finder/bundle'
11
- autoload :BundledGem, 'license_finder/bundled_gem'
12
- autoload :BundledGemSaver, 'license_finder/bundled_gem_saver'
11
+ autoload :PackageSaver, 'license_finder/package_saver'
13
12
  autoload :CLI, 'license_finder/cli'
14
13
  autoload :Configuration, 'license_finder/configuration'
15
14
  autoload :DependencyManager, 'license_finder/dependency_manager'
16
15
  autoload :License, 'license_finder/license'
17
16
  autoload :LicenseUrl, 'license_finder/license_url'
17
+ autoload :NPM, 'license_finder/npm'
18
+ autoload :Pip, 'license_finder/pip'
19
+ autoload :Package, 'license_finder/package'
18
20
  autoload :Platform, 'license_finder/platform'
19
21
  autoload :PossibleLicenseFile, 'license_finder/possible_license_file'
20
22
  autoload :PossibleLicenseFiles, 'license_finder/possible_license_files'
@@ -4,12 +4,22 @@ module LicenseFinder
4
4
  class Bundle
5
5
  attr_writer :ignore_groups
6
6
 
7
- def self.current_gems(config, bundler_definition=nil)
8
- new(config, bundler_definition).gems
7
+ class << self
8
+ def current_gems(config, bundler_definition=nil)
9
+ new(config, bundler_definition).gems
10
+ end
11
+
12
+ def has_gemfile?
13
+ File.exists?(gemfile_path)
14
+ end
15
+
16
+ def gemfile_path
17
+ Pathname.new("Gemfile").expand_path
18
+ end
9
19
  end
10
20
 
11
21
  def initialize(config=nil, bundler_definition=nil)
12
- @definition = bundler_definition || Bundler::Definition.build(gemfile_path, lockfile_path, nil)
22
+ @definition = bundler_definition || Bundler::Definition.build(self.class.gemfile_path, lockfile_path, nil)
13
23
  @config ||= config
14
24
  end
15
25
 
@@ -24,7 +34,7 @@ module LicenseFinder
24
34
  formatted_name = format_name(spec)
25
35
  gem_names_cache[format_name(spec)] = true
26
36
 
27
- BundledGem.new(spec, dependency)
37
+ Package.new(spec, dependency)
28
38
  end
29
39
 
30
40
  @gems.each do |gem|
@@ -49,12 +59,8 @@ module LicenseFinder
49
59
  definition.groups - ignore_groups.map(&:to_sym)
50
60
  end
51
61
 
52
- def gemfile_path
53
- Pathname.new("Gemfile").expand_path
54
- end
55
-
56
62
  def lockfile_path
57
- gemfile_path.dirname.join('Gemfile.lock')
63
+ self.class.gemfile_path.dirname.join('Gemfile.lock')
58
64
  end
59
65
 
60
66
  def children_for(gem, cache)
@@ -4,7 +4,20 @@ module LicenseFinder
4
4
  module DependencyManager
5
5
  def self.sync_with_bundler
6
6
  modifying {
7
- current_dependencies = BundledGemSaver.save_gems(Bundle.current_gems(LicenseFinder.config))
7
+ current_dependencies = []
8
+
9
+ if Bundle.has_gemfile?
10
+ current_dependencies += PackageSaver.save_packages(Bundle.current_gems(LicenseFinder.config))
11
+ end
12
+
13
+ if Pip.has_requirements?
14
+ current_dependencies += PackageSaver.save_packages(Pip.current_dists())
15
+ end
16
+
17
+ if NPM.has_package?
18
+ current_dependencies += PackageSaver.save_packages(NPM.current_modules())
19
+ end
20
+
8
21
  Dependency.bundler.obsolete(current_dependencies).each(&:destroy)
9
22
  }
10
23
  end
@@ -1,5 +1,5 @@
1
1
  class LicenseFinder::License::Apache2 < LicenseFinder::License::Base
2
- self.alternative_names = ["Apache 2.0", "Apache2", "Apache-2.0"]
2
+ self.alternative_names = ["Apache 2.0", "Apache2", "Apache-2.0", "Apache Software License"]
3
3
  self.license_url = "http://www.apache.org/licenses/LICENSE-2.0.txt"
4
4
 
5
5
  def self.pretty_name
@@ -1,4 +1,4 @@
1
1
  class LicenseFinder::License::BSD < LicenseFinder::License::Base
2
- self.alternative_names = ["BSD4", "bsd-old", "4-clause BSD", "BSD-4-Clause"]
2
+ self.alternative_names = ["BSD4", "bsd-old", "4-clause BSD", "BSD-4-Clause", "BSD License"]
3
3
  self.license_url = "http://en.wikipedia.org/wiki/BSD_licenses#4-clause_license_.28original_.22BSD_License.22.29"
4
4
  end
@@ -1,6 +1,6 @@
1
1
  class LicenseFinder::License::MIT < LicenseFinder::License::Base
2
2
  self.license_url = "http://opensource.org/licenses/mit-license"
3
- self.alternative_names = ["Expat"]
3
+ self.alternative_names = ["Expat", "MIT license", "MIT License"]
4
4
 
5
5
  HEADER_REGEX = /The MIT Licen[sc]e/
6
6
  ONE_LINER_REGEX = /is released under the MIT licen[sc]e/
@@ -0,0 +1,8 @@
1
+ class LicenseFinder::License::Python < LicenseFinder::License::Base
2
+ self.alternative_names = ["PSF", "Python Software Foundation License"]
3
+ self.license_url = "http://hg.python.org/cpython/raw-file/89ce323357db/LICENSE"
4
+
5
+ def self.pretty_name
6
+ 'Python Software Foundation License'
7
+ end
8
+ end
@@ -0,0 +1,56 @@
1
+ require 'json'
2
+ require 'license_finder/package'
3
+
4
+ module LicenseFinder
5
+ class NPM
6
+
7
+ def self.current_modules
8
+ return @modules if @modules
9
+
10
+ output = `npm list --json --long`
11
+
12
+ json = JSON(output)
13
+
14
+ @modules = json.fetch("dependencies",[]).map do |node_module|
15
+ node_module = node_module[1]
16
+
17
+ Package.new(OpenStruct.new(
18
+ :name => node_module.fetch("name", nil),
19
+ :version => node_module.fetch("version", nil),
20
+ :full_gem_path => node_module.fetch("path", nil),
21
+ :license => self.harvest_license(node_module),
22
+ :summary => node_module.fetch("description", nil),
23
+ :description => node_module.fetch("readme", nil)
24
+ ))
25
+ end
26
+ end
27
+
28
+ def self.has_package?
29
+ File.exists?(package_path)
30
+ end
31
+
32
+ private
33
+
34
+ def self.package_path
35
+ Pathname.new('package.json').expand_path
36
+ end
37
+
38
+ def self.harvest_license(node_module)
39
+ license = node_module.fetch("licenses", []).first
40
+
41
+ if license
42
+ license = license.fetch("type", nil)
43
+ end
44
+
45
+ if license.nil?
46
+ license = node_module.fetch("license", nil)
47
+
48
+ if license.is_a? Hash
49
+ license = license.fetch("type", nil)
50
+ end
51
+ end
52
+
53
+ license
54
+ end
55
+ end
56
+ end
@@ -1,5 +1,5 @@
1
1
  module LicenseFinder
2
- class BundledGem
2
+ class Package
3
3
  attr_reader :parents, :spec, :bundler_dependency, :children
4
4
 
5
5
  def initialize(spec, bundler_dependency = nil)
@@ -24,6 +24,14 @@ module LicenseFinder
24
24
  @spec.version.to_s
25
25
  end
26
26
 
27
+ def summary
28
+ @spec.summary
29
+ end
30
+
31
+ def description
32
+ @spec.description
33
+ end
34
+
27
35
  def groups
28
36
  @groups ||= bundler_dependency ? bundler_dependency.groups : []
29
37
  end
@@ -49,7 +57,41 @@ module LicenseFinder
49
57
  def determine_license
50
58
  return @spec.license if @spec.license
51
59
 
52
- license_files.map(&:license).compact.first || 'other'
60
+ license = license_files.map(&:license).compact.first
61
+ license || "other"
62
+ end
63
+ end
64
+
65
+ class PythonPackage < Package
66
+ def determine_license
67
+ return @spec.license if @spec.license
68
+
69
+ license = super
70
+
71
+ if !license || license == "other"
72
+ license = Pip.license_for self
73
+ end
74
+
75
+ license
76
+ end
77
+
78
+ def summary
79
+ json.fetch("summary", "")
80
+ end
81
+
82
+ def description
83
+ json.fetch("description", "")
84
+ end
85
+
86
+ def json
87
+ return @json if @json
88
+
89
+ response = HTTParty.get("https://pypi.python.org/pypi/#{dependency_name}/#{dependency_version}/json")
90
+ if response.code == 200
91
+ @json = JSON.parse(response.body).fetch("info", {})
92
+ end
93
+
94
+ @json ||= {}
53
95
  end
54
96
  end
55
- end
97
+ end
@@ -1,24 +1,26 @@
1
+ require 'forwardable'
2
+
1
3
  module LicenseFinder
2
- class BundledGemSaver
4
+ class PackageSaver
3
5
  extend Forwardable
4
- def_delegators :spec, :name, :version, :summary, :description, :homepage
5
- def_delegators :bundled_gem, :bundler_dependency, :license, :children, :groups
6
+ def_delegators :spec, :name, :version, :homepage
7
+ def_delegators :package, :bundler_dependency, :license, :children, :groups, :summary, :description
6
8
 
7
- attr_reader :dependency, :bundled_gem
9
+ attr_reader :dependency, :package
8
10
 
9
- def self.find_or_create_by_name(bundled_gem)
10
- dependency = Dependency.named(bundled_gem.spec.name)
11
- new(dependency, bundled_gem)
11
+ def self.find_or_create_by_name(package)
12
+ dependency = Dependency.named(package.spec.name)
13
+ new(dependency, package)
12
14
  end
13
15
 
14
- def self.save_gems(current_gems)
15
- current_gems.map do |bundled_gem|
16
- BundledGemSaver.find_or_create_by_name(bundled_gem).save
16
+ def self.save_packages(current_packages)
17
+ current_packages.map do |package|
18
+ PackageSaver.find_or_create_by_name(package).save
17
19
  end
18
20
  end
19
21
 
20
- def initialize(dependency, bundled_gem)
21
- @bundled_gem = bundled_gem
22
+ def initialize(dependency, package)
23
+ @package = package
22
24
  @dependency = dependency
23
25
  end
24
26
 
@@ -35,7 +37,7 @@ module LicenseFinder
35
37
  private
36
38
 
37
39
  def spec
38
- bundled_gem.spec
40
+ package.spec
39
41
  end
40
42
 
41
43
  def apply_dependency_definition