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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +1 -1
  3. data/bin/licensee +1 -1
  4. data/lib/licensee/commands/detect.rb +3 -5
  5. data/lib/licensee/commands/diff.rb +3 -7
  6. data/lib/licensee/content_helper.rb +30 -28
  7. data/lib/licensee/hash_helper.rb +1 -1
  8. data/lib/licensee/license.rb +31 -18
  9. data/lib/licensee/matchers/copyright.rb +3 -8
  10. data/lib/licensee/matchers/cran.rb +1 -1
  11. data/lib/licensee/matchers/dice.rb +6 -8
  12. data/lib/licensee/project_files/license_file.rb +29 -24
  13. data/lib/licensee/project_files/project_file.rb +2 -4
  14. data/lib/licensee/project_files/readme_file.rb +1 -1
  15. data/lib/licensee/projects/fs_project.rb +1 -3
  16. data/lib/licensee/projects/git_project.rb +6 -6
  17. data/lib/licensee/projects/project.rb +14 -19
  18. data/lib/licensee/version.rb +1 -1
  19. data/lib/licensee.rb +7 -4
  20. data/licensee.gemspec +6 -4
  21. data/spec/fixture_spec.rb +2 -2
  22. data/spec/fixtures/bsd-3-authorowner/LICENSE +27 -0
  23. data/spec/fixtures/cc-by-sa-mdlinks/License.md +173 -0
  24. data/spec/fixtures/cc-by-sa-nocclicensor/License.md +425 -0
  25. data/spec/fixtures/detect.json +5 -5
  26. data/spec/fixtures/eupl-cal2017/LICENSE.txt +274 -0
  27. data/spec/fixtures/fixtures.yml +45 -25
  28. data/spec/fixtures/license-hashes.json +40 -38
  29. data/spec/fixtures/pixar-modified-apache/LICENSE.txt +174 -0
  30. data/spec/integration_spec.rb +46 -6
  31. data/spec/licensee/commands/detect_spec.rb +2 -2
  32. data/spec/licensee/content_helper_spec.rb +18 -13
  33. data/spec/licensee/license_spec.rb +6 -6
  34. data/spec/licensee/matchers/dice_matcher_spec.rb +3 -3
  35. data/spec/licensee/project_files/license_file_spec.rb +9 -3
  36. data/spec/licensee/project_files/package_info_spec.rb +2 -2
  37. data/spec/licensee/project_spec.rb +4 -5
  38. data/spec/licensee_spec.rb +8 -2
  39. data/spec/spec_helper.rb +3 -3
  40. data/spec/vendored_license_spec.rb +1 -3
  41. data/vendor/choosealicense.com/_licenses/0bsd.txt +4 -2
  42. data/vendor/choosealicense.com/_licenses/afl-3.0.txt +12 -12
  43. data/vendor/choosealicense.com/_licenses/apache-2.0.txt +1 -1
  44. data/vendor/choosealicense.com/_licenses/bsd-3-clause.txt +2 -2
  45. data/vendor/choosealicense.com/_licenses/bsl-1.0.txt +1 -1
  46. data/vendor/choosealicense.com/_licenses/cc-by-4.0.txt +1 -1
  47. data/vendor/choosealicense.com/_licenses/cc-by-sa-4.0.txt +1 -1
  48. data/vendor/choosealicense.com/_licenses/eupl-1.2.txt +75 -58
  49. data/vendor/choosealicense.com/_licenses/isc.txt +8 -8
  50. data/vendor/choosealicense.com/_licenses/mit-0.txt +45 -0
  51. data/vendor/choosealicense.com/_licenses/mulanpsl-2.0.txt +226 -0
  52. data/vendor/choosealicense.com/_licenses/odbl-1.0.txt +2 -2
  53. data/vendor/choosealicense.com/_licenses/osl-3.0.txt +1 -1
  54. data/vendor/choosealicense.com/_licenses/unlicense.txt +1 -1
  55. data/vendor/choosealicense.com/_licenses/upl-1.0.txt +1 -1
  56. data/vendor/license-list-XML/src/0BSD.xml +25 -0
  57. data/vendor/license-list-XML/src/AFL-3.0.xml +212 -0
  58. data/vendor/license-list-XML/src/AGPL-3.0.xml +852 -0
  59. data/vendor/license-list-XML/src/Apache-2.0.xml +223 -0
  60. data/vendor/license-list-XML/src/Artistic-2.0.xml +238 -0
  61. data/vendor/license-list-XML/src/BSD-2-Clause.xml +42 -0
  62. data/vendor/license-list-XML/src/BSD-3-Clause-Clear.xml +59 -0
  63. data/vendor/license-list-XML/src/BSD-3-Clause.xml +46 -0
  64. data/vendor/license-list-XML/src/BSD-4-Clause.xml +59 -0
  65. data/vendor/license-list-XML/src/BSL-1.0.xml +30 -0
  66. data/vendor/license-list-XML/src/CC-BY-4.0.xml +446 -0
  67. data/vendor/license-list-XML/src/CC-BY-SA-4.0.xml +477 -0
  68. data/vendor/license-list-XML/src/CC0-1.0.xml +153 -0
  69. data/vendor/license-list-XML/src/CECILL-2.1.xml +669 -0
  70. data/vendor/license-list-XML/src/ECL-2.0.xml +242 -0
  71. data/vendor/license-list-XML/src/EPL-1.0.xml +255 -0
  72. data/vendor/license-list-XML/src/EPL-2.0.xml +639 -0
  73. data/vendor/license-list-XML/src/EUPL-1.1.xml +337 -0
  74. data/vendor/license-list-XML/src/EUPL-1.2.xml +502 -0
  75. data/vendor/license-list-XML/src/GPL-2.0.xml +474 -0
  76. data/vendor/license-list-XML/src/GPL-3.0.xml +858 -0
  77. data/vendor/license-list-XML/src/ISC.xml +31 -0
  78. data/vendor/license-list-XML/src/LGPL-2.1.xml +662 -0
  79. data/vendor/license-list-XML/src/LGPL-3.0.xml +260 -0
  80. data/vendor/license-list-XML/src/LPPL-1.3c.xml +380 -0
  81. data/vendor/license-list-XML/src/MIT-0.xml +40 -0
  82. data/vendor/license-list-XML/src/MIT.xml +32 -0
  83. data/vendor/license-list-XML/src/MPL-2.0.xml +438 -0
  84. data/vendor/license-list-XML/src/MS-PL.xml +89 -0
  85. data/vendor/license-list-XML/src/MS-RL.xml +97 -0
  86. data/vendor/license-list-XML/src/MulanPSL-2.0.xml +167 -0
  87. data/vendor/license-list-XML/src/NCSA.xml +60 -0
  88. data/vendor/license-list-XML/src/ODbL-1.0.xml +660 -0
  89. data/vendor/license-list-XML/src/OFL-1.1.xml +94 -0
  90. data/vendor/license-list-XML/src/OSL-3.0.xml +209 -0
  91. data/vendor/license-list-XML/src/PostgreSQL.xml +32 -0
  92. data/vendor/license-list-XML/src/UPL-1.0.xml +46 -0
  93. data/vendor/license-list-XML/src/Unlicense.xml +27 -0
  94. data/vendor/license-list-XML/src/Vim.xml +124 -0
  95. data/vendor/license-list-XML/src/WTFPL.xml +30 -0
  96. data/vendor/license-list-XML/src/Zlib.xml +38 -0
  97. metadata +75 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0cdac44039e6185c028d41ab8112b43d7e1ba66f2c8bd02be490255d14dfac38
4
- data.tar.gz: 895ffc0aa9296fef49193b6282edb6286a9115ba4b3207be4c15df5755ca3bf7
3
+ metadata.gz: 334874469d14f16839113e4311ba232c18a8bc8d0ee0c618034ec30e16497f47
4
+ data.tar.gz: aaca8fc841545017ee7dc58e02a8ce41845d3253a281153b599f187218c6fc6a
5
5
  SHA512:
6
- metadata.gz: eb7c6c9d1b2a8c8258b8d499efa96ab7b25b83108bb47ed163eabd5d78e83a2443a0bbf6f43eb1abda0b441e8696a17f79066ec4356c80a1b88d3c40338c726b
7
- data.tar.gz: e1bfeb5c75d28b334d880351acf7977c71e5efa9b61c407c204921475070c3ede8b2331b82cc64446fa81577ede499cf8d2d5b6d70ae1fc507cc238ee4a52a08
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-2020 Ben Balter and Licensee contributors
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
@@ -19,7 +19,7 @@ class LicenseeCLI < Thor
19
19
  args.first || Dir.pwd
20
20
  else
21
21
  "https://github.com/#{args.first}"
22
- end
22
+ end
23
23
  end
24
24
 
25
25
  def project
@@ -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
- end
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('@potential_licenses', potential_licenses)
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 ||= begin
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
- quote_begin: /[`'"‘“]/,
27
- quote_end: /[`'"’”]/,
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
- quotes: {
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/](?:'s|(?<=s)')?)+})&.to_set
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 + fields_adjusted_length_delta(other) / 10)
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) =~ /\.html?/i
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 fields_adjusted_length_delta(other)
336
+ def variation_adjusted_length_delta(other)
341
337
  delta = length_delta(other)
342
- adjusted_delta = delta - fields_normalized.size * 2
343
- adjusted_delta.positive? ? adjusted_delta : delta
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
@@ -13,7 +13,7 @@ module Licensee
13
13
  value.to_h
14
14
  else
15
15
  value
16
- end
16
+ end
17
17
  end
18
18
 
19
19
  hash
@@ -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
- return output if options[:featured].nil?
30
-
31
- output.select { |l| l.featured? == options[:featured] }
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
- dir = ::File.dirname(__FILE__)
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
- # Note: A lack of detected license will be a nil license
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 ||= begin
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}(?:portions )?([_*\-\s]*#{COPYRIGHT_SYMBOLS}.*$)+$/i.freeze
11
- # rubocop:enable Layout/LineLength
12
-
9
+ REGEX = /#{ContentHelper::START_REGEX}([_*\-\s]*#{COPYRIGHT_SYMBOLS}.*$)+$/i.freeze
13
10
  def match
14
- # Note: must use content, and not content_normalized here
15
- if file.content.strip =~ /#{REGEX}+\z/i
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-#{(match[1] || match[2])}.0" : nil
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
- end
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 ||= begin
25
- super.select do |license|
26
- if license.creative_commons? && file.potential_false_positive?
27
- false
28
- else
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
- OTHER_EXT_REGEX = %r{\.(?!spdx|header|gemspec)[^./]+\z}i.freeze
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/ => 1.00, # LICENSE
30
- /\A#{LICENSE_REGEX}#{PREFERRED_EXT_REGEX}\z/ => 0.95, # LICENSE.md
31
- /\A#{COPYING_REGEX}\z/ => 0.90, # COPYING
32
- /\A#{COPYING_REGEX}#{PREFERRED_EXT_REGEX}\z/ => 0.85, # COPYING.md
33
- /\A#{LICENSE_REGEX}#{OTHER_EXT_REGEX}\z/ => 0.80, # LICENSE.textile
34
- /\A#{COPYING_REGEX}#{OTHER_EXT_REGEX}\z/ => 0.75, # COPYING.textile
35
- /\A#{LICENSE_REGEX}[-_]/ => 0.70, # LICENSE-MIT
36
- /\A#{COPYING_REGEX}[-_]/ => 0.65, # COPYING-MIT
37
- /\A\w+[-_]#{LICENSE_REGEX}/ => 0.60, # MIT-LICENSE-MIT
38
- /\A\w+[-_]#{COPYING_REGEX}/ => 0.55, # MIT-COPYING
39
- /\A#{OFL_REGEX}#{PREFERRED_EXT_REGEX}/ => 0.50, # OFL.md
40
- /\A#{OFL_REGEX}#{OTHER_EXT_REGEX}/ => 0.45, # OFL.textile
41
- /\A#{OFL_REGEX}\z/ => 0.40, # OFL
42
- /\A#{PATENTS_REGEX}\z/ => 0.35, # PATENTS
43
- /\A#{PATENTS_REGEX}#{OTHER_EXT_REGEX}\z/ => 0.30, # PATENTS.txt
44
- // => 0.00 # Catch all
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 ||= begin
59
- return unless copyright? || license.content&.include?('[fullname]')
60
-
61
- matches = Matchers::Copyright::REGEX
62
- .match(content_without_title_and_version)
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/i
94
+ filename =~ /\Acopyright(?:#{LicenseFile::OTHER_EXT_REGEX})?\z/io
97
95
  end
98
96
 
99
97
  def content_hash
@@ -35,7 +35,7 @@ module Licensee
35
35
 
36
36
  def self.name_score(filename)
37
37
  SCORES.each do |pattern, score|
38
- return score if pattern =~ filename
38
+ return score if pattern&.match?(filename)
39
39
  end
40
40
  0.0
41
41
  end
@@ -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 ||= begin
31
- return @raw_repo if @raw_repo.is_a? Rugged::Repository
32
-
33
- Rugged::Repository.new(@raw_repo)
34
- end
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
- end
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
- end
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 ||= begin
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 ||= begin
58
- return [] if files.empty? || files.nil?
59
-
60
- files = find_files do |n|
61
- Licensee::ProjectFiles::LicenseFile.name_score(n)
62
- end
63
- files = files.map do |file|
64
- Licensee::ProjectFiles::LicenseFile.new(load_file(file), file)
65
- end
66
-
67
- prioritize_lgpl(files)
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 ||= begin
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Licensee
4
- VERSION = '9.14.1'
4
+ VERSION = '9.15.2'
5
5
  end