licensee 6.1.1 → 7.0.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.
- checksums.yaml +4 -4
- data/Rakefile +2 -2
- data/bin/licensee +7 -4
- data/lib/licensee.rb +25 -22
- data/lib/licensee/content_helper.rb +5 -4
- data/lib/licensee/license.rb +56 -45
- data/lib/licensee/matchers/copyright_matcher.rb +2 -2
- data/lib/licensee/matchers/dice_matcher.rb +7 -4
- data/lib/licensee/matchers/exact_matcher.rb +2 -2
- data/lib/licensee/matchers/gemspec_matcher.rb +5 -2
- data/lib/licensee/matchers/npm_bower_matcher.rb +5 -2
- data/lib/licensee/matchers/package_matcher.rb +2 -2
- data/lib/licensee/project.rb +21 -96
- data/lib/licensee/project_file.rb +6 -7
- data/lib/licensee/project_files/license_file.rb +3 -3
- data/lib/licensee/project_files/package_info.rb +7 -7
- data/lib/licensee/project_files/readme.rb +24 -0
- data/lib/licensee/projects/fs_project.rb +32 -0
- data/lib/licensee/projects/git_project.rb +55 -0
- data/lib/licensee/version.rb +2 -2
- data/test/fixtures/bower-with-readme/README.md +1 -0
- data/test/fixtures/bower-with-readme/bower.json +3 -0
- data/test/functions.rb +23 -12
- data/test/helper.rb +5 -0
- data/test/test_licensee.rb +9 -8
- data/test/test_licensee_bin.rb +11 -5
- data/test/test_licensee_copyright_matcher.rb +23 -23
- data/test/test_licensee_dice_matcher.rb +5 -5
- data/test/test_licensee_exact_matcher.rb +4 -4
- data/test/test_licensee_gemspec_matcher.rb +4 -4
- data/test/test_licensee_license.rb +82 -70
- data/test/test_licensee_license_file.rb +30 -28
- data/test/test_licensee_npm_bower_matcher.rb +11 -11
- data/test/test_licensee_package_info.rb +8 -7
- data/test/test_licensee_project.rb +45 -37
- data/test/test_licensee_project_file.rb +9 -9
- data/test/test_licensee_readme.rb +47 -0
- data/test/test_licensee_vendor.rb +10 -7
- data/vendor/choosealicense.com/_licenses/afl-3.0.txt +0 -3
- data/vendor/choosealicense.com/_licenses/agpl-3.0.txt +5 -5
- data/vendor/choosealicense.com/_licenses/apache-2.0.txt +1 -2
- data/vendor/choosealicense.com/_licenses/artistic-2.0.txt +14 -13
- data/vendor/choosealicense.com/_licenses/bsd-2-clause.txt +2 -3
- data/vendor/choosealicense.com/_licenses/bsd-3-clause-clear.txt +0 -6
- data/vendor/choosealicense.com/_licenses/bsd-3-clause.txt +2 -4
- data/vendor/choosealicense.com/_licenses/cc0-1.0.txt +2 -1
- data/vendor/choosealicense.com/_licenses/epl-1.0.txt +2 -1
- data/vendor/choosealicense.com/_licenses/eupl-1.1.txt +345 -0
- data/vendor/choosealicense.com/_licenses/gpl-2.0.txt +5 -5
- data/vendor/choosealicense.com/_licenses/gpl-3.0.txt +5 -4
- data/vendor/choosealicense.com/_licenses/isc.txt +1 -2
- data/vendor/choosealicense.com/_licenses/lgpl-2.1.txt +5 -6
- data/vendor/choosealicense.com/_licenses/lgpl-3.0.txt +8 -8
- data/vendor/choosealicense.com/_licenses/lppl-1.3c.txt +445 -0
- data/vendor/choosealicense.com/_licenses/mit.txt +1 -1
- data/vendor/choosealicense.com/_licenses/mpl-2.0.txt +2 -1
- data/vendor/choosealicense.com/_licenses/ms-pl.txt +0 -1
- data/vendor/choosealicense.com/_licenses/ms-rl.txt +1 -1
- data/vendor/choosealicense.com/_licenses/ofl-1.1.txt +1 -2
- data/vendor/choosealicense.com/_licenses/osl-3.0.txt +1 -3
- data/vendor/choosealicense.com/_licenses/unlicense.txt +1 -2
- data/vendor/choosealicense.com/_licenses/wtfpl.txt +0 -2
- metadata +33 -11
- data/vendor/choosealicense.com/_licenses/no-license.txt +0 -25
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
module Licensee
|
2
2
|
module Matchers
|
3
3
|
class Package
|
4
4
|
def initialize(file)
|
@@ -6,7 +6,7 @@ class Licensee
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def match
|
9
|
-
Licensee.licenses(:
|
9
|
+
Licensee.licenses(hidden: true).find { |l| l.key == license_property }
|
10
10
|
end
|
11
11
|
|
12
12
|
def confidence
|
data/lib/licensee/project.rb
CHANGED
@@ -1,32 +1,40 @@
|
|
1
1
|
require 'rugged'
|
2
2
|
|
3
|
-
|
4
|
-
private
|
3
|
+
module Licensee
|
5
4
|
class Project
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
attr_reader :detect_readme, :detect_packages
|
6
|
+
alias detect_readme? detect_readme
|
7
|
+
alias detect_packages? detect_packages
|
9
8
|
|
10
|
-
def detect_packages
|
11
|
-
@detect_packages
|
9
|
+
def initialize(detect_packages: false, detect_readme: false)
|
10
|
+
@detect_packages = detect_packages
|
11
|
+
@detect_readme = detect_readme
|
12
12
|
end
|
13
13
|
|
14
|
-
# Returns the matching
|
14
|
+
# Returns the matching License instance if a license can be detected
|
15
15
|
def license
|
16
16
|
@license ||= matched_file && matched_file.license
|
17
17
|
end
|
18
18
|
|
19
19
|
def matched_file
|
20
|
-
@matched_file ||= (license_file || package_file)
|
20
|
+
@matched_file ||= (license_file || readme || package_file)
|
21
21
|
end
|
22
22
|
|
23
23
|
def license_file
|
24
24
|
return @license_file if defined? @license_file
|
25
25
|
@license_file = begin
|
26
26
|
content, name = find_file { |name| LicenseFile.name_score(name) }
|
27
|
-
if content && name
|
28
|
-
|
29
|
-
|
27
|
+
LicenseFile.new(content, name) if content && name
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def readme
|
32
|
+
return unless detect_readme?
|
33
|
+
return @readme if defined? @readme
|
34
|
+
@readme = begin
|
35
|
+
content, name = find_file { |name| Readme.name_score(name) }
|
36
|
+
content = Readme.license_content(content)
|
37
|
+
Readme.new(content, name) if content && name
|
30
38
|
end
|
31
39
|
end
|
32
40
|
|
@@ -35,91 +43,8 @@ class Licensee
|
|
35
43
|
return @package_file if defined? @package_file
|
36
44
|
@package_file = begin
|
37
45
|
content, name = find_file { |name| PackageInfo.name_score(name) }
|
38
|
-
if content && name
|
39
|
-
PackageInfo.new(content, name)
|
40
|
-
end
|
46
|
+
PackageInfo.new(content, name) if content && name
|
41
47
|
end
|
42
48
|
end
|
43
49
|
end
|
44
|
-
|
45
|
-
public
|
46
|
-
|
47
|
-
# Git-based project
|
48
|
-
#
|
49
|
-
# analyze a given git repository for license information
|
50
|
-
class GitProject < Project
|
51
|
-
attr_reader :repository, :revision
|
52
|
-
|
53
|
-
class InvalidRepository < ArgumentError; end
|
54
|
-
|
55
|
-
def initialize(repo, revision: nil, detect_packages: false)
|
56
|
-
if repo.kind_of? Rugged::Repository
|
57
|
-
@repository = repo
|
58
|
-
else
|
59
|
-
@repository = Rugged::Repository.new(repo)
|
60
|
-
end
|
61
|
-
|
62
|
-
@revision = revision
|
63
|
-
super(detect_packages)
|
64
|
-
rescue Rugged::RepositoryError
|
65
|
-
raise InvalidRepository
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
def commit
|
70
|
-
@commit ||= revision ? repository.lookup(revision) : repository.last_commit
|
71
|
-
end
|
72
|
-
|
73
|
-
MAX_LICENSE_SIZE = 64 * 1024
|
74
|
-
|
75
|
-
def load_blob_data(oid)
|
76
|
-
data, _ = Rugged::Blob.to_buffer(repository, oid, MAX_LICENSE_SIZE)
|
77
|
-
data
|
78
|
-
end
|
79
|
-
|
80
|
-
def find_file
|
81
|
-
files = commit.tree.map do |entry|
|
82
|
-
next unless entry[:type] == :blob
|
83
|
-
if (score = yield entry[:name]) > 0
|
84
|
-
{ :name => entry[:name], :oid => entry[:oid], :score => score }
|
85
|
-
end
|
86
|
-
end.compact
|
87
|
-
|
88
|
-
return if files.empty?
|
89
|
-
files.sort! { |a, b| b[:score] <=> a[:score] }
|
90
|
-
|
91
|
-
f = files.first
|
92
|
-
[load_blob_data(f[:oid]), f[:name]]
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Filesystem-based project
|
97
|
-
#
|
98
|
-
# Analyze a folder on the filesystem for license information
|
99
|
-
class FSProject < Project
|
100
|
-
attr_reader :path
|
101
|
-
|
102
|
-
def initialize(path, detect_packages: false)
|
103
|
-
@path = path
|
104
|
-
super(detect_packages)
|
105
|
-
end
|
106
|
-
|
107
|
-
private
|
108
|
-
def find_file
|
109
|
-
files = []
|
110
|
-
|
111
|
-
Dir.foreach(path) do |file|
|
112
|
-
next unless ::File.file?(::File.join(path, file))
|
113
|
-
if (score = yield file) > 0
|
114
|
-
files.push({ :name => file, :score => score })
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
return if files.empty?
|
119
|
-
files.sort! { |a, b| b[:score] <=> a[:score] }
|
120
|
-
|
121
|
-
f = files.first
|
122
|
-
[::File.read(::File.join(path, f[:name])), f[:name]]
|
123
|
-
end
|
124
|
-
end
|
125
50
|
end
|
@@ -1,18 +1,17 @@
|
|
1
|
-
|
1
|
+
module Licensee
|
2
2
|
class Project
|
3
|
-
private
|
4
|
-
|
5
3
|
class File
|
6
4
|
attr_reader :content, :filename
|
7
5
|
|
8
6
|
def initialize(content, filename = nil)
|
9
7
|
@content = content
|
10
|
-
|
8
|
+
options = { invalid: :replace, undef: :replace, replace: '' }
|
9
|
+
@content.encode!(Encoding::UTF_8, options)
|
11
10
|
@filename = filename
|
12
11
|
end
|
13
12
|
|
14
13
|
def matcher
|
15
|
-
@matcher ||= possible_matchers.map { |m| m.new(self) }.find
|
14
|
+
@matcher ||= possible_matchers.map { |m| m.new(self) }.find(&:match)
|
16
15
|
end
|
17
16
|
|
18
17
|
# Returns the percent confident with the match
|
@@ -24,8 +23,8 @@ class Licensee
|
|
24
23
|
matcher && matcher.match
|
25
24
|
end
|
26
25
|
|
27
|
-
|
28
|
-
|
26
|
+
alias match license
|
27
|
+
alias path filename
|
29
28
|
end
|
30
29
|
end
|
31
30
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
module Licensee
|
2
2
|
class Project
|
3
3
|
class LicenseFile < Licensee::Project::File
|
4
4
|
include Licensee::ContentHelper
|
@@ -6,7 +6,7 @@ class Licensee
|
|
6
6
|
def possible_matchers
|
7
7
|
[Matchers::Copyright, Matchers::Exact, Matchers::Dice]
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def attribution
|
11
11
|
matches = /^#{Matchers::Copyright::REGEX}$/i.match(content)
|
12
12
|
matches[0].strip if matches
|
@@ -18,7 +18,7 @@ class Licensee
|
|
18
18
|
return 0.8 if filename =~ /\Acopy(ing|right)(\.[^.]+)?\z/i
|
19
19
|
return 0.7 if filename =~ /\A(un)?licen[sc]e\.[^.]+\z/i
|
20
20
|
return 0.5 if filename =~ /licen[sc]e/i
|
21
|
-
|
21
|
+
0.0
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -1,11 +1,11 @@
|
|
1
|
-
|
1
|
+
module Licensee
|
2
2
|
class Project
|
3
3
|
class PackageInfo < Licensee::Project::File
|
4
4
|
def possible_matchers
|
5
5
|
case ::File.extname(filename)
|
6
|
-
when
|
6
|
+
when '.gemspec'
|
7
7
|
[Matchers::Gemspec]
|
8
|
-
when
|
8
|
+
when '.json'
|
9
9
|
[Matchers::NpmBower]
|
10
10
|
else
|
11
11
|
[]
|
@@ -13,10 +13,10 @@ class Licensee
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.name_score(filename)
|
16
|
-
return 1.0 if ::File.extname(filename) ==
|
17
|
-
return 1.0 if filename ==
|
18
|
-
return 0.75 if filename ==
|
19
|
-
|
16
|
+
return 1.0 if ::File.extname(filename) == '.gemspec'
|
17
|
+
return 1.0 if filename == 'package.json'
|
18
|
+
return 0.75 if filename == 'bower.json'
|
19
|
+
0.0
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Licensee
|
2
|
+
class Project
|
3
|
+
class Readme < LicenseFile
|
4
|
+
SCORES = {
|
5
|
+
/\AREADME\z/i => 1.0,
|
6
|
+
/\AREADME\.(md|markdown|txt)\z/i => 0.9
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
CONTENT_REGEX = /^#+ Licen[sc]e$(.*?)(?=#+|\z)/im
|
10
|
+
|
11
|
+
def self.name_score(filename)
|
12
|
+
SCORES.each do |pattern, score|
|
13
|
+
return score if pattern =~ filename
|
14
|
+
end
|
15
|
+
0.0
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.license_content(content)
|
19
|
+
match = CONTENT_REGEX.match(content)
|
20
|
+
match[1].strip if match
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Filesystem-based project
|
2
|
+
#
|
3
|
+
# Analyze a folder on the filesystem for license information
|
4
|
+
module Licensee
|
5
|
+
class FSProject < Project
|
6
|
+
attr_reader :path
|
7
|
+
|
8
|
+
def initialize(path, **args)
|
9
|
+
@path = path
|
10
|
+
super(**args)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def find_file
|
16
|
+
files = []
|
17
|
+
|
18
|
+
Dir.foreach(path) do |file|
|
19
|
+
next unless ::File.file?(::File.join(path, file))
|
20
|
+
if (score = yield file) > 0
|
21
|
+
files.push(name: file, score: score)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
return if files.empty?
|
26
|
+
files.sort! { |a, b| b[:score] <=> a[:score] }
|
27
|
+
|
28
|
+
f = files.first
|
29
|
+
[::File.read(::File.join(path, f[:name])), f[:name]]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# Git-based project
|
2
|
+
#
|
3
|
+
# analyze a given git repository for license information
|
4
|
+
module Licensee
|
5
|
+
class GitProject < Licensee::Project
|
6
|
+
attr_reader :repository, :revision
|
7
|
+
|
8
|
+
class InvalidRepository < ArgumentError; end
|
9
|
+
|
10
|
+
def initialize(repo, revision: nil, **args)
|
11
|
+
@repository = if repo.is_a? Rugged::Repository
|
12
|
+
repo
|
13
|
+
else
|
14
|
+
Rugged::Repository.new(repo)
|
15
|
+
end
|
16
|
+
|
17
|
+
@revision = revision
|
18
|
+
super(**args)
|
19
|
+
rescue Rugged::RepositoryError
|
20
|
+
raise InvalidRepository
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def commit
|
26
|
+
@commit ||= if revision
|
27
|
+
repository.lookup(revision)
|
28
|
+
else
|
29
|
+
repository.last_commit
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
MAX_LICENSE_SIZE = 64 * 1024
|
34
|
+
|
35
|
+
def load_blob_data(oid)
|
36
|
+
data, = Rugged::Blob.to_buffer(repository, oid, MAX_LICENSE_SIZE)
|
37
|
+
data
|
38
|
+
end
|
39
|
+
|
40
|
+
def find_file
|
41
|
+
files = commit.tree.map do |entry|
|
42
|
+
next unless entry[:type] == :blob
|
43
|
+
if (score = yield entry[:name]) > 0
|
44
|
+
{ name: entry[:name], oid: entry[:oid], score: score }
|
45
|
+
end
|
46
|
+
end.compact
|
47
|
+
|
48
|
+
return if files.empty?
|
49
|
+
files.sort! { |a, b| b[:score] <=> a[:score] }
|
50
|
+
|
51
|
+
f = files.first
|
52
|
+
[load_blob_data(f[:oid]), f[:name]]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/licensee/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION =
|
1
|
+
module Licensee
|
2
|
+
VERSION = '7.0.0'.freeze
|
3
3
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
This readme doesn't have a license, so detected the license from bower.
|
data/test/functions.rb
CHANGED
@@ -4,7 +4,7 @@ require 'securerandom'
|
|
4
4
|
require_relative '../lib/licensee'
|
5
5
|
|
6
6
|
def fixtures_base
|
7
|
-
File.expand_path
|
7
|
+
File.expand_path 'fixtures', File.dirname(__FILE__)
|
8
8
|
end
|
9
9
|
|
10
10
|
def fixture_path(fixture)
|
@@ -13,9 +13,9 @@ end
|
|
13
13
|
|
14
14
|
def license_from_path(path)
|
15
15
|
license = File.open(path).read.match(/\A(---\n.*\n---\n+)?(.*)/m).to_a[2]
|
16
|
-
license.sub!
|
17
|
-
license.sub!
|
18
|
-
license.sub!
|
16
|
+
license.sub! '[fullname]', 'Ben Balter'
|
17
|
+
license.sub! '[year]', '2014'
|
18
|
+
license.sub! '[email]', 'ben@github.invalid'
|
19
19
|
license
|
20
20
|
end
|
21
21
|
|
@@ -26,8 +26,8 @@ def chaos_monkey(string)
|
|
26
26
|
string
|
27
27
|
end
|
28
28
|
|
29
|
-
def verify_license_file(license, chaos = false, wrap=false)
|
30
|
-
expected = File.basename(license,
|
29
|
+
def verify_license_file(license, chaos = false, wrap = false)
|
30
|
+
expected = File.basename(license, '.txt')
|
31
31
|
|
32
32
|
text = license_from_path(license)
|
33
33
|
text = chaos_monkey(text) if chaos
|
@@ -39,17 +39,28 @@ def verify_license_file(license, chaos = false, wrap=false)
|
|
39
39
|
msg = "No match for #{expected}."
|
40
40
|
|
41
41
|
assert actual, msg
|
42
|
-
|
42
|
+
|
43
|
+
msg = "Expeceted #{expected} but got #{actual.key} for .match. "
|
44
|
+
msg << "Confidence: #{license_file.confidence}. "
|
45
|
+
msg << "Method: #{license_file.matcher.class}"
|
46
|
+
assert_equal expected, actual.key, msg
|
43
47
|
end
|
44
48
|
|
45
|
-
def wrap(text, line_width=80)
|
49
|
+
def wrap(text, line_width = 80)
|
46
50
|
text = text.clone
|
47
51
|
copyright = /^#{Licensee::Matchers::Copyright::REGEX}$/i.match(text)
|
48
|
-
|
49
|
-
|
52
|
+
if copyright
|
53
|
+
text.gsub!(/^#{Licensee::Matchers::Copyright::REGEX}$/i, '[COPYRIGHT]')
|
54
|
+
end
|
55
|
+
text.gsub!(/([^\n])\n([^\n])/, '\1 \2')
|
56
|
+
|
50
57
|
text = text.split("\n").collect do |line|
|
51
|
-
line.length > line_width
|
58
|
+
if line.length > line_width
|
59
|
+
line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip
|
60
|
+
else
|
61
|
+
line
|
62
|
+
end
|
52
63
|
end * "\n"
|
53
|
-
text.gsub!
|
64
|
+
text.gsub! '[COPYRIGHT]', "\n#{copyright}\n" if copyright
|
54
65
|
text.strip
|
55
66
|
end
|