licensee 9.14.1 → 9.15.2
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/LICENSE.md +1 -1
- data/bin/licensee +1 -1
- data/lib/licensee/commands/detect.rb +3 -5
- data/lib/licensee/commands/diff.rb +3 -7
- data/lib/licensee/content_helper.rb +30 -28
- data/lib/licensee/hash_helper.rb +1 -1
- data/lib/licensee/license.rb +31 -18
- data/lib/licensee/matchers/copyright.rb +3 -8
- data/lib/licensee/matchers/cran.rb +1 -1
- data/lib/licensee/matchers/dice.rb +6 -8
- data/lib/licensee/project_files/license_file.rb +29 -24
- data/lib/licensee/project_files/project_file.rb +2 -4
- data/lib/licensee/project_files/readme_file.rb +1 -1
- data/lib/licensee/projects/fs_project.rb +1 -3
- data/lib/licensee/projects/git_project.rb +6 -6
- data/lib/licensee/projects/project.rb +14 -19
- data/lib/licensee/version.rb +1 -1
- data/lib/licensee.rb +7 -4
- data/licensee.gemspec +6 -4
- data/spec/fixture_spec.rb +2 -2
- data/spec/fixtures/bsd-3-authorowner/LICENSE +27 -0
- data/spec/fixtures/cc-by-sa-mdlinks/License.md +173 -0
- data/spec/fixtures/cc-by-sa-nocclicensor/License.md +425 -0
- data/spec/fixtures/detect.json +5 -5
- data/spec/fixtures/eupl-cal2017/LICENSE.txt +274 -0
- data/spec/fixtures/fixtures.yml +45 -25
- data/spec/fixtures/license-hashes.json +40 -38
- data/spec/fixtures/pixar-modified-apache/LICENSE.txt +174 -0
- data/spec/integration_spec.rb +46 -6
- data/spec/licensee/commands/detect_spec.rb +2 -2
- data/spec/licensee/content_helper_spec.rb +18 -13
- data/spec/licensee/license_spec.rb +6 -6
- data/spec/licensee/matchers/dice_matcher_spec.rb +3 -3
- data/spec/licensee/project_files/license_file_spec.rb +9 -3
- data/spec/licensee/project_files/package_info_spec.rb +2 -2
- data/spec/licensee/project_spec.rb +4 -5
- data/spec/licensee_spec.rb +8 -2
- data/spec/spec_helper.rb +3 -3
- data/spec/vendored_license_spec.rb +1 -3
- data/vendor/choosealicense.com/_licenses/0bsd.txt +4 -2
- data/vendor/choosealicense.com/_licenses/afl-3.0.txt +12 -12
- data/vendor/choosealicense.com/_licenses/apache-2.0.txt +1 -1
- data/vendor/choosealicense.com/_licenses/bsd-3-clause.txt +2 -2
- data/vendor/choosealicense.com/_licenses/bsl-1.0.txt +1 -1
- data/vendor/choosealicense.com/_licenses/cc-by-4.0.txt +1 -1
- data/vendor/choosealicense.com/_licenses/cc-by-sa-4.0.txt +1 -1
- data/vendor/choosealicense.com/_licenses/eupl-1.2.txt +75 -58
- data/vendor/choosealicense.com/_licenses/isc.txt +8 -8
- data/vendor/choosealicense.com/_licenses/mit-0.txt +45 -0
- data/vendor/choosealicense.com/_licenses/mulanpsl-2.0.txt +226 -0
- data/vendor/choosealicense.com/_licenses/odbl-1.0.txt +2 -2
- data/vendor/choosealicense.com/_licenses/osl-3.0.txt +1 -1
- data/vendor/choosealicense.com/_licenses/unlicense.txt +1 -1
- data/vendor/choosealicense.com/_licenses/upl-1.0.txt +1 -1
- data/vendor/license-list-XML/src/0BSD.xml +25 -0
- data/vendor/license-list-XML/src/AFL-3.0.xml +212 -0
- data/vendor/license-list-XML/src/AGPL-3.0.xml +852 -0
- data/vendor/license-list-XML/src/Apache-2.0.xml +223 -0
- data/vendor/license-list-XML/src/Artistic-2.0.xml +238 -0
- data/vendor/license-list-XML/src/BSD-2-Clause.xml +42 -0
- data/vendor/license-list-XML/src/BSD-3-Clause-Clear.xml +59 -0
- data/vendor/license-list-XML/src/BSD-3-Clause.xml +46 -0
- data/vendor/license-list-XML/src/BSD-4-Clause.xml +59 -0
- data/vendor/license-list-XML/src/BSL-1.0.xml +30 -0
- data/vendor/license-list-XML/src/CC-BY-4.0.xml +446 -0
- data/vendor/license-list-XML/src/CC-BY-SA-4.0.xml +477 -0
- data/vendor/license-list-XML/src/CC0-1.0.xml +153 -0
- data/vendor/license-list-XML/src/CECILL-2.1.xml +669 -0
- data/vendor/license-list-XML/src/ECL-2.0.xml +242 -0
- data/vendor/license-list-XML/src/EPL-1.0.xml +255 -0
- data/vendor/license-list-XML/src/EPL-2.0.xml +639 -0
- data/vendor/license-list-XML/src/EUPL-1.1.xml +337 -0
- data/vendor/license-list-XML/src/EUPL-1.2.xml +502 -0
- data/vendor/license-list-XML/src/GPL-2.0.xml +474 -0
- data/vendor/license-list-XML/src/GPL-3.0.xml +858 -0
- data/vendor/license-list-XML/src/ISC.xml +31 -0
- data/vendor/license-list-XML/src/LGPL-2.1.xml +662 -0
- data/vendor/license-list-XML/src/LGPL-3.0.xml +260 -0
- data/vendor/license-list-XML/src/LPPL-1.3c.xml +380 -0
- data/vendor/license-list-XML/src/MIT-0.xml +40 -0
- data/vendor/license-list-XML/src/MIT.xml +32 -0
- data/vendor/license-list-XML/src/MPL-2.0.xml +438 -0
- data/vendor/license-list-XML/src/MS-PL.xml +89 -0
- data/vendor/license-list-XML/src/MS-RL.xml +97 -0
- data/vendor/license-list-XML/src/MulanPSL-2.0.xml +167 -0
- data/vendor/license-list-XML/src/NCSA.xml +60 -0
- data/vendor/license-list-XML/src/ODbL-1.0.xml +660 -0
- data/vendor/license-list-XML/src/OFL-1.1.xml +94 -0
- data/vendor/license-list-XML/src/OSL-3.0.xml +209 -0
- data/vendor/license-list-XML/src/PostgreSQL.xml +32 -0
- data/vendor/license-list-XML/src/UPL-1.0.xml +46 -0
- data/vendor/license-list-XML/src/Unlicense.xml +27 -0
- data/vendor/license-list-XML/src/Vim.xml +124 -0
- data/vendor/license-list-XML/src/WTFPL.xml +30 -0
- data/vendor/license-list-XML/src/Zlib.xml +38 -0
- metadata +75 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 334874469d14f16839113e4311ba232c18a8bc8d0ee0c618034ec30e16497f47
|
|
4
|
+
data.tar.gz: aaca8fc841545017ee7dc58e02a8ce41845d3253a281153b599f187218c6fc6a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7cd4ba6ef792da1ca97536e14b78d92c2fddf01dd14405fb859ad74db0f30018af62ea67af39a754f4a568f83f14a932d501772d83f1b5d19d22833fd8937e20
|
|
7
|
+
data.tar.gz: 9fa7c61dde8ce35d2003c1119206047c3a35179e17484d0d5528e145f99bab29882c3da004a22214c777f758ade7607289a0d73a696135cc3a9c49467ed24238
|
data/LICENSE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2014-
|
|
3
|
+
Copyright (c) 2014-2021 Ben Balter and Licensee contributors
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/bin/licensee
CHANGED
|
@@ -28,11 +28,9 @@ class LicenseeCLI < Thor
|
|
|
28
28
|
['Licenses:', project.licenses.map(&:spdx_id)]
|
|
29
29
|
else
|
|
30
30
|
['License:', set_color('None', :red)]
|
|
31
|
-
|
|
31
|
+
end
|
|
32
32
|
|
|
33
|
-
unless project.matched_files.empty?
|
|
34
|
-
rows << ['Matched files:', project.matched_files.map(&:filename).join(', ')]
|
|
35
|
-
end
|
|
33
|
+
rows << ['Matched files:', project.matched_files.map(&:filename).join(', ')] unless project.matched_files.empty?
|
|
36
34
|
|
|
37
35
|
print_table rows
|
|
38
36
|
|
|
@@ -97,7 +95,7 @@ class LicenseeCLI < Thor
|
|
|
97
95
|
def licenses_by_similarity(matched_file)
|
|
98
96
|
matcher = Licensee::Matchers::Dice.new(matched_file)
|
|
99
97
|
potential_licenses = Licensee.licenses(hidden: true).select(&:wordset)
|
|
100
|
-
matcher.instance_variable_set(
|
|
98
|
+
matcher.instance_variable_set(:@potential_licenses, potential_licenses)
|
|
101
99
|
matcher.licenses_by_similarity
|
|
102
100
|
end
|
|
103
101
|
|
|
@@ -41,17 +41,13 @@ class LicenseeCLI < Thor
|
|
|
41
41
|
|
|
42
42
|
def license_to_diff
|
|
43
43
|
return options[:license_to_diff] if options[:license_to_diff]
|
|
44
|
-
return project.license_file if remote? || $stdin.tty? && project.license_file
|
|
44
|
+
return project.license_file if remote? || ($stdin.tty? && project.license_file)
|
|
45
45
|
|
|
46
|
-
@license_to_diff ||=
|
|
47
|
-
Licensee::ProjectFiles::LicenseFile.new($stdin.read, 'LICENSE')
|
|
48
|
-
end
|
|
46
|
+
@license_to_diff ||= Licensee::ProjectFiles::LicenseFile.new($stdin.read, 'LICENSE')
|
|
49
47
|
end
|
|
50
48
|
|
|
51
49
|
def expected_license
|
|
52
|
-
if options[:license]
|
|
53
|
-
@expected_license ||= Licensee::License.find options[:license]
|
|
54
|
-
end
|
|
50
|
+
@expected_license ||= Licensee::License.find options[:license] if options[:license]
|
|
55
51
|
return @expected_license if @expected_license
|
|
56
52
|
|
|
57
53
|
if options[:license]
|
|
@@ -7,7 +7,7 @@ module Licensee
|
|
|
7
7
|
module ContentHelper
|
|
8
8
|
DIGEST = Digest::SHA1
|
|
9
9
|
START_REGEX = /\A\s*/.freeze
|
|
10
|
-
END_OF_TERMS_REGEX = /^[\s#*_]*end of terms and conditions[\s#*_]*$/i.freeze
|
|
10
|
+
END_OF_TERMS_REGEX = /^[\s#*_]*end of (the )?terms and conditions[\s#*_]*$/i.freeze
|
|
11
11
|
REGEXES = {
|
|
12
12
|
bom: /#{START_REGEX}\xEF\xBB\xBF/,
|
|
13
13
|
hrs: /^\s*[=\-*]{3,}\s*$/,
|
|
@@ -23,8 +23,8 @@ module Licensee
|
|
|
23
23
|
url: %r{#{START_REGEX}https?://[^ ]+\n},
|
|
24
24
|
bullet: /\n\n\s*(?:[*-]|\(?[\da-z]{1,2}[).])\s+/i,
|
|
25
25
|
developed_by: /#{START_REGEX}developed by:.*?\n\n/im,
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
cc_dedication: /The\s+text\s+of\s+the\s+Creative\s+Commons.*?Public\s+Domain\s+Dedication./im,
|
|
27
|
+
cc_wiki: /wiki.creativecommons.org/i,
|
|
28
28
|
cc_legal_code: /^\s*Creative Commons Legal Code\s*$/i,
|
|
29
29
|
cc0_info: /For more information, please see\s*\S+zero\S+/im,
|
|
30
30
|
cc0_disclaimer: /CREATIVE COMMONS CORPORATION.*?\n\n/im,
|
|
@@ -36,10 +36,7 @@ module Licensee
|
|
|
36
36
|
https: { from: /http:/, to: 'https:' },
|
|
37
37
|
ampersands: { from: '&', to: 'and' },
|
|
38
38
|
dashes: { from: /(?<!^)([—–-]+)(?!$)/, to: '-' },
|
|
39
|
-
|
|
40
|
-
from: /#{REGEXES[:quote_begin]}+([\w -]*?\w)#{REGEXES[:quote_end]}+/,
|
|
41
|
-
to: '"\1"'
|
|
42
|
-
}
|
|
39
|
+
quote: { from: /[`'"‘“’”]/, to: "'" }
|
|
43
40
|
}.freeze
|
|
44
41
|
|
|
45
42
|
# Legally equivalent words that schould be ignored for comparison
|
|
@@ -90,10 +87,9 @@ module Licensee
|
|
|
90
87
|
}.freeze
|
|
91
88
|
STRIP_METHODS = %i[
|
|
92
89
|
bom
|
|
90
|
+
cc_optional
|
|
93
91
|
cc0_optional
|
|
94
92
|
unlicense_optional
|
|
95
|
-
hrs
|
|
96
|
-
markdown_headings
|
|
97
93
|
borders
|
|
98
94
|
title
|
|
99
95
|
version
|
|
@@ -101,7 +97,6 @@ module Licensee
|
|
|
101
97
|
copyright
|
|
102
98
|
title
|
|
103
99
|
block_markup
|
|
104
|
-
link_markup
|
|
105
100
|
developed_by
|
|
106
101
|
end_of_terms
|
|
107
102
|
whitespace
|
|
@@ -110,7 +105,7 @@ module Licensee
|
|
|
110
105
|
|
|
111
106
|
# A set of each word in the license, without duplicates
|
|
112
107
|
def wordset
|
|
113
|
-
@wordset ||= content_normalized&.scan(%r{(?:[\w
|
|
108
|
+
@wordset ||= content_normalized&.scan(%r{(?:[\w/-](?:'s|(?<=s)')?)+})&.to_set
|
|
114
109
|
end
|
|
115
110
|
|
|
116
111
|
# Number of characters in the normalized content
|
|
@@ -133,7 +128,7 @@ module Licensee
|
|
|
133
128
|
overlap = (wordset_fieldless & other.wordset).size
|
|
134
129
|
total = wordset_fieldless.size + other.wordset.size -
|
|
135
130
|
fields_normalized_set.size
|
|
136
|
-
(overlap * 200.0) / (total +
|
|
131
|
+
(overlap * 200.0) / (total + (variation_adjusted_length_delta(other) / 4))
|
|
137
132
|
end
|
|
138
133
|
|
|
139
134
|
# SHA1 of the normalized content
|
|
@@ -148,7 +143,7 @@ module Licensee
|
|
|
148
143
|
def content_without_title_and_version
|
|
149
144
|
@content_without_title_and_version ||= begin
|
|
150
145
|
@_content = nil
|
|
151
|
-
ops = %i[html hrs comments markdown_headings title version]
|
|
146
|
+
ops = %i[html hrs comments markdown_headings link_markup title version]
|
|
152
147
|
ops.each { |op| strip(op) }
|
|
153
148
|
_content
|
|
154
149
|
end
|
|
@@ -186,12 +181,10 @@ module Licensee
|
|
|
186
181
|
text.gsub!(/([^\n])\n([^\n])/, '\1 \2')
|
|
187
182
|
|
|
188
183
|
text = text.split("\n").collect do |line|
|
|
189
|
-
if line =~ REGEXES[:hrs]
|
|
184
|
+
if line =~ REGEXES[:hrs] || line.length <= line_width
|
|
190
185
|
line
|
|
191
|
-
elsif line.length > line_width
|
|
192
|
-
line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip
|
|
193
186
|
else
|
|
194
|
-
line
|
|
187
|
+
line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip
|
|
195
188
|
end
|
|
196
189
|
end * "\n"
|
|
197
190
|
|
|
@@ -233,9 +226,7 @@ module Licensee
|
|
|
233
226
|
meth = "strip_#{regex_or_sym}"
|
|
234
227
|
return send(meth) if respond_to?(meth, true)
|
|
235
228
|
|
|
236
|
-
unless REGEXES[regex_or_sym]
|
|
237
|
-
raise ArgumentError, "#{regex_or_sym} is an invalid regex reference"
|
|
238
|
-
end
|
|
229
|
+
raise ArgumentError, "#{regex_or_sym} is an invalid regex reference" unless REGEXES[regex_or_sym]
|
|
239
230
|
|
|
240
231
|
regex_or_sym = REGEXES[regex_or_sym]
|
|
241
232
|
end
|
|
@@ -244,9 +235,7 @@ module Licensee
|
|
|
244
235
|
end
|
|
245
236
|
|
|
246
237
|
def strip_title
|
|
247
|
-
while _content =~ ContentHelper.title_regex
|
|
248
|
-
strip(ContentHelper.title_regex)
|
|
249
|
-
end
|
|
238
|
+
strip(ContentHelper.title_regex) while _content =~ ContentHelper.title_regex
|
|
250
239
|
end
|
|
251
240
|
|
|
252
241
|
def strip_borders
|
|
@@ -274,6 +263,13 @@ module Licensee
|
|
|
274
263
|
strip(REGEXES[:cc0_disclaimer])
|
|
275
264
|
end
|
|
276
265
|
|
|
266
|
+
def strip_cc_optional
|
|
267
|
+
return unless _content.include? 'creative commons'
|
|
268
|
+
|
|
269
|
+
strip(REGEXES[:cc_dedication])
|
|
270
|
+
strip(REGEXES[:cc_wiki])
|
|
271
|
+
end
|
|
272
|
+
|
|
277
273
|
def strip_unlicense_optional
|
|
278
274
|
return unless _content.include? 'unlicense'
|
|
279
275
|
|
|
@@ -295,7 +291,7 @@ module Licensee
|
|
|
295
291
|
|
|
296
292
|
def strip_html
|
|
297
293
|
return unless respond_to?(:filename) && filename
|
|
298
|
-
return unless File.extname(filename)
|
|
294
|
+
return unless /\.html?/i.match?(File.extname(filename))
|
|
299
295
|
|
|
300
296
|
require 'reverse_markdown'
|
|
301
297
|
@_content = ReverseMarkdown.convert(_content, unknown_tags: :bypass)
|
|
@@ -319,7 +315,7 @@ module Licensee
|
|
|
319
315
|
end
|
|
320
316
|
|
|
321
317
|
def normalize_bullets
|
|
322
|
-
normalize(REGEXES[:bullet], "\n\n
|
|
318
|
+
normalize(REGEXES[:bullet], "\n\n- ")
|
|
323
319
|
normalize(/\)\s+\(/, ')(')
|
|
324
320
|
end
|
|
325
321
|
|
|
@@ -337,10 +333,16 @@ module Licensee
|
|
|
337
333
|
@fields_normalized_set ||= fields_normalized.to_set
|
|
338
334
|
end
|
|
339
335
|
|
|
340
|
-
def
|
|
336
|
+
def variation_adjusted_length_delta(other)
|
|
341
337
|
delta = length_delta(other)
|
|
342
|
-
|
|
343
|
-
|
|
338
|
+
|
|
339
|
+
# The content helper mixin is used in different objects
|
|
340
|
+
# Licenses have a more advanced SPDX alt. segement-based delta.
|
|
341
|
+
# Use that if it's present, otherwise, just return the simple delta.
|
|
342
|
+
return delta unless respond_to?(:spdx_alt_segments, true)
|
|
343
|
+
|
|
344
|
+
adjusted_delta = delta - ([fields_normalized.size, spdx_alt_segments].max * 4)
|
|
345
|
+
adjusted_delta.positive? ? adjusted_delta : 0
|
|
344
346
|
end
|
|
345
347
|
end
|
|
346
348
|
end
|
data/lib/licensee/hash_helper.rb
CHANGED
data/lib/licensee/license.rb
CHANGED
|
@@ -4,6 +4,7 @@ require 'uri'
|
|
|
4
4
|
|
|
5
5
|
module Licensee
|
|
6
6
|
class InvalidLicense < ArgumentError; end
|
|
7
|
+
|
|
7
8
|
class License
|
|
8
9
|
@all = {}
|
|
9
10
|
@keys_licenses = {}
|
|
@@ -26,9 +27,11 @@ module Licensee
|
|
|
26
27
|
output.reject!(&:hidden?) unless options[:hidden]
|
|
27
28
|
output.reject!(&:pseudo_license?) unless options[:pseudo]
|
|
28
29
|
output.sort_by!(&:key)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
if options[:featured].nil?
|
|
31
|
+
output
|
|
32
|
+
else
|
|
33
|
+
output.select { |l| l.featured? == options[:featured] }
|
|
34
|
+
end
|
|
32
35
|
end
|
|
33
36
|
end
|
|
34
37
|
|
|
@@ -53,14 +56,17 @@ module Licensee
|
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
def license_dir
|
|
56
|
-
|
|
57
|
-
::File.expand_path '../../vendor/choosealicense.com/_licenses', dir
|
|
59
|
+
::File.expand_path '../../vendor/choosealicense.com/_licenses', __dir__
|
|
58
60
|
end
|
|
59
61
|
|
|
60
62
|
def license_files
|
|
61
63
|
@license_files ||= Dir.glob("#{license_dir}/*.txt")
|
|
62
64
|
end
|
|
63
65
|
|
|
66
|
+
def spdx_dir
|
|
67
|
+
::File.expand_path '../../vendor/license-list-XML/src', __dir__
|
|
68
|
+
end
|
|
69
|
+
|
|
64
70
|
private
|
|
65
71
|
|
|
66
72
|
def licenses
|
|
@@ -82,7 +88,7 @@ module Licensee
|
|
|
82
88
|
# `other` - The project had a license, but we were not able to detect it
|
|
83
89
|
# `no-license` - The project is not licensed (e.g., all rights reserved)
|
|
84
90
|
#
|
|
85
|
-
#
|
|
91
|
+
# NOTE: A lack of detected license will be a nil license
|
|
86
92
|
PSEUDO_LICENSES = %w[other no-license].freeze
|
|
87
93
|
|
|
88
94
|
# Default options to use when retrieving licenses via #all
|
|
@@ -139,6 +145,7 @@ module Licensee
|
|
|
139
145
|
return @title_regex if defined? @title_regex
|
|
140
146
|
|
|
141
147
|
string = name.downcase.sub('*', 'u')
|
|
148
|
+
simple_title_regex = Regexp.new string, 'i'
|
|
142
149
|
string.sub!(/\Athe /i, '')
|
|
143
150
|
string.sub!(/,? version /, ' ')
|
|
144
151
|
string.sub!(/v(\d+\.\d+)/, '\1')
|
|
@@ -153,10 +160,8 @@ module Licensee
|
|
|
153
160
|
string << '(?:\ licen[sc]e)?'
|
|
154
161
|
key_regex = Regexp.new string, 'i'
|
|
155
162
|
|
|
156
|
-
parts = [title_regex, key_regex]
|
|
157
|
-
if meta.nickname
|
|
158
|
-
parts.push Regexp.new meta.nickname.sub(/\bGNU /i, '(?:GNU )?')
|
|
159
|
-
end
|
|
163
|
+
parts = [simple_title_regex, title_regex, key_regex]
|
|
164
|
+
parts.push Regexp.new meta.nickname.sub(/\bGNU /i, '(?:GNU )?') if meta.nickname
|
|
160
165
|
|
|
161
166
|
@title_regex = Regexp.union parts
|
|
162
167
|
end
|
|
@@ -173,8 +178,8 @@ module Licensee
|
|
|
173
178
|
return @source_regex if defined? @source_regex
|
|
174
179
|
return unless meta.source
|
|
175
180
|
|
|
176
|
-
source = meta.source.dup.sub(/\A#{SOURCE_PREFIX}
|
|
177
|
-
source = source.sub(/#{SOURCE_SUFFIX}\z
|
|
181
|
+
source = meta.source.dup.sub(/\A#{SOURCE_PREFIX}/o, '')
|
|
182
|
+
source = source.sub(/#{SOURCE_SUFFIX}\z/o, '')
|
|
178
183
|
|
|
179
184
|
escaped_source = Regexp.escape(source)
|
|
180
185
|
@source_regex = /#{SOURCE_PREFIX}#{escaped_source}(?:#{SOURCE_SUFFIX})?/i
|
|
@@ -234,9 +239,7 @@ module Licensee
|
|
|
234
239
|
# Returns a string with `[fields]` replaced by `{{{fields}}}`
|
|
235
240
|
# Does not mangle non-supported fields in the form of `[field]`
|
|
236
241
|
def content_for_mustache
|
|
237
|
-
@content_for_mustache ||=
|
|
238
|
-
content.gsub(LicenseField::FIELD_REGEX, '{{{\1}}}')
|
|
239
|
-
end
|
|
242
|
+
@content_for_mustache ||= content.gsub(LicenseField::FIELD_REGEX, '{{{\1}}}')
|
|
240
243
|
end
|
|
241
244
|
|
|
242
245
|
private
|
|
@@ -244,9 +247,7 @@ module Licensee
|
|
|
244
247
|
# Raw content of license file, including YAML front matter
|
|
245
248
|
def raw_content
|
|
246
249
|
return if pseudo_license?
|
|
247
|
-
unless File.exist?(path)
|
|
248
|
-
raise Licensee::InvalidLicense, "'#{key}' is not a valid license key"
|
|
249
|
-
end
|
|
250
|
+
raise Licensee::InvalidLicense, "'#{key}' is not a valid license key" unless File.exist?(path)
|
|
250
251
|
|
|
251
252
|
@raw_content ||= File.read(path, encoding: 'utf-8')
|
|
252
253
|
end
|
|
@@ -260,5 +261,17 @@ module Licensee
|
|
|
260
261
|
def yaml
|
|
261
262
|
@yaml ||= parts[1] if parts
|
|
262
263
|
end
|
|
264
|
+
|
|
265
|
+
def spdx_alt_segments
|
|
266
|
+
@spdx_alt_segments ||= begin
|
|
267
|
+
path = File.expand_path "#{spdx_id}.xml", Licensee::License.spdx_dir
|
|
268
|
+
raw_xml = File.read(path, encoding: 'utf-8')
|
|
269
|
+
text = raw_xml.match(%r{<text>(.*)</text>}m)[1]
|
|
270
|
+
text.gsub!(%r{<copyrightText>.*?</copyrightText>}m, '')
|
|
271
|
+
text.gsub!(%r{<titleText>.*?</titleText>}m, '')
|
|
272
|
+
text.gsub!(%r{<optional.*?>.*?</optional>}m, '')
|
|
273
|
+
text.scan(/<alt .*?>/m).size
|
|
274
|
+
end
|
|
275
|
+
end
|
|
263
276
|
end
|
|
264
277
|
end
|
|
@@ -5,16 +5,11 @@ module Licensee
|
|
|
5
5
|
class Copyright < Licensee::Matchers::Matcher
|
|
6
6
|
attr_reader :file
|
|
7
7
|
|
|
8
|
-
# rubocop:disable Layout/LineLength
|
|
9
8
|
COPYRIGHT_SYMBOLS = Regexp.union([/copyright/i, /\(c\)/i, "\u00A9", "\xC2\xA9"])
|
|
10
|
-
REGEX = /#{ContentHelper::START_REGEX}(
|
|
11
|
-
# rubocop:enable Layout/LineLength
|
|
12
|
-
|
|
9
|
+
REGEX = /#{ContentHelper::START_REGEX}([_*\-\s]*#{COPYRIGHT_SYMBOLS}.*$)+$/i.freeze
|
|
13
10
|
def match
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
Licensee::License.find('no-license')
|
|
17
|
-
end
|
|
11
|
+
# NOTE: must use content, and not content_normalized here
|
|
12
|
+
Licensee::License.find('no-license') if /#{REGEX}+\z/io.match?(file.content.strip)
|
|
18
13
|
rescue Encoding::CompatibilityError
|
|
19
14
|
nil
|
|
20
15
|
end
|
|
@@ -26,7 +26,7 @@ module Licensee
|
|
|
26
26
|
# Otherwise, returns `nil`
|
|
27
27
|
def gpl_version(license_key)
|
|
28
28
|
match = license_key.match GPL_VERSION_REGEX
|
|
29
|
-
match ? "gpl-#{
|
|
29
|
+
match ? "gpl-#{match[1] || match[2]}.0" : nil
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
# Normalizes the license field value to an SPDX ID
|
|
@@ -10,7 +10,7 @@ module Licensee
|
|
|
10
10
|
nil
|
|
11
11
|
else
|
|
12
12
|
matches.first[0]
|
|
13
|
-
|
|
13
|
+
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
# Licenses that may be a match for this file.
|
|
@@ -21,13 +21,11 @@ module Licensee
|
|
|
21
21
|
# 2. The percentage change in file length may not exceed the inverse
|
|
22
22
|
# of the confidence threshold
|
|
23
23
|
def potential_matches
|
|
24
|
-
@potential_matches ||=
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
license.wordset
|
|
30
|
-
end
|
|
24
|
+
@potential_matches ||= super.select do |license|
|
|
25
|
+
if license.creative_commons? && file.potential_false_positive?
|
|
26
|
+
false
|
|
27
|
+
else
|
|
28
|
+
license.wordset
|
|
31
29
|
end
|
|
32
30
|
end
|
|
33
31
|
end
|
|
@@ -10,7 +10,14 @@ module Licensee
|
|
|
10
10
|
PREFERRED_EXT_REGEX = /\.#{Regexp.union(PREFERRED_EXT)}\z/.freeze
|
|
11
11
|
|
|
12
12
|
# Regex to match any extension except .spdx or .header
|
|
13
|
-
|
|
13
|
+
LICENSE_EXT_REGEX = %r{\.(?!spdx|header)[^./]+\z}i.freeze
|
|
14
|
+
|
|
15
|
+
# Regex to match any extension except a few unlikely as license
|
|
16
|
+
# texts with complex filenames
|
|
17
|
+
OTHER_EXT_REGEX = %r{\.(?!xml|go|gemspec)[^./]+\z}i.freeze
|
|
18
|
+
|
|
19
|
+
# Regex to match any extension
|
|
20
|
+
ANY_EXT_REGEX = %r{\.[^./]+\z}i.freeze
|
|
14
21
|
|
|
15
22
|
# Regex to match, LICENSE, LICENCE, unlicense, etc.
|
|
16
23
|
LICENSE_REGEX = /(un)?licen[sc]e/i.freeze
|
|
@@ -26,22 +33,22 @@ module Licensee
|
|
|
26
33
|
|
|
27
34
|
# Hash of Regex => score with which to score potential license files
|
|
28
35
|
FILENAME_REGEXES = {
|
|
29
|
-
/\A#{LICENSE_REGEX}\z/
|
|
30
|
-
/\A#{LICENSE_REGEX}#{PREFERRED_EXT_REGEX}\z/
|
|
31
|
-
/\A#{COPYING_REGEX}\z/
|
|
32
|
-
/\A#{COPYING_REGEX}#{PREFERRED_EXT_REGEX}\z/
|
|
33
|
-
/\A#{LICENSE_REGEX}#{
|
|
34
|
-
/\A#{COPYING_REGEX}#{
|
|
35
|
-
/\A#{LICENSE_REGEX}[-_]/
|
|
36
|
-
/\A#{COPYING_REGEX}[-_]/
|
|
37
|
-
/\A\w+[-_]#{LICENSE_REGEX}/
|
|
38
|
-
/\A\w+[-_]#{COPYING_REGEX}/
|
|
39
|
-
/\A#{OFL_REGEX}#{PREFERRED_EXT_REGEX}/
|
|
40
|
-
/\A#{OFL_REGEX}#{OTHER_EXT_REGEX}/
|
|
41
|
-
/\A#{OFL_REGEX}\z/
|
|
42
|
-
/\A#{PATENTS_REGEX}\z/
|
|
43
|
-
/\A#{PATENTS_REGEX}#{OTHER_EXT_REGEX}\z/
|
|
44
|
-
//
|
|
36
|
+
/\A#{LICENSE_REGEX}\z/ => 1.00, # LICENSE
|
|
37
|
+
/\A#{LICENSE_REGEX}#{PREFERRED_EXT_REGEX}\z/ => 0.95, # LICENSE.md
|
|
38
|
+
/\A#{COPYING_REGEX}\z/ => 0.90, # COPYING
|
|
39
|
+
/\A#{COPYING_REGEX}#{PREFERRED_EXT_REGEX}\z/ => 0.85, # COPYING.md
|
|
40
|
+
/\A#{LICENSE_REGEX}#{LICENSE_EXT_REGEX}\z/ => 0.80, # LICENSE.textile
|
|
41
|
+
/\A#{COPYING_REGEX}#{ANY_EXT_REGEX}\z/ => 0.75, # COPYING.textile
|
|
42
|
+
/\A#{LICENSE_REGEX}[-_][^.]*#{OTHER_EXT_REGEX}?\z/ => 0.70, # LICENSE-MIT
|
|
43
|
+
/\A#{COPYING_REGEX}[-_][^.]*#{OTHER_EXT_REGEX}?\z/ => 0.65, # COPYING-MIT
|
|
44
|
+
/\A\w+[-_]#{LICENSE_REGEX}[^.]*#{OTHER_EXT_REGEX}?\z/ => 0.60, # MIT-LICENSE-MIT
|
|
45
|
+
/\A\w+[-_]#{COPYING_REGEX}[^.]*#{OTHER_EXT_REGEX}?\z/ => 0.55, # MIT-COPYING
|
|
46
|
+
/\A#{OFL_REGEX}#{PREFERRED_EXT_REGEX}/ => 0.50, # OFL.md
|
|
47
|
+
/\A#{OFL_REGEX}#{OTHER_EXT_REGEX}/ => 0.45, # OFL.textile
|
|
48
|
+
/\A#{OFL_REGEX}\z/ => 0.40, # OFL
|
|
49
|
+
/\A#{PATENTS_REGEX}\z/ => 0.35, # PATENTS
|
|
50
|
+
/\A#{PATENTS_REGEX}#{OTHER_EXT_REGEX}\z/ => 0.30, # PATENTS.txt
|
|
51
|
+
// => 0.00 # Catch all
|
|
45
52
|
}.freeze
|
|
46
53
|
|
|
47
54
|
# CC-NC and CC-ND are not open source licenses and should not be
|
|
@@ -55,13 +62,11 @@ module Licensee
|
|
|
55
62
|
end
|
|
56
63
|
|
|
57
64
|
def attribution
|
|
58
|
-
@attribution ||=
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
matches[0] if matches
|
|
64
|
-
end
|
|
65
|
+
@attribution ||= if copyright? || license.content&.include?('[fullname]')
|
|
66
|
+
matches = Matchers::Copyright::REGEX
|
|
67
|
+
.match(content_without_title_and_version)
|
|
68
|
+
matches[0] if matches
|
|
69
|
+
end
|
|
65
70
|
end
|
|
66
71
|
|
|
67
72
|
# Is this file likely to result in a creative commons false positive?
|
|
@@ -37,9 +37,7 @@ module Licensee
|
|
|
37
37
|
def initialize(content, metadata = {})
|
|
38
38
|
@content = content.dup
|
|
39
39
|
@content.force_encoding(ENCODING)
|
|
40
|
-
unless @content.valid_encoding?
|
|
41
|
-
@content.encode!(ENCODING, **ENCODING_OPTIONS)
|
|
42
|
-
end
|
|
40
|
+
@content.encode!(ENCODING, **ENCODING_OPTIONS) unless @content.valid_encoding?
|
|
43
41
|
@content.encode!(ENCODING, universal_newline: true)
|
|
44
42
|
|
|
45
43
|
metadata = { name: metadata } if metadata.is_a? String
|
|
@@ -93,7 +91,7 @@ module Licensee
|
|
|
93
91
|
return false unless is_a?(LicenseFile)
|
|
94
92
|
return false unless matcher.is_a?(Matchers::Copyright)
|
|
95
93
|
|
|
96
|
-
filename =~ /\Acopyright(?:#{LicenseFile::OTHER_EXT_REGEX})?\z/
|
|
94
|
+
filename =~ /\Acopyright(?:#{LicenseFile::OTHER_EXT_REGEX})?\z/io
|
|
97
95
|
end
|
|
98
96
|
|
|
99
97
|
def content_hash
|
|
@@ -20,9 +20,7 @@ module Licensee
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
@root = File.expand_path(args.delete(:search_root) || @dir)
|
|
23
|
-
unless valid_search_root?
|
|
24
|
-
raise 'Search root must be the project path directory or its ancestor'
|
|
25
|
-
end
|
|
23
|
+
raise 'Search root must be the project path directory or its ancestor' unless valid_search_root?
|
|
26
24
|
|
|
27
25
|
super(**args)
|
|
28
26
|
end
|
|
@@ -27,11 +27,11 @@ module Licensee
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def repository
|
|
30
|
-
@repository ||=
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
@repository ||= if @raw_repo.is_a? Rugged::Repository
|
|
31
|
+
@raw_repo
|
|
32
|
+
else
|
|
33
|
+
Rugged::Repository.new(@raw_repo)
|
|
34
|
+
end
|
|
35
35
|
rescue Rugged::OSError, Rugged::RepositoryError
|
|
36
36
|
raise InvalidRepository
|
|
37
37
|
end
|
|
@@ -47,7 +47,7 @@ module Licensee
|
|
|
47
47
|
repository.lookup(revision)
|
|
48
48
|
else
|
|
49
49
|
repository.last_commit
|
|
50
|
-
|
|
50
|
+
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
MAX_LICENSE_SIZE = 64 * 1024
|
|
@@ -28,7 +28,7 @@ module Licensee
|
|
|
28
28
|
licenses_without_copyright.first
|
|
29
29
|
elsif licenses_without_copyright.count > 1
|
|
30
30
|
Licensee::License.find('other')
|
|
31
|
-
|
|
31
|
+
end
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# Returns an array of detected Licenses
|
|
@@ -43,9 +43,7 @@ module Licensee
|
|
|
43
43
|
|
|
44
44
|
# Returns an array of matches LicenseFiles
|
|
45
45
|
def matched_files
|
|
46
|
-
@matched_files ||=
|
|
47
|
-
project_files.select(&:license)
|
|
48
|
-
end
|
|
46
|
+
@matched_files ||= project_files.select(&:license)
|
|
49
47
|
end
|
|
50
48
|
|
|
51
49
|
# Returns the LicenseFile used to determine the License
|
|
@@ -54,18 +52,17 @@ module Licensee
|
|
|
54
52
|
end
|
|
55
53
|
|
|
56
54
|
def license_files
|
|
57
|
-
@license_files ||=
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
end
|
|
55
|
+
@license_files ||= if files.empty? || files.nil?
|
|
56
|
+
[]
|
|
57
|
+
else
|
|
58
|
+
files = find_files do |n|
|
|
59
|
+
Licensee::ProjectFiles::LicenseFile.name_score(n)
|
|
60
|
+
end
|
|
61
|
+
files = files.map do |file|
|
|
62
|
+
Licensee::ProjectFiles::LicenseFile.new(load_file(file), file)
|
|
63
|
+
end
|
|
64
|
+
prioritize_lgpl(files)
|
|
65
|
+
end
|
|
69
66
|
end
|
|
70
67
|
|
|
71
68
|
def readme_file
|
|
@@ -154,9 +151,7 @@ module Licensee
|
|
|
154
151
|
# Returns an array of matches licenses, excluding the COPYRIGHT file
|
|
155
152
|
# which can often be ignored for purposes of determing dual licensing
|
|
156
153
|
def licenses_without_copyright
|
|
157
|
-
@licenses_without_copyright ||=
|
|
158
|
-
matched_files.reject(&:copyright?).map(&:license).uniq
|
|
159
|
-
end
|
|
154
|
+
@licenses_without_copyright ||= matched_files.reject(&:copyright?).map(&:license).uniq
|
|
160
155
|
end
|
|
161
156
|
|
|
162
157
|
def files
|
data/lib/licensee/version.rb
CHANGED