ecosystems-bibliothecary 15.1.1 → 15.3.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/README.md +189 -124
  4. data/lib/bibliothecary/analyser.rb +4 -0
  5. data/lib/bibliothecary/dependency.rb +6 -1
  6. data/lib/bibliothecary/parsers/actions.rb +4 -0
  7. data/lib/bibliothecary/parsers/alpm.rb +89 -0
  8. data/lib/bibliothecary/parsers/apk.rb +91 -0
  9. data/lib/bibliothecary/parsers/bentoml.rb +5 -1
  10. data/lib/bibliothecary/parsers/bower.rb +5 -0
  11. data/lib/bibliothecary/parsers/cargo.rb +7 -1
  12. data/lib/bibliothecary/parsers/carthage.rb +4 -0
  13. data/lib/bibliothecary/parsers/clojars.rb +5 -0
  14. data/lib/bibliothecary/parsers/cocoapods.rb +33 -1
  15. data/lib/bibliothecary/parsers/cog.rb +5 -1
  16. data/lib/bibliothecary/parsers/conan.rb +4 -0
  17. data/lib/bibliothecary/parsers/conda.rb +6 -0
  18. data/lib/bibliothecary/parsers/cpan.rb +4 -0
  19. data/lib/bibliothecary/parsers/cran.rb +4 -0
  20. data/lib/bibliothecary/parsers/deb.rb +132 -0
  21. data/lib/bibliothecary/parsers/deno.rb +112 -0
  22. data/lib/bibliothecary/parsers/docker.rb +4 -0
  23. data/lib/bibliothecary/parsers/dub.rb +6 -0
  24. data/lib/bibliothecary/parsers/dvc.rb +5 -1
  25. data/lib/bibliothecary/parsers/elm.rb +4 -0
  26. data/lib/bibliothecary/parsers/go.rb +8 -2
  27. data/lib/bibliothecary/parsers/hackage.rb +58 -2
  28. data/lib/bibliothecary/parsers/haxelib.rb +5 -0
  29. data/lib/bibliothecary/parsers/hex.rb +109 -5
  30. data/lib/bibliothecary/parsers/homebrew.rb +4 -0
  31. data/lib/bibliothecary/parsers/julia.rb +55 -0
  32. data/lib/bibliothecary/parsers/luarocks.rb +5 -0
  33. data/lib/bibliothecary/parsers/maven.rb +4 -0
  34. data/lib/bibliothecary/parsers/meteor.rb +5 -0
  35. data/lib/bibliothecary/parsers/mlflow.rb +5 -1
  36. data/lib/bibliothecary/parsers/nimble.rb +5 -0
  37. data/lib/bibliothecary/parsers/nix.rb +205 -0
  38. data/lib/bibliothecary/parsers/npm.rb +84 -11
  39. data/lib/bibliothecary/parsers/nuget.rb +4 -0
  40. data/lib/bibliothecary/parsers/ollama.rb +5 -1
  41. data/lib/bibliothecary/parsers/packagist.rb +32 -31
  42. data/lib/bibliothecary/parsers/pub.rb +4 -0
  43. data/lib/bibliothecary/parsers/pypi.rb +25 -2
  44. data/lib/bibliothecary/parsers/rpm.rb +80 -0
  45. data/lib/bibliothecary/parsers/rubygems.rb +38 -4
  46. data/lib/bibliothecary/parsers/shard.rb +4 -0
  47. data/lib/bibliothecary/parsers/swift_pm.rb +4 -0
  48. data/lib/bibliothecary/parsers/vcpkg.rb +4 -0
  49. data/lib/bibliothecary/version.rb +1 -1
  50. data/lib/bibliothecary.rb +7 -0
  51. metadata +7 -1
@@ -10,6 +10,10 @@ module Bibliothecary
10
10
  # Max depth to recurse into the "dependencies" property of package-lock.json
11
11
  PACKAGE_LOCK_JSON_MAX_DEPTH = 10
12
12
 
13
+ def self.file_patterns
14
+ ["package.json", "package-lock.json", "npm-shrinkwrap.json", "yarn.lock", "pnpm-lock.yaml", "pnpm-workspace.yaml", "bun.lock", "npm-ls.json"]
15
+ end
16
+
13
17
  def self.mapping
14
18
  {
15
19
  match_filename("package.json") => {
@@ -28,6 +32,11 @@ module Bibliothecary
28
32
  kind: "lockfile",
29
33
  parser: :parse_pnpm_lock,
30
34
  },
35
+ match_filename("pnpm-workspace.yaml") => {
36
+ kind: "manifest",
37
+ parser: :parse_pnpm_workspace,
38
+ related_to: ["lockfile"],
39
+ },
31
40
  match_filename("npm-ls.json") => {
32
41
  kind: "lockfile",
33
42
  parser: :parse_ls,
@@ -97,7 +106,8 @@ module Bibliothecary
97
106
  type: dep.fetch("dev", false) || dep.fetch("devOptional", false) ? "development" : "runtime",
98
107
  local: dep.fetch("link", false),
99
108
  source: source,
100
- platform: platform_name
109
+ platform: platform_name,
110
+ integrity: dep["integrity"]
101
111
  )
102
112
  end
103
113
  end
@@ -118,7 +128,8 @@ module Bibliothecary
118
128
  requirement: version,
119
129
  type: type,
120
130
  source: source,
121
- platform: platform_name
131
+ platform: platform_name,
132
+ integrity: requirement["integrity"]
122
133
  )] + child_dependencies
123
134
  end
124
135
  end
@@ -187,7 +198,8 @@ module Bibliothecary
187
198
  type: nil, # yarn.lock doesn't report on the type of dependency
188
199
  local: dep[:requirements]&.first&.start_with?("file:"),
189
200
  source: options.fetch(:filename, nil),
190
- platform: platform_name
201
+ platform: platform_name,
202
+ integrity: dep[:integrity]
191
203
  )
192
204
  end
193
205
  ParserResult.new(dependencies: dependencies)
@@ -228,11 +240,23 @@ module Bibliothecary
228
240
 
229
241
  def self.parse_v2_yarn_lock(contents, source = nil)
230
242
  deps = []
231
- # Match package blocks: "package@npm:req": followed by version: x.y.z
232
- # Examples: "js-tokens@npm:^3.0.0 || ^4.0.0": or "pkg1@npm:req1, pkg2@npm:req2":
233
- contents.scan(/^"([^"]+)":\s*\n\s+version:\s*([^\n]+)/m) do |packages_str, version|
243
+ # Split into blocks by double newlines or by unquoted key lines
244
+ # Each block starts with "package@npm:req": and continues until the next package
245
+ blocks = contents.split(/\n\n+/)
246
+
247
+ blocks.each do |block|
248
+ # Match the package header: "package@npm:...":\n version: ...
249
+ match = block.match(/^"([^"]+)":\s*\n(.+)/m)
250
+ next unless match
251
+
252
+ packages_str = match[1]
253
+ body = match[2]
254
+
255
+ version = body[/version:\s*([^\n]+)/, 1]
256
+ checksum = body[/checksum:\s*([^\n]+)/, 1]
257
+
234
258
  # Skip workspace/local packages and patches
235
- next if version.include?("use.local") && packages_str.include?("workspace")
259
+ next if version&.include?("use.local") && packages_str.include?("workspace")
236
260
  next if packages_str.include?("@patch:")
237
261
 
238
262
  packages = packages_str.split(", ")
@@ -247,6 +271,7 @@ module Bibliothecary
247
271
  original_requirement: alias_name.nil? ? nil : version.to_s,
248
272
  version: version.to_s,
249
273
  source: source,
274
+ integrity: checksum,
250
275
  }
251
276
  end
252
277
  deps
@@ -281,7 +306,8 @@ module Bibliothecary
281
306
  original_requirement: original_requirement,
282
307
  type: is_dev ? "development" : "runtime",
283
308
  source: source,
284
- platform: platform_name
309
+ platform: platform_name,
310
+ integrity: details.dig("resolution", "integrity")
285
311
  )
286
312
  end
287
313
  end
@@ -318,7 +344,8 @@ module Bibliothecary
318
344
  original_requirement: original_requirement,
319
345
  type: is_dev ? "development" : "runtime",
320
346
  source: source,
321
- platform: platform_name
347
+ platform: platform_name,
348
+ integrity: details.dig("resolution", "integrity")
322
349
  )
323
350
  end
324
351
  end
@@ -327,6 +354,7 @@ module Bibliothecary
327
354
  dependencies = parsed_contents.fetch("importers", {}).fetch(".", {}).fetch("dependencies", {})
328
355
  dev_dependencies = parsed_contents.fetch("importers", {}).fetch(".", {}).fetch("devDependencies", {})
329
356
  dependency_mapping = dependencies.merge(dev_dependencies)
357
+ packages = parsed_contents.fetch("packages", {})
330
358
 
331
359
  # "dependencies" is in "packages" for < v9 and in "snapshots" for >= v9
332
360
  # as of https://github.com/pnpm/pnpm/pull/7700.
@@ -360,6 +388,10 @@ module Bibliothecary
360
388
  dev_name == name && dev_details["version"] == version
361
389
  end
362
390
 
391
+ # In v9, integrity is stored in packages section, not snapshots
392
+ package_key = "#{name}@#{version}"
393
+ integrity = packages.dig(package_key, "resolution", "integrity")
394
+
363
395
  Dependency.new(
364
396
  name: name,
365
397
  requirement: version,
@@ -367,7 +399,8 @@ module Bibliothecary
367
399
  original_requirement: original_requirement,
368
400
  type: is_dev ? "development" : "runtime",
369
401
  source: source,
370
- platform: platform_name
402
+ platform: platform_name,
403
+ integrity: integrity
371
404
  )
372
405
  end
373
406
  end
@@ -391,6 +424,45 @@ module Bibliothecary
391
424
  ParserResult.new(dependencies: dependencies)
392
425
  end
393
426
 
427
+ def self.parse_pnpm_workspace(contents, options: {})
428
+ parsed = YAML.load(contents)
429
+ source = options.fetch(:filename, nil)
430
+
431
+ dependencies = []
432
+
433
+ # Parse the default catalog (pnpm 9+)
434
+ if parsed["catalog"].is_a?(Hash)
435
+ parsed["catalog"].each do |name, requirement|
436
+ dependencies << Dependency.new(
437
+ name: name,
438
+ requirement: requirement,
439
+ type: "runtime",
440
+ source: source,
441
+ platform: platform_name
442
+ )
443
+ end
444
+ end
445
+
446
+ # Parse named catalogs (pnpm 9+)
447
+ if parsed["catalogs"].is_a?(Hash)
448
+ parsed["catalogs"].each do |_catalog_name, catalog_deps|
449
+ next unless catalog_deps.is_a?(Hash)
450
+
451
+ catalog_deps.each do |name, requirement|
452
+ dependencies << Dependency.new(
453
+ name: name,
454
+ requirement: requirement,
455
+ type: "runtime",
456
+ source: source,
457
+ platform: platform_name
458
+ )
459
+ end
460
+ end
461
+ end
462
+
463
+ ParserResult.new(dependencies: dependencies)
464
+ end
465
+
394
466
  def self.parse_ls(file_contents, options: {})
395
467
  manifest = JSON.parse(file_contents)
396
468
 
@@ -421,7 +493,8 @@ module Bibliothecary
421
493
  type: dev_deps&.include?(name) ? "development" : "runtime",
422
494
  local: is_local,
423
495
  source: source,
424
- platform: platform_name
496
+ platform: platform_name,
497
+ integrity: info[3]
425
498
  )
426
499
  end
427
500
  ParserResult.new(dependencies: dependencies)
@@ -8,6 +8,10 @@ module Bibliothecary
8
8
  class Nuget
9
9
  include Bibliothecary::Analyser
10
10
 
11
+ def self.file_patterns
12
+ ["Project.json", "Project.lock.json", "packages.lock.json", "packages.config", "*.nuspec", "*.csproj", "paket.lock", "project.assets.json", "*.deps.json"]
13
+ end
14
+
11
15
  def self.mapping
12
16
  {
13
17
  match_filename("Project.json") => {
@@ -5,12 +5,16 @@ module Bibliothecary
5
5
  class Ollama
6
6
  include Bibliothecary::Analyser
7
7
 
8
+ def self.file_patterns
9
+ ["Modelfile"]
10
+ end
11
+
8
12
  def self.mapping
9
13
  {
10
14
  match_filename("Modelfile") => {
11
15
  kind: 'manifest',
12
16
  parser: :parse_modelfile,
13
- related_to: [ 'manifest' ]
17
+ can_have_lockfile: false,
14
18
  }
15
19
  }
16
20
  end
@@ -7,6 +7,10 @@ module Bibliothecary
7
7
  class Packagist
8
8
  include Bibliothecary::Analyser
9
9
 
10
+ def self.file_patterns
11
+ ["composer.json", "composer.lock"]
12
+ end
13
+
10
14
  def self.mapping
11
15
  {
12
16
  match_filename("composer.json") => {
@@ -23,42 +27,39 @@ module Bibliothecary
23
27
 
24
28
  def self.parse_lockfile(file_contents, options: {})
25
29
  manifest = JSON.parse file_contents
26
- dependencies = manifest.fetch("packages", []).map do |dependency|
27
- requirement = dependency["version"]
30
+ source = options.fetch(:filename, nil)
28
31
 
29
- # Store Drupal version if Drupal, but include the original manifest version for reference
30
- if drupal_module?(dependency)
31
- original_requirement = requirement
32
- requirement = dependency.dig("source", "reference")
33
- end
34
-
35
- Dependency.new(
36
- name: dependency["name"],
37
- requirement: requirement,
38
- type: "runtime",
39
- original_requirement: original_requirement,
40
- source: options.fetch(:filename, nil),
41
- platform: platform_name
42
- )
32
+ dependencies = manifest.fetch("packages", []).map do |dependency|
33
+ parse_composer_dependency(dependency, "runtime", source)
43
34
  end + manifest.fetch("packages-dev", []).map do |dependency|
44
- requirement = dependency["version"]
35
+ parse_composer_dependency(dependency, "development", source)
36
+ end
37
+ ParserResult.new(dependencies: dependencies)
38
+ end
45
39
 
46
- # Store Drupal version if Drupal, but include the original manifest version for reference
47
- if drupal_module?(dependency)
48
- original_requirement = requirement
49
- requirement = dependency.dig("source", "reference")
50
- end
40
+ def self.parse_composer_dependency(dependency, type, source)
41
+ requirement = dependency["version"]
42
+ original_requirement = nil
51
43
 
52
- Dependency.new(
53
- name: dependency["name"],
54
- requirement: requirement,
55
- type: "development",
56
- original_requirement: original_requirement,
57
- source: options.fetch(:filename, nil),
58
- platform: platform_name
59
- )
44
+ # Store Drupal version if Drupal, but include the original manifest version for reference
45
+ if drupal_module?(dependency)
46
+ original_requirement = requirement
47
+ requirement = dependency.dig("source", "reference")
60
48
  end
61
- ParserResult.new(dependencies: dependencies)
49
+
50
+ # Extract shasum from dist if present and non-empty
51
+ shasum = dependency.dig("dist", "shasum")
52
+ integrity = shasum && !shasum.empty? ? "sha1=#{shasum}" : nil
53
+
54
+ Dependency.new(
55
+ name: dependency["name"],
56
+ requirement: requirement,
57
+ type: type,
58
+ original_requirement: original_requirement,
59
+ source: source,
60
+ platform: platform_name,
61
+ integrity: integrity
62
+ )
62
63
  end
63
64
 
64
65
  def self.parse_manifest(file_contents, options: {})
@@ -7,6 +7,10 @@ module Bibliothecary
7
7
  class Pub
8
8
  include Bibliothecary::Analyser
9
9
 
10
+ def self.file_patterns
11
+ ["pubspec.yaml", "pubspec.lock"]
12
+ end
13
+
10
14
  def self.mapping
11
15
  {
12
16
  match_filename("pubspec.yaml", case_insensitive: true) => {
@@ -24,6 +24,15 @@ module Bibliothecary
24
24
  # https://packaging.python.org/en/latest/specifications/pylock-toml/
25
25
  PEP_751_LOCKFILE_REGEXP = /^pylock(\.[^.]+)?\.toml$/
26
26
 
27
+ def self.file_patterns
28
+ [
29
+ "setup.py", "requirements*.txt", "requirements*.pip", "requirements*.in",
30
+ "requirements.frozen", "Pipfile", "Pipfile.lock", "pyproject.toml",
31
+ "poetry.lock", "uv.lock", "pylock.toml", "pdm.lock",
32
+ "pip-resolved-dependencies.txt", "pip-dependency-graph.json"
33
+ ]
34
+ end
35
+
27
36
  def self.mapping
28
37
  {
29
38
  match_filenames("requirements-dev.txt", "requirements/dev.txt",
@@ -122,12 +131,16 @@ module Bibliothecary
122
131
  name = block[/name\s*=\s*"([^"]+)"/, 1]
123
132
  version = block[/version\s*=\s*"([^"]+)"/, 1]
124
133
 
134
+ # Extract sdist hash: sdist = { url = "...", hash = "sha256:...", size = ... }
135
+ integrity = block[/^sdist\s*=\s*\{[^}]*hash\s*=\s*"([^"]+)"/m, 1]
136
+
125
137
  dependencies << Dependency.new(
126
138
  platform: platform_name,
127
139
  name: name,
128
140
  requirement: version,
129
141
  type: "runtime", # All dependencies are considered runtime
130
- source: source
142
+ source: source,
143
+ integrity: integrity
131
144
  )
132
145
  end
133
146
  ParserResult.new(dependencies: dependencies)
@@ -297,6 +310,15 @@ module Bibliothecary
297
310
 
298
311
  groups = ["runtime"] if groups.empty?
299
312
 
313
+ # Extract sdist hash from files array (look for .tar.gz entry)
314
+ integrity = nil
315
+ if (files_match = block[/^files\s*=\s*\[(.*?)\]/m, 1])
316
+ # Match .tar.gz file entry and extract hash
317
+ if (sdist_match = files_match.match(/\{file\s*=\s*"[^"]+\.tar\.gz",\s*hash\s*=\s*"([^"]+)"\}/))
318
+ integrity = sdist_match[1]
319
+ end
320
+ end
321
+
300
322
  groups.each do |group|
301
323
  # Poetry lockfiles should already contain normalized names, but we'll
302
324
  # apply it here as well just to be consistent with pyproject.toml parsing.
@@ -307,7 +329,8 @@ module Bibliothecary
307
329
  requirement: version,
308
330
  type: group,
309
331
  source: options.fetch(:filename, nil),
310
- platform: platform_name
332
+ platform: platform_name,
333
+ integrity: integrity
311
334
  )
312
335
  end
313
336
  end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bibliothecary
4
+ module Parsers
5
+ class Rpm
6
+ include Bibliothecary::Analyser
7
+
8
+ def self.file_patterns
9
+ ["*.spec"]
10
+ end
11
+
12
+ def self.mapping
13
+ {
14
+ match_extension(".spec") => {
15
+ kind: "manifest",
16
+ parser: :parse_spec,
17
+ can_have_lockfile: false,
18
+ },
19
+ }
20
+ end
21
+
22
+ def self.parse_spec(file_contents, options: {})
23
+ source = options.fetch(:filename, nil)
24
+ dependencies = []
25
+
26
+ # Parse BuildRequires (build dependencies)
27
+ file_contents.scan(/^BuildRequires:\s*(.+)$/i) do |match|
28
+ parse_dependency_line(match[0]).each do |dep|
29
+ dependencies << Dependency.new(
30
+ name: dep[:name],
31
+ requirement: dep[:requirement] || "*",
32
+ type: "build",
33
+ source: source,
34
+ platform: platform_name
35
+ )
36
+ end
37
+ end
38
+
39
+ # Parse Requires (runtime dependencies), including Requires(pre), Requires(post), etc.
40
+ file_contents.scan(/^Requires(?:\([^)]+\))?:\s*(.+)$/i) do |match|
41
+ parse_dependency_line(match[0]).each do |dep|
42
+ dependencies << Dependency.new(
43
+ name: dep[:name],
44
+ requirement: dep[:requirement] || "*",
45
+ type: "runtime",
46
+ source: source,
47
+ platform: platform_name
48
+ )
49
+ end
50
+ end
51
+
52
+ ParserResult.new(dependencies: dependencies)
53
+ end
54
+
55
+ def self.parse_dependency_line(line)
56
+ # Dependencies can be comma or whitespace separated
57
+ # Each dependency can have version constraints like: pkg >= 1.0
58
+ # Also filter out RPM macros like %{name}
59
+ deps = []
60
+
61
+ # Split on commas first, then handle each part
62
+ line.split(/,/).each do |part|
63
+ part = part.strip
64
+ next if part.empty?
65
+ next if part.start_with?("%") # Skip RPM macros
66
+ next if part.start_with?("/") # Skip file paths like /bin/sh
67
+
68
+ # Check for version constraint (pkg >= 1.0, pkg < 2.0, etc.)
69
+ if part =~ /^(\S+)\s+([<>=]+)\s*(\S+)$/
70
+ deps << { name: $1, requirement: "#{$2} #{$3}" }
71
+ elsif part =~ /^(\S+)$/
72
+ deps << { name: $1, requirement: nil }
73
+ end
74
+ end
75
+
76
+ deps
77
+ end
78
+ end
79
+ end
80
+ end
@@ -10,6 +10,8 @@ module Bibliothecary
10
10
  NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'
11
11
  NAME_VERSION_4 = /^ {4}#{NAME_VERSION}$/
12
12
  BUNDLED_WITH = /BUNDLED WITH/
13
+ CHECKSUMS_START = /^CHECKSUMS$/
14
+ CHECKSUM_LINE = /^ (.+) \(([^)]+)\) sha256=([a-f0-9]+)$/
13
15
 
14
16
  # Gemfile patterns
15
17
  GEM_REGEXP = /^\s*gem\s+['"]([^'"]+)['"]\s*(?:,\s*['"]([^'"]+)['"])?/
@@ -19,6 +21,10 @@ module Bibliothecary
19
21
  # Gemspec pattern - captures type in first group
20
22
  GEMSPEC_DEPENDENCY = /\.add_(development_|runtime_)?dependency\s*\(?\s*['"]([^'"]+)['"]\s*(?:,\s*['"]([^'"]+)['"])?(?:\s*,\s*['"]([^'"]+)['"])?\s*\)?/
21
23
 
24
+ def self.file_patterns
25
+ ["Gemfile", "Gemfile.lock", "gems.rb", "gems.locked", "*.gemspec"]
26
+ end
27
+
22
28
  def self.mapping
23
29
  {
24
30
  match_filenames("Gemfile", "gems.rb") => {
@@ -43,6 +49,7 @@ module Bibliothecary
43
49
  def self.parse_gemfile_lock(file_contents, options: {})
44
50
  source = options.fetch(:filename, nil)
45
51
  dependencies = []
52
+ checksums = parse_checksums(file_contents)
46
53
 
47
54
  file_contents.each_line do |line|
48
55
  line = line.chomp.gsub(/\r$/, "")
@@ -56,17 +63,43 @@ module Bibliothecary
56
63
  name: name,
57
64
  requirement: version,
58
65
  type: "runtime",
59
- source: source
66
+ source: source,
67
+ integrity: checksums["#{name}-#{version}"]
60
68
  )
61
69
  end
62
70
 
63
- if (bundler_dep = parse_bundler(file_contents, source))
71
+ if (bundler_dep = parse_bundler(file_contents, source, checksums))
64
72
  dependencies << bundler_dep
65
73
  end
66
74
 
67
75
  ParserResult.new(dependencies: dependencies)
68
76
  end
69
77
 
78
+ def self.parse_checksums(file_contents)
79
+ checksums = {}
80
+ in_checksums = false
81
+
82
+ file_contents.each_line do |line|
83
+ line = line.chomp
84
+ if line.match?(CHECKSUMS_START)
85
+ in_checksums = true
86
+ next
87
+ end
88
+
89
+ next unless in_checksums
90
+
91
+ # End of CHECKSUMS section (blank line or new section)
92
+ break if line.empty? || line.match?(/^[A-Z]/)
93
+
94
+ if (match = line.match(CHECKSUM_LINE))
95
+ name, version, sha256 = match.captures
96
+ checksums["#{name}-#{version}"] = "sha256=#{sha256}"
97
+ end
98
+ end
99
+
100
+ checksums
101
+ end
102
+
70
103
  def self.parse_gemfile(file_contents, options: {})
71
104
  source = options.fetch(:filename, nil)
72
105
  deps = []
@@ -147,7 +180,7 @@ module Bibliothecary
147
180
  end
148
181
  end
149
182
 
150
- def self.parse_bundler(file_contents, source = nil)
183
+ def self.parse_bundler(file_contents, source = nil, checksums = {})
151
184
  bundled_with_index = file_contents.lines(chomp: true).find_index { |line| line.match(BUNDLED_WITH) }
152
185
  return nil unless bundled_with_index
153
186
 
@@ -159,7 +192,8 @@ module Bibliothecary
159
192
  requirement: version,
160
193
  type: "runtime",
161
194
  source: source,
162
- platform: platform_name
195
+ platform: platform_name,
196
+ integrity: checksums["bundler-#{version}"]
163
197
  )
164
198
  end
165
199
  end
@@ -7,6 +7,10 @@ module Bibliothecary
7
7
  class Shard
8
8
  include Bibliothecary::Analyser
9
9
 
10
+ def self.file_patterns
11
+ ["shard.yml", "shard.lock"]
12
+ end
13
+
10
14
  def self.mapping
11
15
  {
12
16
  match_filename("shard.yml", case_insensitive: true) => {
@@ -12,6 +12,10 @@ module Bibliothecary
12
12
  PACKAGE_REGEXP_EXACT = /\.package\s*\(\s*(?:name:\s*"[^"]+",\s*)?url:\s*"([^"]+)"[^)]*(?:\.exact|exact)\s*\(\s*"([^"]+)"\s*\)/i
13
13
  PACKAGE_REGEXP_RANGE = /\.package\s*\(\s*(?:name:\s*"[^"]+",\s*)?url:\s*"([^"]+)"[^)]*"([^"]+)"\s*(?:\.\.|\.\.\.)\s*"([^"]+)"/i
14
14
 
15
+ def self.file_patterns
16
+ ["Package.swift", "Package.resolved"]
17
+ end
18
+
15
19
  def self.mapping
16
20
  {
17
21
  match_filename("Package.swift", case_insensitive: true) => {
@@ -3,6 +3,10 @@ module Bibliothecary
3
3
  class Vcpkg
4
4
  include Bibliothecary::Analyser
5
5
 
6
+ def self.file_patterns
7
+ ["vcpkg.json", "_generated-vcpkg-list.json"]
8
+ end
9
+
6
10
  def self.mapping
7
11
  {
8
12
  match_filename("vcpkg.json", case_insensitive: true) => {
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bibliothecary
4
- VERSION = "15.1.1"
4
+ VERSION = "15.3.0"
5
5
  end
data/lib/bibliothecary.rb CHANGED
@@ -57,6 +57,13 @@ module Bibliothecary
57
57
  runner.package_managers
58
58
  end
59
59
 
60
+ def self.supported_files
61
+ package_managers.each_with_object({}) do |pm, hash|
62
+ patterns = pm.file_patterns
63
+ hash[pm.platform_name] = patterns unless patterns.empty?
64
+ end
65
+ end
66
+
60
67
  def self.find_manifests(path)
61
68
  runner.find_manifests(path)
62
69
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecosystems-bibliothecary
3
3
  version: !ruby/object:Gem::Version
4
- version: 15.1.1
4
+ version: 15.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Nesbitt
@@ -117,6 +117,8 @@ files:
117
117
  - lib/bibliothecary/file_info.rb
118
118
  - lib/bibliothecary/parser_result.rb
119
119
  - lib/bibliothecary/parsers/actions.rb
120
+ - lib/bibliothecary/parsers/alpm.rb
121
+ - lib/bibliothecary/parsers/apk.rb
120
122
  - lib/bibliothecary/parsers/bentoml.rb
121
123
  - lib/bibliothecary/parsers/bower.rb
122
124
  - lib/bibliothecary/parsers/cargo.rb
@@ -128,6 +130,8 @@ files:
128
130
  - lib/bibliothecary/parsers/conda.rb
129
131
  - lib/bibliothecary/parsers/cpan.rb
130
132
  - lib/bibliothecary/parsers/cran.rb
133
+ - lib/bibliothecary/parsers/deb.rb
134
+ - lib/bibliothecary/parsers/deno.rb
131
135
  - lib/bibliothecary/parsers/docker.rb
132
136
  - lib/bibliothecary/parsers/dub.rb
133
137
  - lib/bibliothecary/parsers/dvc.rb
@@ -143,12 +147,14 @@ files:
143
147
  - lib/bibliothecary/parsers/meteor.rb
144
148
  - lib/bibliothecary/parsers/mlflow.rb
145
149
  - lib/bibliothecary/parsers/nimble.rb
150
+ - lib/bibliothecary/parsers/nix.rb
146
151
  - lib/bibliothecary/parsers/npm.rb
147
152
  - lib/bibliothecary/parsers/nuget.rb
148
153
  - lib/bibliothecary/parsers/ollama.rb
149
154
  - lib/bibliothecary/parsers/packagist.rb
150
155
  - lib/bibliothecary/parsers/pub.rb
151
156
  - lib/bibliothecary/parsers/pypi.rb
157
+ - lib/bibliothecary/parsers/rpm.rb
152
158
  - lib/bibliothecary/parsers/rubygems.rb
153
159
  - lib/bibliothecary/parsers/shard.rb
154
160
  - lib/bibliothecary/parsers/swift_pm.rb