license_finder 0.4.5 → 0.5.0

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 (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