bibliothecary 11.0.1 → 12.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +2 -1
  3. data/.rubocop.yml +10 -2
  4. data/.ruby-version +1 -1
  5. data/CHANGELOG.md +24 -0
  6. data/Gemfile +16 -1
  7. data/Rakefile +2 -0
  8. data/bibliothecary.gemspec +11 -14
  9. data/bin/bibliothecary +2 -1
  10. data/bin/console +1 -0
  11. data/lib/bibliothecary/analyser/analysis.rb +13 -8
  12. data/lib/bibliothecary/analyser/determinations.rb +2 -0
  13. data/lib/bibliothecary/analyser/matchers.rb +17 -17
  14. data/lib/bibliothecary/analyser.rb +11 -8
  15. data/lib/bibliothecary/cli.rb +3 -1
  16. data/lib/bibliothecary/configuration.rb +3 -11
  17. data/lib/bibliothecary/dependency.rb +17 -15
  18. data/lib/bibliothecary/exceptions.rb +6 -2
  19. data/lib/bibliothecary/file_info.rb +9 -11
  20. data/lib/bibliothecary/multi_parsers/bundler_like_manifest.rb +13 -10
  21. data/lib/bibliothecary/multi_parsers/cyclonedx.rb +10 -8
  22. data/lib/bibliothecary/multi_parsers/dependencies_csv.rb +11 -4
  23. data/lib/bibliothecary/multi_parsers/json_runtime.rb +5 -2
  24. data/lib/bibliothecary/multi_parsers/spdx.rb +24 -19
  25. data/lib/bibliothecary/parsers/bower.rb +5 -3
  26. data/lib/bibliothecary/parsers/cargo.rb +10 -4
  27. data/lib/bibliothecary/parsers/cocoapods.rb +15 -11
  28. data/lib/bibliothecary/parsers/conda.rb +56 -33
  29. data/lib/bibliothecary/parsers/cpan.rb +6 -4
  30. data/lib/bibliothecary/parsers/cran.rb +10 -6
  31. data/lib/bibliothecary/parsers/dub.rb +4 -2
  32. data/lib/bibliothecary/parsers/elm.rb +4 -1
  33. data/lib/bibliothecary/parsers/go.rb +51 -43
  34. data/lib/bibliothecary/parsers/haxelib.rb +2 -1
  35. data/lib/bibliothecary/parsers/julia.rb +5 -1
  36. data/lib/bibliothecary/parsers/maven.rb +93 -77
  37. data/lib/bibliothecary/parsers/meteor.rb +2 -0
  38. data/lib/bibliothecary/parsers/npm.rb +97 -34
  39. data/lib/bibliothecary/parsers/nuget.rb +37 -28
  40. data/lib/bibliothecary/parsers/packagist.rb +21 -11
  41. data/lib/bibliothecary/parsers/pub.rb +4 -2
  42. data/lib/bibliothecary/parsers/pypi.rb +48 -37
  43. data/lib/bibliothecary/parsers/rubygems.rb +16 -12
  44. data/lib/bibliothecary/parsers/shard.rb +10 -7
  45. data/lib/bibliothecary/purl_util.rb +2 -4
  46. data/lib/bibliothecary/related_files_info.rb +7 -8
  47. data/lib/bibliothecary/runner/multi_manifest_filter.rb +5 -4
  48. data/lib/bibliothecary/runner.rb +12 -10
  49. data/lib/bibliothecary/version.rb +3 -1
  50. data/lib/bibliothecary.rb +7 -4
  51. data/lib/sdl_parser.rb +11 -6
  52. metadata +18 -120
  53. data/lib/bibliothecary/parsers/carthage.rb +0 -52
  54. data/lib/bibliothecary/parsers/clojars.rb +0 -38
  55. data/lib/bibliothecary/parsers/hackage.rb +0 -53
  56. data/lib/bibliothecary/parsers/hex.rb +0 -54
  57. data/lib/bibliothecary/parsers/swift_pm.rb +0 -35
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  module Parsers
3
5
  class Pypi
@@ -24,15 +26,15 @@ module Bibliothecary
24
26
  "requirements-docs.txt", "requirements/docs.txt",
25
27
  "requirements-test.txt", "requirements/test.txt",
26
28
  "requirements-tools.txt", "requirements/tools.txt") => {
27
- kind: "manifest",
28
- parser: :parse_requirements_txt,
29
- },
30
- lambda { |p| PIP_COMPILE_REGEXP.match(p) } => {
29
+ kind: "manifest",
30
+ parser: :parse_requirements_txt,
31
+ },
32
+ ->(p) { PIP_COMPILE_REGEXP.match(p) } => {
31
33
  content_matcher: :pip_compile?,
32
34
  kind: "lockfile",
33
35
  parser: :parse_requirements_txt,
34
36
  },
35
- lambda { |p| MANIFEST_REGEXP.match(p) } => {
37
+ ->(p) { MANIFEST_REGEXP.match(p) } => {
36
38
  kind: "manifest",
37
39
  parser: :parse_requirements_txt,
38
40
  can_have_lockfile: false,
@@ -79,14 +81,6 @@ module Bibliothecary
79
81
  parser: :parse_conda,
80
82
  kind: "manifest",
81
83
  },
82
- match_filename("environment.yml.lock") => {
83
- parser: :parse_conda,
84
- kind: "lockfile",
85
- },
86
- match_filename("environment.yaml.lock") => {
87
- parser: :parse_conda,
88
- kind: "lockfile",
89
- },
90
84
  }
91
85
  end
92
86
 
@@ -94,33 +88,34 @@ module Bibliothecary
94
88
  add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
95
89
  add_multi_parser(Bibliothecary::MultiParsers::Spdx)
96
90
 
97
- def self.parse_pipfile(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
91
+ def self.parse_pipfile(file_contents, options: {})
98
92
  manifest = Tomlrb.parse(file_contents)
99
- map_dependencies(manifest["packages"], "runtime") + map_dependencies(manifest["dev-packages"], "develop")
93
+ map_dependencies(manifest["packages"], "runtime", options.fetch(:filename, nil)) +
94
+ map_dependencies(manifest["dev-packages"], "develop", options.fetch(:filename, nil))
100
95
  end
101
96
 
102
- def self.parse_pyproject(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
97
+ def self.parse_pyproject(file_contents, options: {})
103
98
  deps = []
104
99
 
105
100
  file_contents = Tomlrb.parse(file_contents)
106
101
 
107
102
  # Parse poetry [tool.poetry] deps
108
103
  poetry_manifest = file_contents.fetch("tool", {}).fetch("poetry", {})
109
- deps += map_dependencies(poetry_manifest["dependencies"], "runtime")
104
+ deps += map_dependencies(poetry_manifest["dependencies"], "runtime", options.fetch(:filename, nil))
110
105
  # Poetry 1.0.0-1.2.0 way of defining dev deps
111
- deps += map_dependencies(poetry_manifest["dev-dependencies"], "develop")
106
+ deps += map_dependencies(poetry_manifest["dev-dependencies"], "develop", options.fetch(:filename, nil))
112
107
  # Poetry's 1.2.0+ of defining dev deps
113
108
  poetry_manifest
114
109
  .fetch("group", {})
115
110
  .each_pair do |group_name, obj|
116
111
  group_name = "develop" if group_name == "dev"
117
- deps += map_dependencies(obj.fetch("dependencies", {}), group_name)
112
+ deps += map_dependencies(obj.fetch("dependencies", {}), group_name, options.fetch(:filename, nil))
118
113
  end
119
114
 
120
115
  # Parse PEP621 [project] deps
121
116
  pep621_manifest = file_contents.fetch("project", {})
122
117
  pep621_deps = pep621_manifest.fetch("dependencies", []).map { |d| parse_pep_508_dep_spec(d) }
123
- deps += map_dependencies(pep621_deps, "runtime")
118
+ deps += map_dependencies(pep621_deps, "runtime", options.fetch(:filename, nil))
124
119
 
125
120
  # We're combining both poetry+PEP621 deps instead of making them mutually exclusive, until we
126
121
  # find a reason not to ingest them both.
@@ -133,24 +128,26 @@ module Bibliothecary
133
128
  parse_pyproject(file_contents, options)
134
129
  end
135
130
 
136
- def self.parse_conda(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
131
+ def self.parse_conda(file_contents, options: {})
137
132
  contents = YAML.safe_load(file_contents)
138
133
  return [] unless contents
139
134
 
140
135
  dependencies = contents["dependencies"]
141
- pip = dependencies.find { |dep| dep.is_a?(Hash) && dep["pip"]}
136
+ pip = dependencies.find { |dep| dep.is_a?(Hash) && dep["pip"] }
142
137
  return [] unless pip
143
138
 
144
- Pypi.parse_requirements_txt(pip["pip"].join("\n"))
139
+ Pypi.parse_requirements_txt(pip["pip"].join("\n"), options:)
145
140
  end
146
141
 
147
- def self.map_dependencies(packages, type)
142
+ def self.map_dependencies(packages, type, source = nil)
148
143
  return [] unless packages
144
+
149
145
  packages.map do |name, info|
150
146
  Dependency.new(
151
147
  name: name,
152
148
  requirement: map_requirements(info),
153
149
  type: type,
150
+ source: source
154
151
  )
155
152
  end
156
153
  end
@@ -160,7 +157,7 @@ module Bibliothecary
160
157
  if info["version"]
161
158
  info["version"]
162
159
  elsif info["git"]
163
- info["git"] + "#" + info["ref"]
160
+ "#{info['git']}##{info['ref']}"
164
161
  else
165
162
  "*"
166
163
  end
@@ -169,24 +166,26 @@ module Bibliothecary
169
166
  end
170
167
  end
171
168
 
172
- def self.parse_pipfile_lock(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
169
+ def self.parse_pipfile_lock(file_contents, options: {})
173
170
  manifest = JSON.parse(file_contents)
174
171
  deps = []
175
172
  manifest.each do |group, dependencies|
176
173
  next if group == "_meta"
174
+
177
175
  group = "runtime" if group == "default"
178
176
  dependencies.each do |name, info|
179
177
  deps << Dependency.new(
180
178
  name: name,
181
179
  requirement: map_requirements(info),
182
180
  type: group,
181
+ source: options.fetch(:filename, nil)
183
182
  )
184
183
  end
185
184
  end
186
185
  deps
187
186
  end
188
187
 
189
- def self.parse_poetry_lock(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
188
+ def self.parse_poetry_lock(file_contents, options: {})
190
189
  manifest = Tomlrb.parse(file_contents)
191
190
  deps = []
192
191
  manifest["package"].each do |package|
@@ -202,23 +201,28 @@ module Bibliothecary
202
201
  name: package["name"],
203
202
  requirement: map_requirements(package),
204
203
  type: group,
204
+ source: options.fetch(:filename, nil)
205
205
  )
206
206
  end
207
207
  deps
208
208
  end
209
209
 
210
- def self.parse_setup_py(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
210
+ def self.parse_setup_py(file_contents, options: {})
211
211
  match = file_contents.match(INSTALL_REGEXP)
212
212
  return [] unless match
213
+
213
214
  deps = []
214
215
  match[1].gsub(/',(\s)?'/, "\n").split("\n").each do |line|
215
216
  next if line.match(/^#/)
217
+
216
218
  match = line.match(REQUIRE_REGEXP)
217
219
  next unless match
220
+
218
221
  deps << Dependency.new(
219
222
  name: match[1],
220
223
  requirement: match[-1],
221
224
  type: "runtime",
225
+ source: options.fetch(:filename, nil)
222
226
  )
223
227
  end
224
228
  deps
@@ -234,9 +238,10 @@ module Bibliothecary
234
238
  JSON.parse(file_contents)
235
239
  .map do |pkg|
236
240
  Dependency.new(
237
- name: pkg.dig("package", "package_name"),
238
- requirement: pkg.dig("package", "installed_version"),
239
- type: "runtime",
241
+ name: pkg.dig("package", "package_name"),
242
+ requirement: pkg.dig("package", "installed_version"),
243
+ type: "runtime",
244
+ source: options.fetch(:filename, nil)
240
245
  )
241
246
  end
242
247
  .uniq
@@ -246,7 +251,7 @@ module Bibliothecary
246
251
  # https://pip.pypa.io/en/stable/cli/pip_install/#requirement-specifiers
247
252
  # and https://pip.pypa.io/en/stable/topics/vcs-support/#git.
248
253
  # Invalid lines in requirements.txt are skipped.
249
- def self.parse_requirements_txt(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
254
+ def self.parse_requirements_txt(file_contents, options: {})
250
255
  deps = []
251
256
  type = case options[:filename]
252
257
  when /dev/ || /docs/ || /tools/
@@ -260,7 +265,7 @@ module Bibliothecary
260
265
  file_contents.split("\n").each do |line|
261
266
  if line["://"]
262
267
  begin
263
- result = parse_requirements_txt_url(line, type)
268
+ result = parse_requirements_txt_url(line, type, options.fetch(:filename, nil))
264
269
  rescue URI::Error, NoEggSpecified
265
270
  next
266
271
  end
@@ -271,6 +276,7 @@ module Bibliothecary
271
276
  name: match[1],
272
277
  requirement: match[-1],
273
278
  type: type,
279
+ source: options.fetch(:filename, nil)
274
280
  )
275
281
  end
276
282
  end
@@ -278,7 +284,7 @@ module Bibliothecary
278
284
  deps.uniq
279
285
  end
280
286
 
281
- def self.parse_requirements_txt_url(url, type=nil)
287
+ def self.parse_requirements_txt_url(url, type = nil, source = nil)
282
288
  uri = URI.parse(url)
283
289
  raise NoEggSpecified, "No egg specified in #{url}" unless uri.fragment
284
290
 
@@ -287,11 +293,16 @@ module Bibliothecary
287
293
 
288
294
  requirement = uri.path[/@(.+)$/, 1]
289
295
 
290
- Dependency.new(name: name, requirement: requirement, type: type)
296
+ Dependency.new(
297
+ name: name,
298
+ requirement: requirement,
299
+ type: type,
300
+ source: source
301
+ )
291
302
  end
292
303
 
293
304
  def self.pip_compile?(file_contents)
294
- return file_contents.include?("This file is autogenerated by pip-compile")
305
+ file_contents.include?("This file is autogenerated by pip-compile")
295
306
  rescue Exception # rubocop:disable Lint/RescueException
296
307
  # We rescue exception here since native libs can throw a non-StandardError
297
308
  # We don't want to throw errors during the matching phase, only during
@@ -305,7 +316,7 @@ module Bibliothecary
305
316
  name, requirement = dep.split(PEP_508_NAME_REGEXP, 2).last(2).map(&:strip)
306
317
  requirement = requirement.sub(/^[\s;]*/, "")
307
318
  requirement = "*" if requirement == ""
308
- return name, requirement
319
+ [name, requirement]
309
320
  end
310
321
  end
311
322
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "gemnasium/parser"
2
4
 
3
5
  module Bibliothecary
@@ -6,7 +8,7 @@ module Bibliothecary
6
8
  include Bibliothecary::Analyser
7
9
  extend Bibliothecary::MultiParsers::BundlerLikeManifest
8
10
 
9
- NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'.freeze
11
+ NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'
10
12
  NAME_VERSION_4 = /^ {4}#{NAME_VERSION}$/
11
13
  BUNDLED_WITH = /BUNDLED WITH/
12
14
 
@@ -15,17 +17,17 @@ module Bibliothecary
15
17
  match_filenames("Gemfile", "gems.rb") => {
16
18
  kind: "manifest",
17
19
  parser: :parse_gemfile,
18
- related_to: [ "manifest", "lockfile" ],
20
+ related_to: %w[manifest lockfile],
19
21
  },
20
22
  match_extension(".gemspec") => {
21
23
  kind: "manifest",
22
24
  parser: :parse_gemspec,
23
- related_to: [ "manifest", "lockfile" ],
25
+ related_to: %w[manifest lockfile],
24
26
  },
25
27
  match_filenames("Gemfile.lock", "gems.locked") => {
26
28
  kind: "lockfile",
27
29
  parser: :parse_gemfile_lock,
28
- related_to: [ "manifest", "lockfile" ],
30
+ related_to: %w[manifest lockfile],
29
31
  },
30
32
  }
31
33
  end
@@ -34,7 +36,7 @@ module Bibliothecary
34
36
  add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
35
37
  add_multi_parser(Bibliothecary::MultiParsers::Spdx)
36
38
 
37
- def self.parse_gemfile_lock(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
39
+ def self.parse_gemfile_lock(file_contents, options: {})
38
40
  file_contents.lines(chomp: true).map do |line|
39
41
  match = line.match(NAME_VERSION_4)
40
42
  bundler_match = line.match(BUNDLED_WITH)
@@ -42,29 +44,30 @@ module Bibliothecary
42
44
 
43
45
  if match
44
46
  name = match[1]
45
- version = match[2].gsub(/\(|\)/,"")
47
+ version = match[2].gsub(/\(|\)/, "")
46
48
  Dependency.new(
47
49
  name: name,
48
50
  requirement: version,
49
51
  type: "runtime",
52
+ source: options.fetch(:filename, nil)
50
53
  )
51
54
  else
52
- parse_bundler(file_contents)
55
+ parse_bundler(file_contents, options.fetch(:filename, nil))
53
56
  end
54
57
  end.compact
55
58
  end
56
59
 
57
- def self.parse_gemfile(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
60
+ def self.parse_gemfile(file_contents, options: {})
58
61
  manifest = Gemnasium::Parser.send(:gemfile, file_contents)
59
- parse_ruby_manifest(manifest)
62
+ parse_ruby_manifest(manifest, options.fetch(:filename, nil))
60
63
  end
61
64
 
62
- def self.parse_gemspec(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
65
+ def self.parse_gemspec(file_contents, options: {})
63
66
  manifest = Gemnasium::Parser.send(:gemspec, file_contents)
64
- parse_ruby_manifest(manifest)
67
+ parse_ruby_manifest(manifest, options.fetch(:filename, nil))
65
68
  end
66
69
 
67
- def self.parse_bundler(file_contents)
70
+ def self.parse_bundler(file_contents, source = nil)
68
71
  bundled_with_index = file_contents.lines(chomp: true).find_index { |line| line.match(BUNDLED_WITH) }
69
72
  version = file_contents.lines(chomp: true).fetch(bundled_with_index + 1)&.strip
70
73
 
@@ -74,6 +77,7 @@ module Bibliothecary
74
77
  name: "bundler",
75
78
  requirement: version,
76
79
  type: "runtime",
80
+ source: source
77
81
  )
78
82
  end
79
83
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "yaml"
2
4
 
3
5
  module Bibliothecary
@@ -20,23 +22,24 @@ module Bibliothecary
20
22
 
21
23
  add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
22
24
 
23
- def self.parse_yaml_lockfile(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
25
+ def self.parse_yaml_lockfile(file_contents, options: {})
24
26
  manifest = YAML.load file_contents
25
- map_dependencies(manifest, "shards", "runtime")
27
+ map_dependencies(manifest, "shards", "runtime", options.fetch(:filename, nil))
26
28
  end
27
29
 
28
- def self.parse_yaml_manifest(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
30
+ def self.parse_yaml_manifest(file_contents, options: {})
29
31
  manifest = YAML.load file_contents
30
- map_dependencies(manifest, "dependencies", "runtime") +
31
- map_dependencies(manifest, "development_dependencies", "runtime")
32
+ map_dependencies(manifest, "dependencies", "runtime", options.fetch(:filename, nil)) +
33
+ map_dependencies(manifest, "development_dependencies", "runtime", options.fetch(:filename, nil))
32
34
  end
33
35
 
34
- def self.map_dependencies(hash, key, type)
35
- hash.fetch(key,[]).map do |name, requirement|
36
+ def self.map_dependencies(hash, key, type, source = nil)
37
+ hash.fetch(key, []).map do |name, requirement|
36
38
  Dependency.new(
37
39
  name: name,
38
40
  requirement: requirement["version"],
39
41
  type: type,
42
+ source: source
40
43
  )
41
44
  end
42
45
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  class PurlUtil
3
5
  # If a purl type (key) exists, it will be used in a manifest for
@@ -13,14 +15,10 @@ module Bibliothecary
13
15
  "conda" => :conda,
14
16
  "cran" => :cran,
15
17
  "gem" => :rubygems,
16
- "hackage" => :hackage,
17
- "hex" => :hex,
18
18
  "nuget" => :nuget,
19
19
  "pypi" => :pypi,
20
- "swift" => :swift_pm,
21
20
  }.freeze
22
21
 
23
-
24
22
  # @param purl [PackageURL]
25
23
  # @return [String] The properly namespaced package name
26
24
  def self.full_name(purl)
@@ -1,17 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  class RelatedFilesInfo
3
- attr_reader :path
4
- attr_reader :platform
5
- attr_reader :manifests
6
- attr_reader :lockfiles
5
+ attr_reader :path, :platform, :manifests, :lockfiles
7
6
 
8
7
  # Create a set of RelatedFilesInfo for the provided file_infos,
9
- # where each RelatedFilesInfo contains all the file_infos
8
+ # where each RelatedFilesInfo contains all the file_infos
10
9
  def self.create_from_file_infos(file_infos)
11
10
  returns = []
12
11
 
13
12
  file_infos_by_directory = file_infos.group_by { |info| File.dirname(info.relative_path) }
14
- file_infos_by_directory.values.each do |file_infos_for_path|
13
+ file_infos_by_directory.each_value do |file_infos_for_path|
15
14
  groupable, ungroupable = file_infos_for_path.partition(&:groupable?)
16
15
 
17
16
  # add ungroupable ones as separate RFIs
@@ -19,9 +18,9 @@ module Bibliothecary
19
18
  returns.append(RelatedFilesInfo.new([file_info]))
20
19
  end
21
20
 
22
- file_infos_by_directory_by_package_manager = groupable.group_by { |info| info.package_manager}
21
+ file_infos_by_directory_by_package_manager = groupable.group_by(&:package_manager)
23
22
 
24
- file_infos_by_directory_by_package_manager.values.each do |file_infos_in_directory_for_package_manager|
23
+ file_infos_by_directory_by_package_manager.each_value do |file_infos_in_directory_for_package_manager|
25
24
  returns.append(RelatedFilesInfo.new(file_infos_in_directory_for_package_manager))
26
25
  end
27
26
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  class Runner
3
5
  class MultiManifestFilter
@@ -11,8 +13,8 @@ module Bibliothecary
11
13
  # @return [Boolean] True if we should skip processing
12
14
  def skip?
13
15
  !@file_analysis ||
14
- !@file_analysis[:dependencies] ||
15
- @file_analysis[:dependencies].empty?
16
+ !@file_analysis[:dependencies] ||
17
+ @file_analysis[:dependencies].empty?
16
18
  end
17
19
  end
18
20
 
@@ -80,7 +82,7 @@ module Bibliothecary
80
82
  end
81
83
 
82
84
  def partition_file_entries!
83
- @single_file_entries, @multiple_file_entries = files_to_check.partition { |_file, count| count == 1 }
85
+ @single_file_entries, @multiple_file_entries = files_to_check.partition { |_file, count| count == 1 }
84
86
 
85
87
  @single_file_entries = @single_file_entries.map(&:first)
86
88
  @multiple_file_entries = @multiple_file_entries.map(&:first)
@@ -88,4 +90,3 @@ module Bibliothecary
88
90
  end
89
91
  end
90
92
  end
91
-
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
4
  # A class that allows bibliothecary to run with multiple configurations at once, rather than with one global.
3
5
  # A runner is created every time a file is targeted to be parsed. Don't call
@@ -24,8 +26,8 @@ module Bibliothecary
24
26
  analyses = analyses.flatten.compact
25
27
 
26
28
  info_list.select { |info| info.package_manager.nil? }.each do |info|
27
- analyses.push(Bibliothecary::Analyser::create_error_analysis("unknown", info.relative_path, "unknown",
28
- "No parser for this file type"))
29
+ analyses.push(Bibliothecary::Analyser.create_error_analysis("unknown", info.relative_path, "unknown",
30
+ "No parser for this file type"))
29
31
  end
30
32
 
31
33
  analyses
@@ -34,16 +36,16 @@ module Bibliothecary
34
36
 
35
37
  # deprecated; use load_file_info_list.
36
38
  def load_file_list(path)
37
- load_file_info_list(path).map { |info| info.full_path }
39
+ load_file_info_list(path).map(&:full_path)
38
40
  end
39
41
 
40
42
  def applicable_package_managers(info)
41
43
  managers = package_managers.select { |pm| pm.match_info?(info) }
42
- managers.length > 0 ? managers : [nil]
44
+ managers.empty? ? [nil] : managers
43
45
  end
44
46
 
45
47
  def package_managers
46
- Bibliothecary::Parsers.constants.map{|c| Bibliothecary::Parsers.const_get(c) }.sort_by{|c| c.to_s.downcase }
48
+ Bibliothecary::Parsers.constants.map { |c| Bibliothecary::Parsers.const_get(c) }.sort_by { |c| c.to_s.downcase }
47
49
  end
48
50
 
49
51
  # Parses an array of format [{file_path: "", contents: ""},] to match
@@ -130,13 +132,13 @@ module Bibliothecary
130
132
  # because this API is used by libraries.io and we don't want to
131
133
  # download all .xml files from GitHub.
132
134
  def identify_manifests(file_list)
133
- ignored_dirs_with_slash = ignored_dirs.map { |d| if d.end_with?("/") then d else d + "/" end }
135
+ ignored_dirs_with_slash = ignored_dirs.map { |d| d.end_with?("/") ? d : "#{d}/" }
134
136
  allowed_file_list = file_list.reject do |f|
135
137
  ignored_dirs.include?(f) || f.start_with?(*ignored_dirs_with_slash)
136
138
  end
137
- allowed_file_list = allowed_file_list.reject{|f| ignored_files.include?(f)}
139
+ allowed_file_list = allowed_file_list.reject { |f| ignored_files.include?(f) }
138
140
  package_managers.map do |pm|
139
- allowed_file_list.select do |file_path|
141
+ allowed_file_list.select do |file_path| # rubocop:disable Style/SelectByRegexp (this is a rubocop false positive, match? is a custom method)
140
142
  # this is a call to match? without file contents, which will skip
141
143
  # ambiguous filenames that are only possibly a manifest
142
144
  pm.match?(file_path)
@@ -159,7 +161,7 @@ module Bibliothecary
159
161
  # This means we're likely analyzing these files twice in processing,
160
162
  # but we need that accurate package manager information.
161
163
  def filter_multi_manifest_entries(path, related_files_info_entries)
162
- MultiManifestFilter.new(path: path, related_files_info_entries: related_files_info_entries , runner: self).results
164
+ MultiManifestFilter.new(path: path, related_files_info_entries: related_files_info_entries, runner: self).results
163
165
  end
164
166
 
165
167
  private
@@ -178,4 +180,4 @@ module Bibliothecary
178
180
  end
179
181
  end
180
182
 
181
- require_relative "./runner/multi_manifest_filter.rb"
183
+ require_relative "runner/multi_manifest_filter"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bibliothecary
2
- VERSION = "11.0.1"
4
+ VERSION = "12.1.0"
3
5
  end
data/lib/bibliothecary.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bibliothecary/version"
2
4
  require "bibliothecary/dependency"
3
5
  require "bibliothecary/analyser"
@@ -10,16 +12,16 @@ require "bibliothecary/purl_util"
10
12
  require "find"
11
13
  require "tomlrb"
12
14
 
13
- Dir[File.expand_path("../bibliothecary/multi_parsers/*.rb", __FILE__)].each do |file|
15
+ Dir[File.expand_path("bibliothecary/multi_parsers/*.rb", __dir__)].each do |file|
14
16
  require file
15
17
  end
16
- Dir[File.expand_path("../bibliothecary/parsers/*.rb", __FILE__)].each do |file|
18
+ Dir[File.expand_path("bibliothecary/parsers/*.rb", __dir__)].each do |file|
17
19
  require file
18
20
  end
19
21
 
20
22
  module Bibliothecary
21
- VERSION_OPERATORS = /[~^<>*"]/.freeze
22
- INVALID_UTF8_ERROR_REGEXP = /invalid byte sequence/.freeze
23
+ VERSION_OPERATORS = /[~^<>*"]/
24
+ INVALID_UTF8_ERROR_REGEXP = /invalid byte sequence/
23
25
 
24
26
  def self.analyse(path, ignore_unparseable_files: true)
25
27
  runner.analyse(path, ignore_unparseable_files: ignore_unparseable_files)
@@ -86,6 +88,7 @@ module Bibliothecary
86
88
  rescue ArgumentError => e
87
89
  # Bibliothecary doesn't need to analyze non-UTF8 files like binary files, so just return blank.
88
90
  return "" if e.message.match?(INVALID_UTF8_ERROR_REGEXP)
91
+
89
92
  raise e
90
93
  end
91
94
 
data/lib/sdl_parser.rb CHANGED
@@ -1,23 +1,28 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "sdl4r"
2
4
 
3
5
  class SdlParser
4
6
  attr_reader :contents, :type
5
- def initialize(type, contents)
7
+
8
+ def initialize(type, contents, source = nil)
6
9
  @contents = contents
7
10
  @type = type || "runtime"
11
+ @source = source
8
12
  end
9
13
 
10
14
  def dependencies
11
15
  parse.children("dependency").inject([]) do |deps, dep|
12
16
  deps.push(Bibliothecary::Dependency.new(
13
- name: dep.value,
14
- requirement: dep.attribute("version") || ">= 0",
15
- type: type,
16
- ))
17
+ name: dep.value,
18
+ requirement: dep.attribute("version") || ">= 0",
19
+ type: type,
20
+ source: @source
21
+ ))
17
22
  end.uniq
18
23
  end
19
24
 
20
25
  def parse
21
- SDL4R::read(contents)
26
+ SDL4R.read(contents)
22
27
  end
23
28
  end