bibliothecary 11.0.1 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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