license_finder 0.9.1-java → 0.9.2-java

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