licensee 9.14.1 → 9.15.2

Sign up to get free protection for your applications and to get access to all the features.
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