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