licensee 6.1.1 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 635a65cf8bd046b4f88528088de2dc0863648ed3
|
4
|
+
data.tar.gz: d3ddf6c216c07d29e868ce5772d70935a45cf75e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4ea781352b1a409c3cf0652637a8f270b226770d8a27f93e8a590eaa3b9a320ed9a347e1c488bcd7f336b7c736e4e1262ba65420780ff569c2990fe1c8b0b88
|
7
|
+
data.tar.gz: 01c989238c40de7102e5558f3f4086c93cf65003ec451a8aa9d5ac6123cda560861d4b1486ac64923fbb5fbfed922b395d921a2215d859df6b1f4284649dd4ae
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ Rake::TestTask.new(:test) do |test|
|
|
6
6
|
test.pattern = 'test/**/test_licensee*.rb'
|
7
7
|
end
|
8
8
|
|
9
|
-
desc
|
9
|
+
desc 'Open console with Licensee loaded'
|
10
10
|
task :console do
|
11
|
-
exec
|
11
|
+
exec 'pry -r ./lib/licensee.rb'
|
12
12
|
end
|
data/bin/licensee
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require_relative
|
2
|
+
require_relative '../lib/licensee'
|
3
3
|
|
4
4
|
path = ARGV[0] || Dir.pwd
|
5
5
|
|
6
|
-
|
6
|
+
options = { detect_packages: true, detect_readme: true }
|
7
|
+
project = Licensee::GitProject.new(path, options)
|
7
8
|
file = project.matched_file
|
8
9
|
|
9
10
|
if project.license_file
|
10
11
|
puts "License file: #{project.license_file.filename}"
|
11
|
-
|
12
|
+
if project.license_file.attribution
|
13
|
+
puts "Attribution: #{project.license_file.attribution}"
|
14
|
+
end
|
12
15
|
end
|
13
16
|
|
14
17
|
if file
|
@@ -16,5 +19,5 @@ if file
|
|
16
19
|
puts "Confidence: #{file.confidence}%"
|
17
20
|
puts "Method: #{file.matcher.class}"
|
18
21
|
else
|
19
|
-
puts
|
22
|
+
puts 'Unknown'
|
20
23
|
end
|
data/lib/licensee.rb
CHANGED
@@ -1,33 +1,38 @@
|
|
1
|
-
require_relative
|
2
|
-
require_relative
|
3
|
-
require_relative
|
4
|
-
|
1
|
+
require_relative 'licensee/version'
|
2
|
+
require_relative 'licensee/content_helper'
|
3
|
+
require_relative 'licensee/license'
|
4
|
+
|
5
|
+
# Projects
|
6
|
+
require_relative 'licensee/project'
|
7
|
+
require_relative 'licensee/projects/git_project'
|
8
|
+
require_relative 'licensee/projects/fs_project'
|
5
9
|
|
6
10
|
# Project files
|
7
|
-
require_relative
|
8
|
-
require_relative
|
9
|
-
require_relative
|
11
|
+
require_relative 'licensee/project_file'
|
12
|
+
require_relative 'licensee/project_files/license_file'
|
13
|
+
require_relative 'licensee/project_files/package_info'
|
14
|
+
require_relative 'licensee/project_files/readme'
|
10
15
|
|
11
16
|
# Matchers
|
12
|
-
require_relative
|
13
|
-
require_relative
|
14
|
-
require_relative
|
15
|
-
require_relative
|
16
|
-
require_relative
|
17
|
-
require_relative
|
18
|
-
|
19
|
-
|
17
|
+
require_relative 'licensee/matchers/exact_matcher'
|
18
|
+
require_relative 'licensee/matchers/copyright_matcher'
|
19
|
+
require_relative 'licensee/matchers/dice_matcher'
|
20
|
+
require_relative 'licensee/matchers/package_matcher'
|
21
|
+
require_relative 'licensee/matchers/gemspec_matcher'
|
22
|
+
require_relative 'licensee/matchers/npm_bower_matcher'
|
23
|
+
|
24
|
+
module Licensee
|
20
25
|
# Over which percent is a match considered a match by default
|
21
26
|
CONFIDENCE_THRESHOLD = 90
|
22
27
|
|
23
28
|
# Base domain from which to build license URLs
|
24
|
-
DOMAIN =
|
29
|
+
DOMAIN = 'http://choosealicense.com'.freeze
|
25
30
|
|
26
31
|
class << self
|
27
32
|
attr_writer :confidence_threshold
|
28
33
|
|
29
34
|
# Returns an array of Licensee::License instances
|
30
|
-
def licenses(options={})
|
35
|
+
def licenses(options = {})
|
31
36
|
Licensee::License.all(options)
|
32
37
|
end
|
33
38
|
|
@@ -37,11 +42,9 @@ class Licensee
|
|
37
42
|
end
|
38
43
|
|
39
44
|
def project(path)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
Licensee::FSProject.new(path)
|
44
|
-
end
|
45
|
+
Licensee::GitProject.new(path)
|
46
|
+
rescue Licensee::GitProject::InvalidRepository
|
47
|
+
Licensee::FSProject.new(path)
|
45
48
|
end
|
46
49
|
|
47
50
|
def confidence_threshold
|
@@ -1,13 +1,14 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'digest'
|
3
3
|
|
4
|
-
|
4
|
+
module Licensee
|
5
5
|
module ContentHelper
|
6
|
-
|
7
6
|
DIGEST = Digest::SHA1
|
8
7
|
|
9
8
|
def wordset
|
10
|
-
@wordset ||=
|
9
|
+
@wordset ||= if content_normalized
|
10
|
+
content_normalized.scan(/[\w']+/).to_set
|
11
|
+
end
|
11
12
|
end
|
12
13
|
|
13
14
|
def hash
|
@@ -19,7 +20,7 @@ class Licensee
|
|
19
20
|
@content_normalized ||= begin
|
20
21
|
content_normalized = content.downcase.strip
|
21
22
|
content_normalized.gsub!(/^#{Matchers::Copyright::REGEX}$/i, '')
|
22
|
-
content_normalized.
|
23
|
+
content_normalized.tr("\n", ' ').squeeze(' ')
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
data/lib/licensee/license.rb
CHANGED
@@ -1,39 +1,41 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'yaml'
|
3
3
|
|
4
|
-
|
4
|
+
module Licensee
|
5
5
|
class InvalidLicense < ArgumentError; end
|
6
6
|
class License
|
7
|
-
|
8
7
|
class << self
|
9
|
-
|
10
8
|
# All license objects defined via Licensee (via choosealicense.com)
|
11
9
|
#
|
12
|
-
# Options
|
13
|
-
#
|
10
|
+
# Options:
|
11
|
+
# - :hidden - boolean, return hidden licenses (default: false)
|
12
|
+
# - :featured - boolean, return only (non)featured licenses (default: all)
|
14
13
|
#
|
15
14
|
# Returns an Array of License objects.
|
16
|
-
def all(options={})
|
15
|
+
def all(options = {})
|
16
|
+
options = { hidden: false, featured: nil }.merge(options)
|
17
17
|
output = licenses.dup
|
18
|
-
output.reject!
|
19
|
-
output
|
20
|
-
output
|
18
|
+
output.reject!(&:hidden?) unless options[:hidden]
|
19
|
+
return output if options[:featured].nil?
|
20
|
+
output.select { |l| l.featured? == options[:featured] }
|
21
21
|
end
|
22
22
|
|
23
23
|
def keys
|
24
|
-
@keys ||= license_files.map
|
24
|
+
@keys ||= license_files.map do |license_file|
|
25
|
+
File.basename(license_file, '.txt').downcase
|
26
|
+
end + PSEUDO_LICENSES
|
25
27
|
end
|
26
28
|
|
27
|
-
def find(key, options={})
|
28
|
-
options = {:
|
29
|
-
|
30
|
-
all(options).find { |license| license.key == key }
|
29
|
+
def find(key, options = {})
|
30
|
+
options = { hidden: true }.merge(options)
|
31
|
+
all(options).find { |license| key.casecmp(license.key).zero? }
|
31
32
|
end
|
32
|
-
|
33
|
-
|
33
|
+
alias [] find
|
34
|
+
alias find_by_key find
|
34
35
|
|
35
36
|
def license_dir
|
36
|
-
|
37
|
+
dir = File.dirname(__FILE__)
|
38
|
+
File.expand_path '../../vendor/choosealicense.com/_licenses', dir
|
37
39
|
end
|
38
40
|
|
39
41
|
def license_files
|
@@ -43,19 +45,26 @@ class Licensee
|
|
43
45
|
private
|
44
46
|
|
45
47
|
def licenses
|
46
|
-
@licenses ||= keys.map { |key|
|
48
|
+
@licenses ||= keys.map { |key| new(key) }
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
50
52
|
attr_reader :key
|
51
53
|
|
54
|
+
# These should be in sync with choosealicense.com's collection defaults
|
52
55
|
YAML_DEFAULTS = {
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
}
|
57
|
-
|
58
|
-
|
56
|
+
'featured' => false,
|
57
|
+
'hidden' => true,
|
58
|
+
'variant' => false
|
59
|
+
}.freeze
|
60
|
+
|
61
|
+
# Pseudo-license are license placeholders with no content
|
62
|
+
#
|
63
|
+
# `other` - The project had a license, but we were not able to detect it
|
64
|
+
# `no-license` - The project is not licensed (e.g., all rights reserved)
|
65
|
+
#
|
66
|
+
# Note: A lack of detected license will be a nil license
|
67
|
+
PSEUDO_LICENSES = %w(other no-license).freeze
|
59
68
|
|
60
69
|
include Licensee::ContentHelper
|
61
70
|
|
@@ -71,10 +80,10 @@ class Licensee
|
|
71
80
|
# License metadata from YAML front matter
|
72
81
|
def meta
|
73
82
|
@meta ||= if parts && parts[1]
|
74
|
-
if YAML.respond_to? :safe_load
|
75
|
-
|
83
|
+
meta = if YAML.respond_to? :safe_load
|
84
|
+
YAML.safe_load(parts[1])
|
76
85
|
else
|
77
|
-
|
86
|
+
YAML.load(parts[1])
|
78
87
|
end
|
79
88
|
YAML_DEFAULTS.merge(meta)
|
80
89
|
end
|
@@ -82,11 +91,11 @@ class Licensee
|
|
82
91
|
|
83
92
|
# Returns the human-readable license name
|
84
93
|
def name
|
85
|
-
meta.nil? ? key.capitalize : meta[
|
94
|
+
meta.nil? ? key.capitalize : meta['title']
|
86
95
|
end
|
87
96
|
|
88
97
|
def nickname
|
89
|
-
meta[
|
98
|
+
meta['nickname'] if meta
|
90
99
|
end
|
91
100
|
|
92
101
|
def name_without_version
|
@@ -94,50 +103,52 @@ class Licensee
|
|
94
103
|
end
|
95
104
|
|
96
105
|
def featured?
|
97
|
-
|
106
|
+
return YAML_DEFAULTS['featured'] unless meta
|
107
|
+
meta['featured']
|
98
108
|
end
|
99
|
-
|
109
|
+
alias featured featured?
|
100
110
|
|
101
111
|
def hidden?
|
102
|
-
return true if
|
103
|
-
|
112
|
+
return true if PSEUDO_LICENSES.include?(key)
|
113
|
+
return YAML_DEFAULTS['hidden'] unless meta
|
114
|
+
meta['hidden']
|
104
115
|
end
|
105
116
|
|
106
117
|
# The license body (e.g., contents - frontmatter)
|
107
118
|
def content
|
108
119
|
@content ||= parts[2] if parts && parts[2]
|
109
120
|
end
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
def inspect
|
115
|
-
"#<Licensee::License key=\"#{key}\" name=\"#{name}\">"
|
116
|
-
end
|
121
|
+
alias to_s content
|
122
|
+
alias text content
|
123
|
+
alias body content
|
117
124
|
|
118
125
|
def url
|
119
126
|
URI.join(Licensee::DOMAIN, "/licenses/#{key}/").to_s
|
120
127
|
end
|
121
128
|
|
122
129
|
def ==(other)
|
123
|
-
other
|
130
|
+
!other.nil? && key == other.key
|
124
131
|
end
|
125
132
|
|
126
133
|
private
|
127
134
|
|
135
|
+
def pseudo_license?
|
136
|
+
PSEUDO_LICENSES.include?(key)
|
137
|
+
end
|
138
|
+
|
128
139
|
# Raw content of license file, including YAML front matter
|
129
140
|
def raw_content
|
130
|
-
|
141
|
+
return if pseudo_license?
|
142
|
+
@raw_content ||= if File.exist?(path)
|
131
143
|
File.open(path).read
|
132
|
-
elsif key == "other" # A pseudo-license with no content
|
133
|
-
nil
|
134
144
|
else
|
135
145
|
raise Licensee::InvalidLicense, "'#{key}' is not a valid license key"
|
136
146
|
end
|
137
147
|
end
|
138
148
|
|
139
149
|
def parts
|
140
|
-
|
150
|
+
return unless raw_content
|
151
|
+
@parts ||= raw_content.match(/\A(---\n.*\n---\n+)?(.*)/m).to_a
|
141
152
|
end
|
142
153
|
end
|
143
154
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# encoding=utf-8
|
2
|
-
|
2
|
+
module Licensee
|
3
3
|
module Matchers
|
4
4
|
class Copyright
|
5
5
|
REGEX = /\s*Copyright (©|\(c\)|\xC2\xA9)? ?(\d{4}|\[year\])(.*)?\s*/i
|
@@ -11,7 +11,7 @@ class Licensee
|
|
11
11
|
def match
|
12
12
|
# Note: must use content, and not content_normalized here
|
13
13
|
if @file.content.strip =~ /\A#{REGEX}\z/i
|
14
|
-
Licensee::License.find(
|
14
|
+
Licensee::License.find('no-license')
|
15
15
|
end
|
16
16
|
rescue
|
17
17
|
nil
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
module Licensee
|
2
2
|
module Matchers
|
3
3
|
class Dice
|
4
4
|
def initialize(file)
|
@@ -18,7 +18,7 @@ class Licensee
|
|
18
18
|
@match = if matches.empty?
|
19
19
|
nil
|
20
20
|
else
|
21
|
-
matches.max_by { |
|
21
|
+
matches.max_by { |_l, sim| sim }.first
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -28,7 +28,7 @@ class Licensee
|
|
28
28
|
# the confidence threshold / 100
|
29
29
|
def potential_licenses
|
30
30
|
@potential_licenses ||= begin
|
31
|
-
licenses = Licensee.licenses(:
|
31
|
+
licenses = Licensee.licenses(hidden: true)
|
32
32
|
licenses = licenses.select do |license|
|
33
33
|
license.wordset && length_delta(license) <= max_delta
|
34
34
|
end
|
@@ -45,7 +45,9 @@ class Licensee
|
|
45
45
|
# Maximum possible difference between file length and license length
|
46
46
|
# for a license to be a potential license to be matched
|
47
47
|
def max_delta
|
48
|
-
@max_delta ||= (
|
48
|
+
@max_delta ||= (
|
49
|
+
@file.wordset.size * (Licensee.confidence_threshold / 100.0)
|
50
|
+
)
|
49
51
|
end
|
50
52
|
|
51
53
|
# Confidence that the matched license is a match
|
@@ -54,6 +56,7 @@ class Licensee
|
|
54
56
|
end
|
55
57
|
|
56
58
|
private
|
59
|
+
|
57
60
|
# Calculate percent changed between file and potential license
|
58
61
|
def similarity(license)
|
59
62
|
overlap = (@file.wordset & license.wordset).size
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
module Licensee
|
2
2
|
module Matchers
|
3
3
|
class Exact
|
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.wordset == @file.wordset }
|
10
10
|
end
|
11
11
|
|
12
12
|
def confidence
|
@@ -1,12 +1,15 @@
|
|
1
|
-
|
1
|
+
module Licensee
|
2
2
|
module Matchers
|
3
3
|
class Gemspec < Package
|
4
4
|
# We definitely don't want to be evaling arbitrary Gemspec files
|
5
5
|
# While not 100% accurate, use some lenient regex to try to grep the
|
6
6
|
# license declaration from the Gemspec as a string, if any
|
7
|
-
LICENSE_REGEX =
|
7
|
+
LICENSE_REGEX = /
|
8
|
+
^\s*[a-z0-9_]+\.license\s*\=\s*[\'\"]([a-z\-0-9\.]+)[\'\"]\s*$
|
9
|
+
/ix
|
8
10
|
|
9
11
|
private
|
12
|
+
|
10
13
|
def license_property
|
11
14
|
match = @file.content.match LICENSE_REGEX
|
12
15
|
match[1].downcase if match && match[1]
|
@@ -1,11 +1,14 @@
|
|
1
|
-
|
1
|
+
module Licensee
|
2
2
|
module Matchers
|
3
3
|
class NpmBower < Package
|
4
4
|
# While we could parse the package.json or bower.json file, prefer
|
5
5
|
# a lenient regex for speed and security. Moar parsing moar problems.
|
6
|
-
LICENSE_REGEX =
|
6
|
+
LICENSE_REGEX = /
|
7
|
+
s*[\"\']license[\"\']\s*\:\s*[\'\"]([a-z\-0-9\.]+)[\'\"],?\s*
|
8
|
+
/ix
|
7
9
|
|
8
10
|
private
|
11
|
+
|
9
12
|
def license_property
|
10
13
|
match = @file.content.match LICENSE_REGEX
|
11
14
|
match[1].downcase if match && match[1]
|