bibliothecary 12.1.9 → 12.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38a42d90ccaf9bb96b2be9c736b5559a3c3fa81286bbea8c404a33f3a4cb89be
4
- data.tar.gz: 36b09c415f331863ba6ab1a82eff0a78cc759b01ae0bad339c9e6cc80c6789c1
3
+ metadata.gz: 37cce0e70366df9eeaaf3d134ba139335359ed2b484ce78c737e8f155d4606b7
4
+ data.tar.gz: b23e369a3077301e8f3078a179f474b3afc83af926e445370988d170d998ae19
5
5
  SHA512:
6
- metadata.gz: 769fe185aedefda6b8c95c6c66700a070a4b7448a0ee452c8b1cbaf1507e3443945f6bef6ff7ead4e17458c43f81afbc86b2e0f592bb779d6f603b379a09fed6
7
- data.tar.gz: 05d1709b1cb6410ff3250ea2472cefa2eec4f7dff5eca9864d9eb5837f107ec6aaf3fc629f6ba476e49b382e9a05951fdb25abbe04099d1b95124219891bb149
6
+ metadata.gz: b46141115f05919f3d4f16b0e1cf03a0baf0060e972e5ec044c791c2f0124e0e0bcc34e87eec715298d207252cfbf8960c68edfc533ff5ee7290ad358af76ccb
7
+ data.tar.gz: a302ac6a16b775df78f2eef640feac02e624b2be6b8165f75492922c34e1c218de449bdfb6e3992e7f8b3941cf2d42c6457eb4d2025266b5abec05f553219902
data/CHANGELOG.md CHANGED
@@ -13,6 +13,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13
13
 
14
14
  ### Removed
15
15
 
16
+ ## [12.2.0] - 2025-05-30
17
+
18
+ ### Added
19
+
20
+ - Maven parser support for maven-dependency-tree.dot file.
21
+
22
+ ### Changed
23
+
24
+ ### Removed
25
+
26
+ ## [12.1.10] - 2025-05-23
27
+
28
+ ### Added
29
+
30
+ ### Changed
31
+
32
+ - Normalize package names in Poetry manifests, storing the original in
33
+ Dependency#original_name if it differs. This is because Poetry normalizes/canoncalizes
34
+ names in its lockfile according to PyPa's rules, but doesn't provide the original name.
35
+ Storing the original_name will provide a connection from manifest to lockfile.
36
+
37
+ ### Removed
38
+
16
39
  ## [12.1.9] - 2025-05-16
17
40
 
18
41
  ### Added
@@ -11,6 +11,10 @@ module Bibliothecary
11
11
  class Maven
12
12
  include Bibliothecary::Analyser
13
13
 
14
+ # Matches digraph contents from the Maven dependency tree .dot file format.
15
+ MAVEN_DOT_PROJECT_REGEXP = /digraph\s+"([^\"]+)"\s+{/
16
+ MAVEN_DOT_RELATIONSHIP_REGEXP = /"([^\"]+)"\s+->\s+"([^\"]+)"/
17
+
14
18
  # e.g. "annotationProcessor - Annotation processors and their dependencies for source set 'main'."
15
19
  GRADLE_TYPE_REGEXP = /^(\w+)/
16
20
 
@@ -113,10 +117,19 @@ module Bibliothecary
113
117
  kind: "lockfile",
114
118
  parser: :parse_sbt_update_full,
115
119
  },
120
+ # maven-dependency-tree.txt is the output of `mvn dependency:tree` as a single command.
121
+ # The tree lines contain "[INFO]" prefix and uses 2-space indentation.
116
122
  match_filename("maven-dependency-tree.txt", case_insensitive: true) => {
117
123
  kind: "lockfile",
118
124
  parser: :parse_maven_tree,
119
125
  },
126
+ # maven-dependency-tree.dot is the output of this command:
127
+ # `mvn dependency:tree -DoutputType=dot -DoutputFile=maven-dependency-tree.dot`
128
+ # It doesn't have the "[INFO]" prefix, and is in graphviz .dot format.
129
+ match_filename("maven-dependency-tree.dot", case_insensitive: true) => {
130
+ kind: "lockfile",
131
+ parser: :parse_maven_tree_dot,
132
+ },
120
133
  }
121
134
  end
122
135
 
@@ -303,23 +316,24 @@ module Bibliothecary
303
316
 
304
317
  raise "found no lines with deps in maven-dependency-tree.txt" if items.empty?
305
318
 
306
- projects = {}
319
+ projects_to_exclude = {}
307
320
 
308
321
  if keep_subprojects
309
322
  # traditional behavior: we only exclude the root project, and only if we parsed multiple lines
310
323
  (root_name, root_version, _root_type) = parse_maven_tree_dependency(items.shift[1])
311
324
  unless items.empty?
312
- projects[root_name] = Set.new
313
- projects[root_name].add(root_version)
325
+ projects_to_exclude[root_name] = Set.new
326
+ projects_to_exclude[root_name].add(root_version)
314
327
  end
315
328
  end
316
329
 
317
330
  unique_items = items.map do |(depth, item)|
331
+ # new behavior: we exclude root and subprojects (depth 0 items)
318
332
  (name, version, type) = parse_maven_tree_dependency(item)
319
333
  if depth == 0 && !keep_subprojects
320
334
  # record and then remove the depth 0
321
- projects[name] ||= Set.new
322
- projects[name].add(version)
335
+ projects_to_exclude[name] ||= Set.new
336
+ projects_to_exclude[name].add(version)
323
337
  nil
324
338
  else
325
339
  [name, version, type]
@@ -328,7 +342,7 @@ module Bibliothecary
328
342
 
329
343
  unique_items
330
344
  # drop the projects and subprojects
331
- .reject { |(name, version, _type)| projects[name]&.include?(version) }
345
+ .reject { |(name, version, _type)| projects_to_exclude[name]&.include?(version) }
332
346
  .map do |(name, version, type)|
333
347
  Bibliothecary::Dependency.new(
334
348
  name: name,
@@ -339,6 +353,32 @@ module Bibliothecary
339
353
  end
340
354
  end
341
355
 
356
+ def self.parse_maven_tree_dot(file_contents, options: {})
357
+ # Project could be either the root project or a sub-module.
358
+ project = file_contents.match(MAVEN_DOT_PROJECT_REGEXP)[1]
359
+ relationships = file_contents.scan(MAVEN_DOT_RELATIONSHIP_REGEXP)
360
+
361
+ direct_names_to_versions = relationships.each.with_object({}) do |(parent, child), obj|
362
+ next unless parent == project
363
+
364
+ name, version, _type = parse_maven_tree_dependency(child)
365
+ obj[name] ||= Set.new
366
+ obj[name].add(version)
367
+ end
368
+
369
+ relationships.map do |(_parent, child)|
370
+ child_name, child_version, child_type = parse_maven_tree_dependency(child)
371
+
372
+ Dependency.new(
373
+ name: child_name,
374
+ requirement: child_version,
375
+ type: child_type,
376
+ direct: direct_names_to_versions[child_name]&.include?(child_version) || false,
377
+ source: options.fetch(:filename, nil)
378
+ )
379
+ end.uniq
380
+ end
381
+
342
382
  def self.parse_resolved_dep_line(line, options: {})
343
383
  # filter out anything that doesn't look like a
344
384
  # resolved dep line
@@ -119,7 +119,15 @@ module Bibliothecary
119
119
 
120
120
  # We're combining both poetry+PEP621 deps instead of making them mutually exclusive, until we
121
121
  # find a reason not to ingest them both.
122
- deps.uniq
122
+ deps = deps.uniq
123
+
124
+ # Poetry normalizes names in lockfiles but doesn't provide the original, so we need to keep
125
+ # track of the original name so the dep is connected between manifest+lockfile.
126
+ deps.map do |dep|
127
+ normalized_name = normalize_name(dep.name)
128
+ Dependency.new(**dep.to_h, name: normalized_name,
129
+ original_name: normalized_name == dep.name ? nil : dep.name)
130
+ end
123
131
  end
124
132
 
125
133
  def self.parse_conda(file_contents, options: {})
@@ -210,8 +218,12 @@ module Bibliothecary
210
218
  groups = ["runtime"] if groups.empty?
211
219
 
212
220
  groups.each do |group|
221
+ # Poetry lockfiles should already contain normalizated names, but we'll
222
+ # apply it here as well just to be consistent with pyproject.toml parsing.
223
+ normalized_name = normalize_name(package["name"])
213
224
  deps << Dependency.new(
214
- name: package["name"],
225
+ name: normalized_name,
226
+ original_name: normalized_name == package["name"] ? nil : package["name"],
215
227
  requirement: map_requirements(package),
216
228
  type: group,
217
229
  source: options.fetch(:filename, nil)
@@ -332,6 +344,12 @@ module Bibliothecary
332
344
  requirement = "*" if requirement == ""
333
345
  [name, requirement]
334
346
  end
347
+
348
+ # Apply PyPa's name normalization rules to the package name
349
+ # https://packaging.python.org/en/latest/specifications/name-normalization/#name-normalization
350
+ def self.normalize_name(name)
351
+ name.downcase.gsub(/[-_.]+/, "-")
352
+ end
335
353
  end
336
354
  end
337
355
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bibliothecary
4
- VERSION = "12.1.9"
4
+ VERSION = "12.2.0"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bibliothecary
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.1.9
4
+ version: 12.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Nesbitt
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-05-17 00:00:00.000000000 Z
10
+ date: 2025-05-30 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: commander