license_finder 0.4.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/README.markdown +43 -11
  2. data/bin/license_finder +2 -5
  3. data/features/executables/license_finder.feature +19 -0
  4. data/features/rake_tasks/action_items.feature +18 -4
  5. data/features/rake_tasks/action_items_ok.feature +10 -7
  6. data/features/rake_tasks/generate_dependencies.feature +43 -12
  7. data/features/rake_tasks/init.feature +8 -1
  8. data/features/rake_tasks/regressions.feature +18 -0
  9. data/features/step_definitions/steps.rb +163 -43
  10. data/lib/license_finder.rb +9 -4
  11. data/lib/license_finder/{gem_spec_details.rb → bundled_gem.rb} +12 -41
  12. data/lib/license_finder/bundler_dependency_query.rb +51 -0
  13. data/lib/license_finder/cli.rb +16 -0
  14. data/lib/license_finder/dependency.rb +80 -28
  15. data/lib/license_finder/dependency_list.rb +20 -35
  16. data/lib/license_finder/finder.rb +2 -2
  17. data/lib/license_finder/license.rb +74 -0
  18. data/lib/license_finder/license/apache.rb +5 -0
  19. data/lib/license_finder/license/bsd.rb +2 -0
  20. data/lib/license_finder/license/gplv2.rb +2 -0
  21. data/lib/license_finder/license/isc.rb +2 -0
  22. data/lib/license_finder/license/lgpl.rb +2 -0
  23. data/lib/license_finder/license/mit.rb +20 -0
  24. data/lib/license_finder/license/new_bsd.rb +5 -0
  25. data/lib/license_finder/license/ruby.rb +11 -0
  26. data/lib/license_finder/license/simplified_bsd.rb +5 -0
  27. data/lib/license_finder/{file_parser.rb → possible_license_file.rb} +9 -17
  28. data/lib/tasks/license_finder.rake +8 -8
  29. data/lib/templates/{Apache-2.0-body → Apache.txt} +0 -0
  30. data/lib/templates/BSD.txt +24 -0
  31. data/lib/templates/{GPL-2.0-body → GPLv2.txt} +0 -0
  32. data/lib/templates/{ISC-body → ISC.txt} +0 -0
  33. data/lib/templates/{LGPL-body → LGPL.txt} +0 -0
  34. data/lib/templates/{MIT-body → MIT.txt} +0 -0
  35. data/lib/templates/NewBSD.txt +21 -0
  36. data/lib/templates/Ruby.txt +52 -0
  37. data/lib/templates/SimplifiedBSD.txt +23 -0
  38. data/license_finder.gemspec +4 -3
  39. data/spec/fixtures/{no_license/.gitkeep → license_names/Licence.rdoc} +0 -0
  40. data/spec/lib/license_finder/bundled_gem_spec.rb +148 -0
  41. data/spec/lib/license_finder/dependency_list_spec.rb +133 -144
  42. data/spec/lib/license_finder/dependency_spec.rb +189 -5
  43. data/spec/lib/license_finder/license/apache_spec.rb +7 -0
  44. data/spec/lib/license_finder/license/bsd_spec.rb +41 -0
  45. data/spec/lib/license_finder/license/gplv2_spec.rb +7 -0
  46. data/spec/lib/license_finder/license/isc_spec.rb +7 -0
  47. data/spec/lib/license_finder/license/lgpl_spec.rb +7 -0
  48. data/spec/lib/license_finder/license/mit_spec.rb +33 -0
  49. data/spec/lib/license_finder/license/new_bsd_spec.rb +35 -0
  50. data/spec/lib/license_finder/license/ruby_spec.rb +19 -0
  51. data/spec/lib/license_finder/license/simplified_bsd_spec.rb +7 -0
  52. data/spec/lib/license_finder/possible_license_file_spec.rb +42 -0
  53. data/spec/spec_helper.rb +6 -0
  54. data/spec/support/license_examples.rb +24 -0
  55. metadata +89 -33
  56. data/lib/license_finder/license_file.rb +0 -98
  57. data/spec/fixtures/apache_licensed_gem/LICENSE +0 -191
  58. data/spec/fixtures/gplv2_licensed_gem/LICENSE +0 -339
  59. data/spec/fixtures/isc_licensed_gem/LICENSE +0 -10
  60. data/spec/fixtures/lgpl_licensed_gem/LICENSE +0 -165
  61. data/spec/fixtures/mit_licensed_gem_in_README/README.rdoc +0 -222
  62. data/spec/fixtures/mit_licensed_gem_via_url/README +0 -210
  63. data/spec/fixtures/mit_licensed_with_hashes/MIT-LICENSE +0 -20
  64. data/spec/lib/license_finder/file_parser_spec.rb +0 -16
  65. data/spec/lib/license_finder/gem_spec_details_spec.rb +0 -229
  66. data/spec/lib/license_finder/license_file_spec.rb +0 -155
@@ -32,13 +32,18 @@ module LicenseFinder
32
32
  def self.config
33
33
  @config ||= Configuration.new
34
34
  end
35
+
36
+ def self.load_rake_tasks
37
+ load 'tasks/license_finder.rake'
38
+ end
35
39
  end
36
40
 
37
41
  require 'license_finder/railtie' if defined?(Rails)
42
+ require 'license_finder/bundler_dependency_query'
38
43
  require 'license_finder/finder'
39
- require 'license_finder/gem_spec_details'
40
- require 'license_finder/file_parser'
41
- require 'license_finder/license_file'
42
-
44
+ require 'license_finder/bundled_gem'
45
+ require 'license_finder/license'
46
+ require 'license_finder/possible_license_file'
43
47
  require 'license_finder/dependency'
44
48
  require 'license_finder/dependency_list'
49
+ require 'license_finder/cli'
@@ -1,6 +1,6 @@
1
1
  module LicenseFinder
2
- class GemSpecDetails
3
- LICENSE_FILE_NAMES = '*{LICENSE,License,COPYING,README,Readme,ReadMe}*' # follows Dir.glob format
2
+ class BundledGem
3
+ LICENSE_FILE_NAMES = '*{LICENSE,License,Licence,COPYING,README,Readme,ReadMe}*' # follows Dir.glob format
4
4
  README_FILE_NAMES = '*{README,Readme,ReadMe}*' # follows Dir.glob format
5
5
 
6
6
  def initialize(spec)
@@ -22,26 +22,22 @@ module LicenseFinder
22
22
  end
23
23
 
24
24
  def dependency
25
- license = determine_license
26
-
27
25
  @dependency ||= Dependency.new(
28
26
  'name' => @spec.name,
29
- 'version' => @spec.version,
30
- 'license' => license,
27
+ 'version' => @spec.version.to_s,
28
+ 'license' => determine_license,
31
29
  'license_files' => license_files.map(&:full_file_path),
32
- 'readme_files' => readme_files.map(&:full_file_path)
30
+ 'readme_files' => readme_files.map(&:full_file_path),
31
+ 'source' => 'bundle',
32
+ 'summary' => @spec.summary,
33
+ 'description' => @spec.description
33
34
  )
34
35
  end
35
36
 
36
37
  def determine_license
37
38
  return @spec.license if @spec.license
38
- return 'MIT' if license_files.any?{|f| f.mit_license_body? || f.mit_license_header?}
39
- return 'Apache 2.0' if license_files.any?(&:apache_license_body?)
40
- return 'GPLv2' if license_files.any?(&:gplv2_license_body?)
41
- return 'ruby' if license_files.any?(&:ruby_license_body?)
42
- return 'LGPL' if license_files.any?(&:lgpl_license_body?)
43
- return 'ISC' if license_files.any?(&:isc_license_body?)
44
- 'other'
39
+
40
+ license_files.map(&:license).compact.first || 'other'
45
41
  end
46
42
 
47
43
  def license_files
@@ -54,9 +50,7 @@ module LicenseFinder
54
50
 
55
51
  def readme_files
56
52
  Dir.glob(File.join(install_path, '**', README_FILE_NAMES)).map do |path|
57
- file = LicenseFile.new(install_path, path)
58
- file.include_license_text = include_license_text?
59
- file
53
+ get_file_for_path path
60
54
  end
61
55
  end
62
56
 
@@ -64,37 +58,14 @@ module LicenseFinder
64
58
  spec.full_gem_path
65
59
  end
66
60
 
67
- def to_s(include_license_text = true)
68
- self.include_license_text = include_license_text
69
-
70
- { name => to_hash }.to_yaml
71
- end
72
-
73
- def to_hash
74
- {
75
- 'dependency_name' => dependency_name,
76
- 'dependency_version' => dependency_version,
77
- 'install_path' => install_path,
78
- 'license_files' => license_files.map { |file| file.to_hash }
79
- }
80
- end
81
-
82
61
  def sort_order
83
62
  dependency_name.downcase
84
63
  end
85
64
 
86
65
  private
87
66
 
88
- attr_writer :include_license_text
89
-
90
- def include_license_text?
91
- @include_license_text
92
- end
93
-
94
67
  def get_file_for_path(path)
95
- file = LicenseFile.new(install_path, path)
96
- file.include_license_text = include_license_text?
97
- file
68
+ PossibleLicenseFile.new(install_path, path)
98
69
  end
99
70
 
100
71
  def paths_for_files_in_license_directory(path)
@@ -0,0 +1,51 @@
1
+ module LicenseFinder
2
+ class BundlerDependencyQuery
3
+ def dependencies
4
+ bundler_definition.specs_for(requested_groups).map do |spec|
5
+ dependency = define_a_new_dependency_from_a_gemspec(spec)
6
+ add_additional_information_from_bundler_to_a_dependency(dependency)
7
+ end
8
+ end
9
+
10
+ private
11
+
12
+ def add_additional_information_from_bundler_to_a_dependency(dependency)
13
+ bundler_dependency = find_bundlers_representation_of_a_dependency_by_name(dependency.name)
14
+
15
+ if bundler_dependency
16
+ dependency.bundler_groups = bundler_dependency.groups
17
+ end
18
+
19
+ dependency
20
+ end
21
+
22
+ def define_a_new_dependency_from_a_gemspec(gemspec)
23
+ BundledGem.new(gemspec).dependency
24
+ end
25
+
26
+ def find_bundlers_representation_of_a_dependency_by_name(name)
27
+ bundler_dependencies.detect { |dep| dep.name == name }
28
+ end
29
+
30
+ def requested_groups
31
+ bundler_definition.groups - LicenseFinder.config.ignore_groups
32
+ end
33
+
34
+ def gemfile_path
35
+ Pathname.new("Gemfile").expand_path
36
+ end
37
+
38
+ def lockfile_path
39
+ root = gemfile_path.dirname
40
+ root.join('Gemfile.lock')
41
+ end
42
+
43
+ def bundler_dependencies
44
+ @bundler_dependencies ||= bundler_definition.dependencies
45
+ end
46
+
47
+ def bundler_definition
48
+ @bundler_definition ||= Bundler::Definition.build(gemfile_path, lockfile_path, nil)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,16 @@
1
+ module LicenseFinder
2
+ class CLI
3
+ def check_for_action_items
4
+ found = LicenseFinder::Finder.new.action_items
5
+
6
+ if found.size == 0
7
+ puts "All gems are approved for use"
8
+ exit 0
9
+ else
10
+ puts "Dependencies that need approval:"
11
+ puts found
12
+ exit 1
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,6 +1,12 @@
1
+ # encoding: UTF-8
2
+ require "erb"
3
+
1
4
  module LicenseFinder
2
5
  class Dependency
3
- attr_reader :name, :version, :license, :approved, :license_url, :notes, :license_files, :readme_files
6
+ attr_accessor :name, :version, :license, :approved, :license_url, :notes, :license_files,
7
+ :readme_files, :source, :bundler_groups
8
+
9
+ attr_reader :summary, :description
4
10
 
5
11
  def self.from_hash(attrs)
6
12
  attrs['license_files'] = attrs['license_files'].map { |lf| lf['path'] } if attrs['license_files']
@@ -10,6 +16,7 @@ module LicenseFinder
10
16
  end
11
17
 
12
18
  def initialize(attributes = {})
19
+ @source = attributes['source']
13
20
  @name = attributes['name']
14
21
  @version = attributes['version']
15
22
  @license = attributes['license']
@@ -18,44 +25,89 @@ module LicenseFinder
18
25
  @notes = attributes['notes'] || ''
19
26
  @license_files = attributes['license_files'] || []
20
27
  @readme_files = attributes['readme_files'] || []
28
+ @bundler_groups = attributes['bundler_groups'] || []
29
+ @summary = attributes['summary']
30
+ @description = attributes['description']
21
31
  end
22
32
 
23
- def to_yaml_entry
24
- attrs = "- name: \"#{name}\"\n version: \"#{version}\"\n license: \"#{license}\"\n approved: #{approved}\n license_url: \"#{license_url}\"\n notes: \"#{notes}\"\n"
25
- attrs << " license_files:\n"
26
- if !self.license_files.empty?
27
- self.license_files.each do |lf|
28
- attrs << " - path: \"#{lf}\"\n"
33
+ def merge(other)
34
+ raise "Cannot merge dependencies with different names. Expected #{name}, was #{other.name}." unless other.name == name
35
+
36
+ merged = self.class.new(
37
+ 'name' => name,
38
+ 'version' => other.version,
39
+ 'license_files' => other.license_files,
40
+ 'readme_files' => other.readme_files,
41
+ 'license_url' => other.license_url,
42
+ 'notes' => notes,
43
+ 'source' => other.source,
44
+ 'summary' => other.summary,
45
+ 'description' => other.description,
46
+ 'bundler_groups' => other.bundler_groups,
47
+ )
48
+
49
+ case other.license
50
+ when license, 'other'
51
+ merged.license = license
52
+ merged.approved = approved
53
+ else
54
+ merged.license = other.license
55
+ merged.approved = other.approved
56
+ end
57
+
58
+ merged
59
+ end
60
+
61
+ def as_yaml
62
+ attrs = {
63
+ 'name' => name,
64
+ 'version' => version,
65
+ 'license' => license,
66
+ 'approved' => approved,
67
+ 'source' => source,
68
+ 'license_url' => license_url,
69
+ 'notes' => notes,
70
+ 'license_files' => nil,
71
+ 'readme_files' => nil
72
+ }
73
+
74
+ unless license_files.empty?
75
+ attrs['license_files'] = license_files.map do |file|
76
+ {'path' => file}
29
77
  end
30
78
  end
31
- attrs << " readme_files:\n"
32
- if !self.readme_files.empty?
33
- self.readme_files.each do |rf|
34
- attrs << " - path: \"#{rf}\"\n"
79
+
80
+ unless readme_files.empty?
81
+ attrs['readme_files'] = readme_files.map do |file|
82
+ {'path' => file}
35
83
  end
36
84
  end
85
+
37
86
  attrs
38
87
  end
39
88
 
89
+ def to_yaml
90
+ as_yaml.to_yaml
91
+ end
92
+
40
93
  def to_s
41
- url = ", #{license_url}" if license_url != ''
42
- str = "#{name} #{version}, #{license}#{url}"
43
- if license == 'other'
44
- str << "\n license files:"
45
- unless self.license_files.empty?
46
- self.license_files.each do |lf|
47
- str << "\n #{lf}"
48
- end
49
- end
50
- str << "\n readme files:"
51
- unless self.readme_files.empty?
52
- self.readme_files.each do |lf|
53
- str << "\n #{lf}"
54
- end
55
- end
56
- end
94
+ template = ERB.new <<-TEMPLATE
95
+ <%= attributes.join(", ") %>
96
+ <% if license == 'other' %>
97
+ <% unless license_files.empty? %>
98
+ license files:
99
+ <%= license_files.join("\n ") %>
100
+ <% end %>
101
+ <% unless readme_files.empty? %>
102
+ readme files:
103
+ <%= readme_files.join("\n ") %>
104
+ <% end %>
105
+ <% end%>
106
+ TEMPLATE
107
+
108
+ attributes = ["#{name} #{version}".strip, license, license_url, summary, description, bundler_groups].flatten.compact.reject {|a| a == ""}
57
109
 
58
- str
110
+ template.result(binding).gsub(/(^|\n)\s*(\n|$)/, '\1')
59
111
  end
60
112
  end
61
113
  end
@@ -4,14 +4,7 @@ module LicenseFinder
4
4
  attr_reader :dependencies
5
5
 
6
6
  def self.from_bundler
7
- gemfile = Pathname.new("Gemfile").expand_path
8
- root = gemfile.dirname
9
- lockfile = root.join('Gemfile.lock')
10
- definition = Bundler::Definition.build(gemfile, lockfile, nil)
11
-
12
- groups = definition.groups - LicenseFinder.config.ignore_groups
13
-
14
- new(definition.specs_for(groups).map { |spec| GemSpecDetails.new(spec).dependency })
7
+ new(BundlerDependencyQuery.new.dependencies)
15
8
  end
16
9
 
17
10
  def initialize(dependencies)
@@ -25,48 +18,40 @@ module LicenseFinder
25
18
 
26
19
  def merge(new_list)
27
20
  deps = new_list.dependencies.map do |new_dep|
28
- old_dep = self.dependencies.detect { |d| d.name == new_dep.name }
29
- if old_dep && old_dep.license == new_dep.license
30
- Dependency.new(
31
- 'name' => new_dep.name,
32
- 'version' => new_dep.version,
33
- 'license' => new_dep.license,
34
- 'approved' => (old_dep.approved || new_dep.approved),
35
- 'license_url' => old_dep.license_url,
36
- 'notes' => old_dep.notes,
37
- 'license_files' => new_dep.license_files,
38
- 'readme_files' => new_dep.readme_files
39
- )
40
- elsif old_dep && new_dep.license == 'other'
41
- Dependency.new(
42
- 'name' => new_dep.name,
43
- 'version' => new_dep.version,
44
- 'license' => old_dep.license,
45
- 'approved' => old_dep.approved,
46
- 'license_url' => old_dep.license_url,
47
- 'notes' => old_dep.notes,
48
- 'license_files' => new_dep.license_files,
49
- 'readme_files' => new_dep.readme_files
50
- )
21
+ old_dep = dependencies.detect { |d| d.name == new_dep.name }
22
+
23
+ if old_dep
24
+ old_dep.merge(new_dep)
51
25
  else
52
26
  new_dep
53
27
  end
54
28
  end
55
29
 
30
+ deps += dependencies.select { |d| d.source != "bundle" }
31
+
56
32
  self.class.new(deps)
57
33
  end
58
34
 
35
+ def as_yaml
36
+ sorted_dependencies.map(&:as_yaml)
37
+ end
38
+
59
39
  def to_yaml
60
- result = "--- \n"
61
- dependencies.sort_by(&:name).inject(result) { |r, d| r << d.to_yaml_entry; r }
40
+ as_yaml.to_yaml
62
41
  end
63
42
 
64
43
  def to_s
65
- dependencies.sort_by(&:name).map(&:to_s).join("\n")
44
+ sorted_dependencies.map(&:to_s).join
66
45
  end
67
46
 
68
47
  def action_items
69
- dependencies.sort_by(&:name).reject(&:approved).map(&:to_s).join("\n")
48
+ sorted_dependencies.reject(&:approved).map(&:to_s).join
49
+ end
50
+
51
+ private
52
+
53
+ def sorted_dependencies
54
+ dependencies.sort_by(&:name)
70
55
  end
71
56
  end
72
57
  end
@@ -2,7 +2,7 @@ module LicenseFinder
2
2
  class Finder
3
3
  def from_bundler
4
4
  require 'bundler'
5
- Bundler.load.specs.map { |spec| GemSpecDetails.new(spec) }.sort_by &:sort_order
5
+ Bundler.load.specs.map { |spec| BundledGem.new(spec) }.sort_by &:sort_order
6
6
  end
7
7
 
8
8
  def write_files
@@ -11,10 +11,10 @@ module LicenseFinder
11
11
  File.open(LicenseFinder.config.dependencies_yaml, 'w+') do |f|
12
12
  f.puts new_list.to_yaml
13
13
  end
14
+
14
15
  File.open(LicenseFinder.config.dependencies_text, 'w+') do |f|
15
16
  f.puts new_list.to_s
16
17
  end
17
-
18
18
  end
19
19
 
20
20
  def action_items
@@ -0,0 +1,74 @@
1
+ module LicenseFinder::License
2
+ class << self
3
+ def all
4
+ @all ||= []
5
+ end
6
+ end
7
+
8
+ class Text
9
+ def initialize(text)
10
+ @text = normalized(text)
11
+ end
12
+
13
+ def to_s
14
+ @text
15
+ end
16
+
17
+ private
18
+
19
+ def normalized(text)
20
+ text.gsub(/\s+/, ' ').gsub(/['`"]{1,2}/, "\"")
21
+ end
22
+ end
23
+
24
+ class Base
25
+ class << self
26
+ def inherited(descendant)
27
+ LicenseFinder::License.all << descendant
28
+ end
29
+
30
+ def demodulized_name
31
+ name.gsub(/^.*::/, '')
32
+ end
33
+
34
+ def slug
35
+ demodulized_name.downcase
36
+ end
37
+
38
+ def pretty_name
39
+ demodulized_name
40
+ end
41
+
42
+ def license_text
43
+ unless defined?(@license_text)
44
+ template = File.join(LicenseFinder::ROOT_PATH, "templates", "#{demodulized_name}.txt").to_s
45
+
46
+ @license_text = Text.new(File.read(template)).to_s if File.exists?(template)
47
+ end
48
+ @license_text
49
+ end
50
+
51
+ def license_regex
52
+ /#{Regexp.escape(license_text).gsub(/<[^<>]+>/, '(.*)')}/ if license_text
53
+ end
54
+ end
55
+
56
+ def initialize(text)
57
+ self.text = text
58
+ end
59
+
60
+ attr_reader :text
61
+
62
+ def text=(text)
63
+ @text = Text.new(text).to_s
64
+ end
65
+
66
+ def matches?
67
+ !!(text =~ self.class.license_regex if self.class.license_regex)
68
+ end
69
+ end
70
+ end
71
+
72
+ Dir[File.join(File.dirname(__FILE__), 'license', '*.rb')].each do |license|
73
+ require license
74
+ end