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
  require "ox"
2
4
 
3
5
  # Known shortcomings and unimplemented Maven features:
@@ -26,7 +28,7 @@ module Bibliothecary
26
28
 
27
29
  # Builtin methods: https://docs.gradle.org/current/userguide/java_plugin.html#tab:configurations
28
30
  # Deprecated methods: https://docs.gradle.org/current/userguide/upgrading_version_6.html#sec:configuration_removal
29
- GRADLE_DEPENDENCY_METHODS = %w(api compile compileClasspath compileOnly compileOnlyApi implementation runtime runtimeClasspath runtimeOnly testCompile testCompileOnly testImplementation testRuntime testRuntimeOnly)
31
+ GRADLE_DEPENDENCY_METHODS = %w[api compile compileClasspath compileOnly compileOnlyApi implementation runtime runtimeClasspath runtimeOnly testCompile testCompileOnly testImplementation testRuntime testRuntimeOnly].freeze
30
32
 
31
33
  # Intentionally overly-simplified regexes to scrape deps from build.gradle (Groovy) and build.gradle.kts (Kotlin) files.
32
34
  # To be truly useful bibliothecary would need full Groovy / Kotlin parsers that speaks Gradle,
@@ -34,7 +36,7 @@ module Bibliothecary
34
36
  GRADLE_VERSION_REGEXP = /[\w.-]+/ # e.g. '1.2.3'
35
37
  GRADLE_VAR_INTERPOLATION_REGEXP = /\$\w+/ # e.g. '$myVersion'
36
38
  GRADLE_CODE_INTERPOLATION_REGEXP = /\$\{.*\}/ # e.g. '${my-project-settings["version"]}'
37
- GRADLE_GAV_REGEXP = /([\w.-]+)\:([\w.-]+)(?:\:(#{GRADLE_VERSION_REGEXP}|#{GRADLE_VAR_INTERPOLATION_REGEXP}|#{GRADLE_CODE_INTERPOLATION_REGEXP}))?/ # e.g. "group:artifactId:1.2.3"
39
+ GRADLE_GAV_REGEXP = /([\w.-]+):([\w.-]+)(?::(#{GRADLE_VERSION_REGEXP}|#{GRADLE_VAR_INTERPOLATION_REGEXP}|#{GRADLE_CODE_INTERPOLATION_REGEXP}))?/ # e.g. "group:artifactId:1.2.3"
38
40
  GRADLE_GROOVY_SIMPLE_REGEXP = /(#{GRADLE_DEPENDENCY_METHODS.join('|')})\s*\(?\s*['"]#{GRADLE_GAV_REGEXP}['"]/m
39
41
  GRADLE_KOTLIN_SIMPLE_REGEXP = /(#{GRADLE_DEPENDENCY_METHODS.join('|')})\s*\(\s*"#{GRADLE_GAV_REGEXP}"/m
40
42
 
@@ -56,7 +58,6 @@ module Bibliothecary
56
58
  # e.g. "[info] "
57
59
  SBT_IGNORE_REGEXP = /^\[info\]\s*$/
58
60
 
59
-
60
61
  # Copied from the "strings-ansi" gem, because it seems abandoned: https://github.com/piotrmurach/strings-ansi/pull/2
61
62
  # From: https://github.com/piotrmurach/strings-ansi/blob/35d0c9430cf0a8022dc12bdab005bce296cb9f00/lib/strings/ansi.rb#L14-L29
62
63
  # License: MIT
@@ -75,8 +76,8 @@ module Bibliothecary
75
76
  |
76
77
  \]8;[^;]*;.*?(\033\\|\07) # hyperlink
77
78
  ))
78
- }x.freeze
79
-
79
+ }x
80
+
80
81
  def self.mapping
81
82
  {
82
83
  match_filename("ivy.xml", case_insensitive: true) => {
@@ -123,7 +124,7 @@ module Bibliothecary
123
124
  add_multi_parser(Bibliothecary::MultiParsers::Spdx)
124
125
  add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
125
126
 
126
- def self.parse_ivy_manifest(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
127
+ def self.parse_ivy_manifest(file_contents, options: {})
127
128
  manifest = Ox.parse file_contents
128
129
  manifest.dependencies.locate("dependency").map do |dependency|
129
130
  attrs = dependency.attributes
@@ -131,6 +132,7 @@ module Bibliothecary
131
132
  name: "#{attrs[:org]}:#{attrs[:name]}",
132
133
  requirement: attrs[:rev],
133
134
  type: "runtime",
135
+ source: options.fetch(:filename, nil)
134
136
  )
135
137
  end
136
138
  end
@@ -138,7 +140,7 @@ module Bibliothecary
138
140
  def self.ivy_report?(file_contents)
139
141
  doc = Ox.parse file_contents
140
142
  root = doc&.locate("ivy-report")&.first
141
- return !root.nil?
143
+ !root.nil?
142
144
  rescue Exception # rubocop:disable Lint/RescueException
143
145
  # We rescue exception here since native libs can throw a non-StandardError
144
146
  # We don't want to throw errors during the matching phase, only during
@@ -146,12 +148,14 @@ module Bibliothecary
146
148
  false
147
149
  end
148
150
 
149
- def self.parse_ivy_report(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
151
+ def self.parse_ivy_report(file_contents, options: {})
150
152
  doc = Ox.parse file_contents
151
153
  root = doc.locate("ivy-report").first
152
154
  raise "ivy-report document does not have ivy-report at the root" if root.nil?
155
+
153
156
  info = doc.locate("ivy-report/info").first
154
157
  raise "ivy-report document lacks <info> element" if info.nil?
158
+
155
159
  type = info.attributes[:conf]
156
160
  type = "unknown" if type.nil?
157
161
  modules = doc.locate("ivy-report/dependencies/module")
@@ -159,19 +163,20 @@ module Bibliothecary
159
163
  attrs = mod.attributes
160
164
  org = attrs[:organisation]
161
165
  name = attrs[:name]
162
- version = mod.locate("revision").first&.attributes[:name]
166
+ version = mod.locate("revision").first&.attributes&.[](:name)
163
167
 
164
- next nil if org.nil? or name.nil? or version.nil?
168
+ next nil if org.nil? || name.nil? || version.nil?
165
169
 
166
170
  Dependency.new(
167
171
  name: "#{org}:#{name}",
168
172
  requirement: version,
169
173
  type: type,
174
+ source: options.fetch(:filename, nil)
170
175
  )
171
176
  end.compact
172
177
  end
173
178
 
174
- def self.parse_gradle_resolved(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
179
+ def self.parse_gradle_resolved(file_contents, options: {})
175
180
  current_type = nil
176
181
 
177
182
  file_contents.split("\n").map do |line|
@@ -190,7 +195,7 @@ module Bibliothecary
190
195
  next if project_match[1].nil?
191
196
 
192
197
  # project names can have colons (e.g. for gradle projects in subfolders), which breaks maven artifact naming assumptions, so just replace them with hyphens.
193
- project_name = project_match[1].gsub(/:/, "-")
198
+ project_name = project_match[1].gsub(":", "-")
194
199
  line = line.sub(GRADLE_PROJECT_REGEXP, "internal:#{project_name}:1.0.0")
195
200
  end
196
201
 
@@ -209,20 +214,22 @@ module Bibliothecary
209
214
  if dep.count == 6
210
215
  # get name from renamed package resolution "org:name:version -> renamed_org:name:version"
211
216
  Dependency.new(
212
- original_name: dep[0,2].join(":"),
217
+ original_name: dep[0, 2].join(":"),
213
218
  original_requirement: dep[2],
214
219
  name: dep[-3..-2].join(":"),
215
220
  requirement: dep[-1],
216
221
  type: current_type,
222
+ source: options.fetch(:filename, nil)
217
223
  )
218
224
  elsif dep.count == 5
219
225
  # get name from renamed package resolution "org:name -> renamed_org:name:version"
220
226
  Dependency.new(
221
- original_name: dep[0,2].join(":"),
227
+ original_name: dep[0, 2].join(":"),
222
228
  original_requirement: "*",
223
229
  name: dep[-3..-2].join(":"),
224
230
  requirement: dep[-1],
225
231
  type: current_type,
232
+ source: options.fetch(:filename, nil)
226
233
  )
227
234
  else
228
235
  # get name from version conflict resolution ("org:name:version -> version") and no-resolution ("org:name:version")
@@ -230,6 +237,7 @@ module Bibliothecary
230
237
  name: dep[0..1].join(":"),
231
238
  requirement: dep[-1],
232
239
  type: current_type,
240
+ source: options.fetch(:filename, nil)
233
241
  )
234
242
  end
235
243
  end
@@ -237,16 +245,16 @@ module Bibliothecary
237
245
  .uniq { |item| [item.name, item.requirement, item.type, item.original_name, item.original_requirement] }
238
246
  end
239
247
 
240
- def self.parse_maven_resolved(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
248
+ def self.parse_maven_resolved(file_contents, options: {})
241
249
  file_contents
242
250
  .gsub(ANSI_MATCHER, "")
243
251
  .split("\n")
244
- .map(&method(:parse_resolved_dep_line))
252
+ .map { |line| parse_resolved_dep_line(line, options: options) }
245
253
  .compact
246
254
  .uniq
247
255
  end
248
256
 
249
- def self.parse_maven_tree(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
257
+ def self.parse_maven_tree(file_contents, options: {})
250
258
  captures = file_contents
251
259
  .gsub(ANSI_MATCHER, "")
252
260
  .gsub(/\r\n?/, "\n")
@@ -267,68 +275,71 @@ module Bibliothecary
267
275
  name: parts[0..1].join(":"),
268
276
  requirement: version,
269
277
  type: type,
278
+ source: options.fetch(:filename, nil)
270
279
  )
271
280
  end
272
281
 
273
282
  # First dep line will be the package itself (unless we're only analyzing a single line)
274
283
  package = deps[0]
275
- deps.size < 2 ? deps : deps[1..-1].reject { |d| d.name == package.name && d.requirement == package.requirement }
284
+ deps.size < 2 ? deps : deps[1..].reject { |d| d.name == package.name && d.requirement == package.requirement }
276
285
  end
277
286
 
278
- def self.parse_resolved_dep_line(line)
287
+ def self.parse_resolved_dep_line(line, options: {})
279
288
  # filter out anything that doesn't look like a
280
289
  # resolved dep line
281
290
  return unless line[/ .*:[^-]+-- /]
282
291
 
283
292
  dep_parts = line.strip.split(":")
284
293
  return unless dep_parts.length == 5
294
+
285
295
  # org.springframework.boot:spring-boot-starter-web:jar:2.0.3.RELEASE:compile -- module spring.boot.starter.web [auto]
286
296
  Dependency.new(
287
297
  name: dep_parts[0, 2].join(":"),
288
298
  requirement: dep_parts[3],
289
299
  type: dep_parts[4].split("--").first.strip,
300
+ source: options.fetch(:filename, nil)
290
301
  )
291
302
  end
292
303
 
293
304
  def self.parse_standalone_pom_manifest(file_contents, options: {})
294
- parse_pom_manifest(file_contents, {}, options: options)
305
+ parse_pom_manifest(file_contents, {}, options:)
295
306
  end
296
307
 
297
- def self.parse_pom_manifest(file_contents, parent_properties = {}, options: {}) # rubocop:disable Lint/UnusedMethodArgument
298
- parse_pom_manifests([file_contents], parent_properties)
308
+ def self.parse_pom_manifest(file_contents, parent_properties = {}, options: {})
309
+ parse_pom_manifests([file_contents], parent_properties, options.fetch(:filename, nil))
299
310
  end
300
311
 
301
312
  # @param files [Array<String>] Ordered array of strings containing the
302
313
  # pom.xml bodies. The first element should be the child file.
303
314
  # @param merged_properties [Hash]
304
- def self.parse_pom_manifests(files, merged_properties)
315
+ def self.parse_pom_manifests(files, merged_properties, source = nil)
305
316
  documents = files.map do |file|
306
317
  doc = Ox.parse(file)
307
318
  doc.respond_to?("project") ? doc.project : doc
308
319
  end
309
320
 
310
- mergedDependencyManagements = {}
321
+ merged_dependency_managements = {}
311
322
  documents.each do |document|
312
- document.locate("dependencyManagement/dependencies/dependency").each do |dep|
313
- groupId = extract_pom_dep_info(document, dep, "groupId", merged_properties)
314
- artifactId = extract_pom_dep_info(document, dep, "artifactId", merged_properties)
315
- key = "#{groupId}:#{artifactId}"
316
- mergedDependencyManagements[key] ||=
317
- {
318
- groupId: groupId,
319
- artifactId: artifactId,
320
- version: extract_pom_dep_info(document, dep, "version", merged_properties),
321
- scope: extract_pom_dep_info(document, dep, "scope", merged_properties),
322
- }
323
- end
323
+ document.locate("dependencyManagement/dependencies/dependency").each do |dep|
324
+ group_id = extract_pom_dep_info(document, dep, "groupId", merged_properties)
325
+ artifact_id = extract_pom_dep_info(document, dep, "artifactId", merged_properties)
326
+ key = "#{group_id}:#{artifact_id}"
327
+ merged_dependency_managements[key] ||=
328
+ {
329
+ groupId: group_id,
330
+ artifactId: artifact_id,
331
+ version: extract_pom_dep_info(document, dep, "version", merged_properties),
332
+ scope: extract_pom_dep_info(document, dep, "scope", merged_properties),
333
+ }
334
+ end
324
335
  end
325
336
 
326
337
  dep_hashes = {}
327
338
  documents.each do |document|
328
339
  document.locate("dependencies/dependency").each do |dep|
329
- groupId = extract_pom_dep_info(document, dep, "groupId", merged_properties)
330
- artifactId = extract_pom_dep_info(document, dep, "artifactId", merged_properties)
331
- key = "#{groupId}:#{artifactId}"
340
+ group_id = extract_pom_dep_info(document, dep, "groupId", merged_properties)
341
+ artifact_id = extract_pom_dep_info(document, dep, "artifactId", merged_properties)
342
+ key = "#{group_id}:#{artifact_id}"
332
343
  unless dep_hashes.key?(key)
333
344
  dep_hashes[key] = {
334
345
  name: key,
@@ -353,41 +364,44 @@ module Bibliothecary
353
364
  # Anything that wasn't covered by a dependency version, get from the
354
365
  # dependencyManagements
355
366
  dep_hashes.each do |key, dep_hash|
356
- if (dependencyManagement = mergedDependencyManagements[key])
357
- dep_hash[:requirement] ||= dependencyManagement[:version]
358
- dep_hash[:type] ||= dependencyManagement[:scope]
367
+ if (dependency_management = merged_dependency_managements[key])
368
+ dep_hash[:requirement] ||= dependency_management[:version]
369
+ dep_hash[:type] ||= dependency_management[:scope]
359
370
  end
360
371
 
361
372
  dep_hash[:type] ||= "runtime"
373
+ dep_hash[:source] = source
362
374
  end
363
375
 
364
- dep_hashes.map{|key, dep_hash| Dependency.new(**dep_hash)}
376
+ dep_hashes.map { |_key, dep_hash| Dependency.new(**dep_hash) }
365
377
  end
366
378
 
367
- def self.parse_gradle(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
379
+ def self.parse_gradle(file_contents, options: {})
368
380
  file_contents
369
- .scan(GRADLE_GROOVY_SIMPLE_REGEXP) # match 'implementation "group:artifactId:version"'
370
- .reject { |(_type, group, artifactId, _version)| group.nil? || artifactId.nil? } # remove any matches with missing group/artifactId
371
- .map { |(type, group, artifactId, version)|
381
+ .scan(GRADLE_GROOVY_SIMPLE_REGEXP) # match 'implementation "group:artifactId:version"'
382
+ .reject { |(_type, group, artifact_id, _version)| group.nil? || artifact_id.nil? } # remove any matches with missing group/artifactId
383
+ .map do |(type, group, artifact_id, version)|
372
384
  Dependency.new(
373
- name: [group, artifactId].join(":"),
385
+ name: [group, artifact_id].join(":"),
374
386
  requirement: version,
375
387
  type: type,
388
+ source: options.fetch(:filename, nil)
376
389
  )
377
- }
390
+ end
378
391
  end
379
392
 
380
- def self.parse_gradle_kts(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
393
+ def self.parse_gradle_kts(file_contents, options: {})
381
394
  file_contents
382
- .scan(GRADLE_KOTLIN_SIMPLE_REGEXP) # match 'implementation("group:artifactId:version")'
383
- .reject { |(_type, group, artifactId, _version)| group.nil? || artifactId.nil? } # remove any matches with missing group/artifactId
384
- .map { |(type, group, artifactId, version)|
395
+ .scan(GRADLE_KOTLIN_SIMPLE_REGEXP) # match 'implementation("group:artifactId:version")'
396
+ .reject { |(_type, group, artifact_id, _version)| group.nil? || artifact_id.nil? } # remove any matches with missing group/artifactId
397
+ .map do |(type, group, artifact_id, version)|
385
398
  Dependency.new(
386
- name: [group, artifactId].join(":"),
399
+ name: [group, artifact_id].join(":"),
387
400
  requirement: version,
388
401
  type: type,
402
+ source: options.fetch(:filename, nil)
389
403
  )
390
- }
404
+ end
391
405
  end
392
406
 
393
407
  def self.gradle_dependency_name(group, name)
@@ -420,11 +434,9 @@ module Bibliothecary
420
434
  # whitespace in dependency tags should be ignored
421
435
  value = value&.strip
422
436
  match = value&.match(MAVEN_PROPERTY_REGEXP)
423
- if match
424
- return extract_property(xml, match[1], value, parent_properties)
425
- else
426
- return value
427
- end
437
+ return extract_property(xml, match[1], value, parent_properties) if match
438
+
439
+ value
428
440
  end
429
441
 
430
442
  def self.replace_value_with_prop(original_value, property_value, property_name)
@@ -434,17 +446,16 @@ module Bibliothecary
434
446
  def self.extract_property(xml, property_name, value, parent_properties = {}, depth = 0)
435
447
  prop_value = property_value(xml, property_name, parent_properties)
436
448
  return value unless prop_value
449
+
437
450
  # don't resolve more than 5 levels deep to avoid potential circular references
438
451
 
439
452
  resolved_value = replace_value_with_prop(value, prop_value, property_name)
440
453
  # check to see if we just resolved to another property name
441
454
  match = resolved_value.match(MAVEN_PROPERTY_REGEXP)
442
- if match && depth < MAX_DEPTH
443
- depth += 1
444
- return extract_property(xml, match[1], resolved_value, parent_properties, depth)
445
- else
446
- return resolved_value
447
- end
455
+ return resolved_value unless match && depth < MAX_DEPTH
456
+
457
+ depth += 1
458
+ extract_property(xml, match[1], resolved_value, parent_properties, depth)
448
459
  end
449
460
 
450
461
  def self.property_value(xml, property_name, parent_properties)
@@ -453,9 +464,9 @@ module Bibliothecary
453
464
  non_prop_name = property_name.gsub(".", "/").gsub("project/", "")
454
465
 
455
466
  prop_field = xml.properties.locate(property_name).first if xml.respond_to?("properties")
456
- parent_prop = parent_properties[property_name] || # e.g. "${foo}"
457
- parent_properties[property_name.sub(/^project\./, "")] || # e.g. "${project.foo}"
458
- parent_properties[property_name.sub(/^project\.parent\./, "")] # e.g. "${project.parent.foo}"
467
+ parent_prop = parent_properties[property_name] || # e.g. "${foo}"
468
+ parent_properties[property_name.sub(/^project\./, "")] || # e.g. "${project.foo}"
469
+ parent_properties[property_name.sub(/^project\.parent\./, "")] # e.g. "${project.parent.foo}"
459
470
 
460
471
  if prop_field
461
472
  prop_field.nodes.first
@@ -472,7 +483,7 @@ module Bibliothecary
472
483
  end
473
484
  end
474
485
 
475
- def self.parse_sbt_update_full(file_contents, options: {}) # rubocop:disable Lint/UnusedMethodArgument
486
+ def self.parse_sbt_update_full(file_contents, options: {})
476
487
  all_deps = []
477
488
  lines = file_contents.split("\n")
478
489
  while lines.any?
@@ -480,6 +491,7 @@ module Bibliothecary
480
491
 
481
492
  type_match = SBT_TYPE_REGEXP.match(line)
482
493
  next unless type_match
494
+
483
495
  type = type_match.captures[0]
484
496
 
485
497
  deps = parse_sbt_deps(type, lines)
@@ -487,8 +499,8 @@ module Bibliothecary
487
499
  end
488
500
 
489
501
  # strip out evicted dependencies
490
- all_deps.select! do |dep|
491
- dep[:fields]["evicted"] != "true"
502
+ all_deps.reject! do |dep|
503
+ dep[:fields]["evicted"] == "true"
492
504
  end
493
505
 
494
506
  # in the future, we could use "callers" in the fields to
@@ -498,19 +510,23 @@ module Bibliothecary
498
510
 
499
511
  # clean out any duplicates (I'm pretty sure sbt will have done this for
500
512
  # us so this is paranoia, basically)
501
- squished = all_deps.compact.uniq {|item| [item[:name], item[:requirement], item[:type]]}
513
+ squished = all_deps.compact.uniq { |item| [item[:name], item[:requirement], item[:type]] }
502
514
 
503
515
  # get rid of the fields
504
516
  squished.each do |dep|
505
517
  dep.delete(:fields)
506
518
  end
507
519
 
508
- return squished.map { |dep_kvs| Dependency.new(**dep_kvs) }
520
+ squished.map do |dep_kvs|
521
+ Dependency.new(
522
+ **dep_kvs, source: options.fetch(:filename, nil)
523
+ )
524
+ end
509
525
  end
510
526
 
511
527
  def self.parse_sbt_deps(type, lines)
512
528
  deps = []
513
- while lines.any? and not SBT_TYPE_REGEXP.match(lines[0])
529
+ while lines.any? && !SBT_TYPE_REGEXP.match(lines[0])
514
530
  line = lines.shift
515
531
 
516
532
  next if SBT_IGNORE_REGEXP.match(line)
@@ -530,7 +546,7 @@ module Bibliothecary
530
546
 
531
547
  def self.parse_sbt_versions(type, name, lines)
532
548
  versions = []
533
- while lines.any? and not SBT_TYPE_REGEXP.match(lines[0])
549
+ while lines.any? && !SBT_TYPE_REGEXP.match(lines[0])
534
550
  line = lines.shift
535
551
 
536
552
  version_match = SBT_VERSION_REGEXP.match(line)
@@ -547,7 +563,7 @@ module Bibliothecary
547
563
 
548
564
  def self.parse_sbt_version(type, name, version, lines)
549
565
  fields = {}
550
- while lines.any? and not SBT_TYPE_REGEXP.match(lines[0])
566
+ while lines.any? && !SBT_TYPE_REGEXP.match(lines[0])
551
567
  line = lines.shift
552
568
 
553
569
  field_match = SBT_FIELD_REGEXP.match(line)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "json"
2
4
 
3
5
  module Bibliothecary