license_finder 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +0 -1
- data/bin/license_finder +21 -1
- data/features/approve_dependencies.feature +10 -0
- data/features/license_finder.feature +13 -3
- data/features/license_finder_rake_task.feature +3 -3
- data/features/set_license.feature +14 -0
- data/features/step_definitions/steps.rb +5 -0
- data/lib/license_finder.rb +13 -2
- data/lib/license_finder/bundle.rb +25 -3
- data/lib/license_finder/bundle_syncer.rb +12 -0
- data/lib/license_finder/bundled_gem.rb +12 -1
- data/lib/license_finder/cli.rb +42 -3
- data/lib/license_finder/configuration.rb +1 -31
- data/lib/license_finder/dependency.rb +30 -94
- data/lib/license_finder/dependency_report.rb +30 -0
- data/lib/license_finder/html_report.rb +14 -0
- data/lib/license_finder/persistence.rb +1 -0
- data/lib/license_finder/persistence/yaml.rb +7 -0
- data/lib/license_finder/persistence/yaml/configuration.rb +34 -0
- data/lib/license_finder/persistence/yaml/dependency.rb +127 -0
- data/lib/license_finder/reporter.rb +7 -38
- data/lib/license_finder/source_syncer.rb +40 -0
- data/lib/license_finder/text_report.rb +9 -0
- data/lib/templates/dependency.html.erb +2 -2
- data/lib/templates/html_report.erb +93 -0
- data/lib/templates/text_report.erb +2 -0
- data/license_finder.gemspec +2 -2
- data/{README.markdown → readme.md} +22 -11
- data/spec/lib/license_finder/bundle_spec.rb +58 -0
- data/spec/lib/license_finder/bundle_syncer_spec.rb +22 -0
- data/spec/lib/license_finder/bundled_gem_spec.rb +17 -14
- data/spec/lib/license_finder/cli_spec.rb +38 -0
- data/spec/lib/license_finder/dependency_spec.rb +130 -223
- data/spec/lib/license_finder/html_report_spec.rb +67 -0
- data/spec/lib/license_finder/persistence/yaml/configuration_spec.rb +5 -0
- data/spec/lib/license_finder/persistence/yaml/dependency_spec.rb +5 -0
- data/spec/lib/license_finder/possible_license_file_spec.rb +4 -9
- data/spec/lib/license_finder/reporter_spec.rb +0 -1
- data/spec/lib/license_finder/source_syncer_spec.rb +37 -0
- data/spec/lib/license_finder/text_report_spec.rb +29 -0
- data/spec/lib/license_finder_spec.rb +9 -11
- data/spec/spec_helper.rb +1 -1
- data/spec/support/license_examples.rb +1 -1
- data/spec/support/shared_examples/persistence/configuration.rb +34 -0
- data/spec/support/shared_examples/persistence/dependency.rb +139 -0
- metadata +38 -26
- data/lib/license_finder/dependency_list.rb +0 -80
- data/lib/license_finder/viewable.rb +0 -31
- data/lib/templates/dependency_list.html.erb +0 -38
- data/spec/lib/license_finder/dependency_list_spec.rb +0 -243
@@ -0,0 +1,30 @@
|
|
1
|
+
module LicenseFinder
|
2
|
+
class DependencyReport
|
3
|
+
def self.underscored_name
|
4
|
+
@underscored_name ||= begin
|
5
|
+
str = name.dup
|
6
|
+
str.sub!(/.*::/, '')
|
7
|
+
str.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
8
|
+
str.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
9
|
+
str.downcase!
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(dependencies=[])
|
14
|
+
@dependencies = Array dependencies
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
filename = File.join(File.dirname(__FILE__), '..', 'templates', "#{self.class.underscored_name}.erb")
|
19
|
+
template = ERB.new(File.read(filename))
|
20
|
+
template.result(binding)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
attr_reader :dependencies
|
25
|
+
|
26
|
+
def sorted_dependencies
|
27
|
+
dependencies.sort_by(&:name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module LicenseFinder
|
4
|
+
class HtmlReport < DependencyReport
|
5
|
+
private
|
6
|
+
def unapproved_dependencies
|
7
|
+
dependencies.reject(&:approved)
|
8
|
+
end
|
9
|
+
|
10
|
+
def grouped_dependencies
|
11
|
+
dependencies.group_by(&:license).sort_by { |_, group| group.size }.reverse
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module LicenseFinder
|
2
|
+
module Persistence
|
3
|
+
class Configuration
|
4
|
+
attr_reader :whitelist, :ignore_groups, :dependencies_dir
|
5
|
+
|
6
|
+
def initialize(config={})
|
7
|
+
if File.exists?(config_file_path)
|
8
|
+
yaml = File.read(config_file_path)
|
9
|
+
config = YAML.load(yaml).merge config
|
10
|
+
end
|
11
|
+
|
12
|
+
@whitelist = config['whitelist'] || []
|
13
|
+
@ignore_groups = (config["ignore_groups"] || []).map(&:to_sym)
|
14
|
+
@dependencies_dir = config['dependencies_file_dir'] || '.'
|
15
|
+
end
|
16
|
+
|
17
|
+
def config_file_path
|
18
|
+
File.join('.', 'config', 'license_finder.yml')
|
19
|
+
end
|
20
|
+
|
21
|
+
def dependencies_yaml
|
22
|
+
File.join(dependencies_dir, "dependencies.yml")
|
23
|
+
end
|
24
|
+
|
25
|
+
def dependencies_text
|
26
|
+
File.join(dependencies_dir, "dependencies.txt")
|
27
|
+
end
|
28
|
+
|
29
|
+
def dependencies_html
|
30
|
+
File.join(dependencies_dir, "dependencies.html")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module LicenseFinder
|
2
|
+
module Persistence
|
3
|
+
class Dependency
|
4
|
+
class Database
|
5
|
+
def initialize
|
6
|
+
@dependency_attributes = YAML.load File.read(LicenseFinder.config.dependencies_yaml) if File.exists?(LicenseFinder.config.dependencies_yaml)
|
7
|
+
end
|
8
|
+
|
9
|
+
def find(&block)
|
10
|
+
dependency_attributes.detect &block
|
11
|
+
end
|
12
|
+
|
13
|
+
def update(dependency_hash)
|
14
|
+
destroy_by_name_without_saving dependency_hash['name']
|
15
|
+
dependency_attributes << dependency_hash
|
16
|
+
persist!
|
17
|
+
end
|
18
|
+
|
19
|
+
def delete_all
|
20
|
+
File.delete(LicenseFinder.config.dependencies_yaml) if File.exists?(LicenseFinder.config.dependencies_yaml)
|
21
|
+
@dependency_attributes = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def destroy_by_name(name)
|
25
|
+
destroy_by_name_without_saving name
|
26
|
+
persist!
|
27
|
+
end
|
28
|
+
|
29
|
+
def persist!
|
30
|
+
File.open(LicenseFinder.config.dependencies_yaml, 'w+') do |f|
|
31
|
+
f.write dependency_attributes.to_yaml
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def all
|
36
|
+
dependency_attributes
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def destroy_by_name_without_saving(name)
|
41
|
+
dependency_attributes.reject! { |a| a['name'] == name }
|
42
|
+
end
|
43
|
+
|
44
|
+
def dependency_attributes
|
45
|
+
@dependency_attributes ||= []
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
attr_accessor *LicenseFinder::DEPENDENCY_ATTRIBUTES
|
50
|
+
|
51
|
+
class << self
|
52
|
+
def find_by_name(name)
|
53
|
+
attributes = database.find { |a| a['name'] == name }
|
54
|
+
new(attributes) if attributes
|
55
|
+
end
|
56
|
+
|
57
|
+
def delete_all
|
58
|
+
database.delete_all
|
59
|
+
end
|
60
|
+
|
61
|
+
def all
|
62
|
+
database.all.map { |attributes| new(attributes) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def unapproved
|
66
|
+
all.select {|d| d.approved == false }
|
67
|
+
end
|
68
|
+
|
69
|
+
def update(attributes)
|
70
|
+
database.update attributes
|
71
|
+
end
|
72
|
+
|
73
|
+
def destroy_by_name(name)
|
74
|
+
database.destroy_by_name name
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
def database
|
79
|
+
@database ||= Database.new
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def initialize(attributes = {})
|
84
|
+
update_attributes_without_saving attributes
|
85
|
+
end
|
86
|
+
|
87
|
+
def config
|
88
|
+
LicenseFinder.config
|
89
|
+
end
|
90
|
+
|
91
|
+
def update_attributes new_values
|
92
|
+
update_attributes_without_saving(new_values)
|
93
|
+
save
|
94
|
+
end
|
95
|
+
|
96
|
+
def approved?
|
97
|
+
!!approved
|
98
|
+
end
|
99
|
+
|
100
|
+
def save
|
101
|
+
self.class.update(attributes)
|
102
|
+
end
|
103
|
+
|
104
|
+
def destroy
|
105
|
+
self.class.destroy_by_name(name)
|
106
|
+
end
|
107
|
+
|
108
|
+
def attributes
|
109
|
+
attributes = {}
|
110
|
+
|
111
|
+
LicenseFinder::DEPENDENCY_ATTRIBUTES.each do |attrib|
|
112
|
+
attributes[attrib] = send attrib
|
113
|
+
end
|
114
|
+
|
115
|
+
attributes
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
def update_attributes_without_saving(new_values)
|
120
|
+
new_values.each do |key, value|
|
121
|
+
send("#{key}=", value)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
@@ -1,51 +1,20 @@
|
|
1
1
|
module LicenseFinder
|
2
|
-
|
3
|
-
|
4
|
-
unless File.exists?(LicenseFinder.config.config_file_path)
|
5
|
-
FileUtils.mkdir_p(File.join('.', 'config'))
|
6
|
-
FileUtils.cp(
|
7
|
-
File.join(File.dirname(__FILE__), '..', '..', 'files', 'license_finder.yml'),
|
8
|
-
LicenseFinder.config.config_file_path
|
9
|
-
)
|
10
|
-
end
|
11
|
-
end
|
2
|
+
module Reporter
|
3
|
+
extend self
|
12
4
|
|
13
|
-
def
|
14
|
-
|
15
|
-
@dependency_list = generate_list
|
16
|
-
save_reports
|
17
|
-
end
|
5
|
+
def write_reports
|
6
|
+
dependencies = Dependency.all
|
18
7
|
|
19
|
-
|
20
|
-
|
8
|
+
write_file LicenseFinder.config.dependencies_text, TextReport.new(dependencies).to_s
|
9
|
+
write_file LicenseFinder.config.dependencies_html, HtmlReport.new(dependencies).to_s
|
21
10
|
end
|
22
11
|
|
23
12
|
private
|
24
|
-
|
25
|
-
attr_reader :dependency_list
|
26
|
-
|
27
|
-
def save_reports
|
28
|
-
write_file LicenseFinder.config.dependencies_yaml, dependency_list.to_yaml
|
29
|
-
write_file LicenseFinder.config.dependencies_text, dependency_list.to_s
|
30
|
-
write_file LicenseFinder.config.dependencies_html, dependency_list.to_html
|
31
|
-
end
|
32
|
-
|
33
13
|
def write_file(file_path, content)
|
34
14
|
File.open(file_path, 'w+') do |f|
|
35
15
|
f.puts content
|
36
16
|
end
|
37
17
|
end
|
38
|
-
|
39
|
-
def generate_list
|
40
|
-
bundler_list = DependencyList.from_bundler
|
41
|
-
|
42
|
-
if File.exists?(LicenseFinder.config.dependencies_yaml)
|
43
|
-
yml = File.open(LicenseFinder.config.dependencies_yaml).readlines.join
|
44
|
-
existing_list = DependencyList.from_yaml(yml)
|
45
|
-
existing_list.merge(bundler_list)
|
46
|
-
else
|
47
|
-
bundler_list
|
48
|
-
end
|
49
|
-
end
|
50
18
|
end
|
51
19
|
end
|
20
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module LicenseFinder
|
2
|
+
class SourceSyncer
|
3
|
+
def initialize(source_dependencies, dependencies)
|
4
|
+
@source_dependencies = Array source_dependencies
|
5
|
+
@dependencies = dependencies
|
6
|
+
end
|
7
|
+
|
8
|
+
def sync!
|
9
|
+
destroy_obsolete_dependencies
|
10
|
+
update_existing_dependencies
|
11
|
+
create_new_dependencies
|
12
|
+
dependencies
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
attr_accessor :dependencies, :source_dependencies
|
17
|
+
|
18
|
+
def destroy_obsolete_dependencies
|
19
|
+
obsolete_dependencies = dependencies.select {|d| !source_dependencies.detect {|s| s.name == d.name }}
|
20
|
+
obsolete_dependencies.map &:destroy
|
21
|
+
|
22
|
+
self.dependencies -= obsolete_dependencies
|
23
|
+
end
|
24
|
+
|
25
|
+
def update_existing_dependencies
|
26
|
+
dependencies.each do |d|
|
27
|
+
source_dep = source_dependencies.detect { |s| s.name == d.name }
|
28
|
+
d.merge(source_dep)
|
29
|
+
self.source_dependencies -= [source_dep]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_new_dependencies
|
34
|
+
source_dependencies.each do |d|
|
35
|
+
dependencies << d
|
36
|
+
d.save
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -38,7 +38,7 @@
|
|
38
38
|
<dl>
|
39
39
|
<dt>Parents</dt>
|
40
40
|
<% parents.each do |parent| %>
|
41
|
-
<dd><%= parent
|
41
|
+
<dd><%= parent %></dd>
|
42
42
|
<% end %>
|
43
43
|
</dl>
|
44
44
|
<% end %>
|
@@ -47,7 +47,7 @@
|
|
47
47
|
<dl>
|
48
48
|
<dt>Children</dt>
|
49
49
|
<% children.each do |child| %>
|
50
|
-
<dd><%= child
|
50
|
+
<dd><%= child %></dd>
|
51
51
|
<% end %>
|
52
52
|
</dl>
|
53
53
|
<% end %>
|
@@ -0,0 +1,93 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/css/bootstrap.min.css" rel="stylesheet">
|
4
|
+
<style type="text/css">
|
5
|
+
body {
|
6
|
+
margin: 50px;
|
7
|
+
}
|
8
|
+
|
9
|
+
.unapproved h2, .unapproved h2 a {
|
10
|
+
color: red;
|
11
|
+
}
|
12
|
+
</style>
|
13
|
+
</head>
|
14
|
+
<body>
|
15
|
+
<div class="container">
|
16
|
+
<div class="summary hero-unit">
|
17
|
+
<h1>Dependencies</h1>
|
18
|
+
|
19
|
+
<h4>
|
20
|
+
<%= dependencies.size %> total
|
21
|
+
|
22
|
+
<% if unapproved_dependencies.any? %>
|
23
|
+
<span class="badge badge-important"><%= unapproved_dependencies.size %> unapproved</span>
|
24
|
+
<% end %>
|
25
|
+
</h4>
|
26
|
+
|
27
|
+
<ul>
|
28
|
+
<% grouped_dependencies.each do |license, group| %>
|
29
|
+
<li><%= group.size %> <%= license %></li>
|
30
|
+
<% end %>
|
31
|
+
</ul>
|
32
|
+
</div>
|
33
|
+
<div class="dependencies">
|
34
|
+
<% sorted_dependencies.each do |dependency| %>
|
35
|
+
<div id="<%= dependency.name %>" class="<%= dependency.approved ? "approved" : "unapproved" %>">
|
36
|
+
<h2>
|
37
|
+
<% if dependency.homepage && !dependency.homepage.empty? %>
|
38
|
+
<a href="<%= dependency.homepage %>"><%= dependency.name %></a>
|
39
|
+
<% else %>
|
40
|
+
<%= dependency.name %>
|
41
|
+
<% end %>
|
42
|
+
v<%= dependency.version %>
|
43
|
+
<% if dependency.bundler_groups.any? %>
|
44
|
+
(<%= dependency.bundler_groups.join(", ") %>)
|
45
|
+
<% end %>
|
46
|
+
</h2>
|
47
|
+
<table class="table table-striped table-bordered">
|
48
|
+
<thead>
|
49
|
+
<tr>
|
50
|
+
<th>Summary</th>
|
51
|
+
<th>Description</th>
|
52
|
+
<th>License</th>
|
53
|
+
</tr>
|
54
|
+
</thead>
|
55
|
+
<tbody>
|
56
|
+
<tr>
|
57
|
+
<td><%= dependency.summary %></td>
|
58
|
+
<td><%= dependency.description %></td>
|
59
|
+
<td>
|
60
|
+
<% if dependency.license_url && !dependency.license_url.empty? %>
|
61
|
+
<a href="<%= dependency.license_url %>"><%= dependency.license %></a>
|
62
|
+
<% else %>
|
63
|
+
<%= dependency.license %>
|
64
|
+
<% end %>
|
65
|
+
</td>
|
66
|
+
</td>
|
67
|
+
</tr>
|
68
|
+
</tbody>
|
69
|
+
</table>
|
70
|
+
|
71
|
+
<% if dependency.parents.any? %>
|
72
|
+
<dl>
|
73
|
+
<dt>Parents</dt>
|
74
|
+
<% dependency.parents.each do |parent| %>
|
75
|
+
<dd><%= parent %></dd>
|
76
|
+
<% end %>
|
77
|
+
</dl>
|
78
|
+
<% end %>
|
79
|
+
|
80
|
+
<% if dependency.children.any? %>
|
81
|
+
<dl>
|
82
|
+
<dt>Children</dt>
|
83
|
+
<% dependency.children.each do |child| %>
|
84
|
+
<dd><%= child %></dd>
|
85
|
+
<% end %>
|
86
|
+
</dl>
|
87
|
+
<% end %>
|
88
|
+
</div>
|
89
|
+
<% end %>
|
90
|
+
</div>
|
91
|
+
</div>
|
92
|
+
</body>
|
93
|
+
</html>
|