bibliothecary 14.4.0 → 15.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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/UPGRADING_TO_15_0_0.md +264 -0
  4. data/lib/bibliothecary/analyser/analysis.rb +2 -2
  5. data/lib/bibliothecary/analyser.rb +24 -20
  6. data/lib/bibliothecary/dependency.rb +1 -4
  7. data/lib/bibliothecary/file_info.rb +7 -3
  8. data/lib/bibliothecary/multi_parsers/cyclonedx.rb +26 -23
  9. data/lib/bibliothecary/multi_parsers/dependencies_csv.rb +7 -4
  10. data/lib/bibliothecary/multi_parsers/spdx.rb +91 -26
  11. data/lib/bibliothecary/{multi_parsers → parser_mixins}/bundler_like_manifest.rb +1 -1
  12. data/lib/bibliothecary/{multi_parsers → parser_mixins}/json_runtime.rb +1 -1
  13. data/lib/bibliothecary/parsers/bower.rb +0 -2
  14. data/lib/bibliothecary/parsers/cargo.rb +0 -4
  15. data/lib/bibliothecary/parsers/cocoapods.rb +1 -3
  16. data/lib/bibliothecary/parsers/conan.rb +0 -4
  17. data/lib/bibliothecary/parsers/conda.rb +0 -4
  18. data/lib/bibliothecary/parsers/cpan.rb +0 -2
  19. data/lib/bibliothecary/parsers/cran.rb +0 -4
  20. data/lib/bibliothecary/parsers/dub.rb +1 -3
  21. data/lib/bibliothecary/parsers/elm.rb +1 -3
  22. data/lib/bibliothecary/parsers/go.rb +0 -4
  23. data/lib/bibliothecary/parsers/haxelib.rb +1 -3
  24. data/lib/bibliothecary/parsers/julia.rb +0 -2
  25. data/lib/bibliothecary/parsers/maven.rb +0 -4
  26. data/lib/bibliothecary/parsers/meteor.rb +1 -3
  27. data/lib/bibliothecary/parsers/npm.rb +0 -4
  28. data/lib/bibliothecary/parsers/nuget.rb +26 -30
  29. data/lib/bibliothecary/parsers/packagist.rb +0 -4
  30. data/lib/bibliothecary/parsers/pub.rb +0 -2
  31. data/lib/bibliothecary/parsers/pypi.rb +0 -4
  32. data/lib/bibliothecary/parsers/rubygems.rb +1 -5
  33. data/lib/bibliothecary/parsers/shard.rb +0 -2
  34. data/lib/bibliothecary/parsers/vcpkg.rb +0 -4
  35. data/lib/bibliothecary/related_files_info.rb +19 -15
  36. data/lib/bibliothecary/runner/multi_manifest_filter.rb +2 -83
  37. data/lib/bibliothecary/runner.rb +40 -23
  38. data/lib/bibliothecary/version.rb +1 -1
  39. data/lib/bibliothecary.rb +16 -3
  40. metadata +5 -4
@@ -9,9 +9,9 @@ Warning[:experimental] = true
9
9
 
10
10
  module Bibliothecary
11
11
  module MultiParsers
12
- module Spdx
12
+ class Spdx
13
13
  include Bibliothecary::Analyser
14
- include Bibliothecary::Analyser::TryCache
14
+ extend Bibliothecary::Analyser::TryCache
15
15
 
16
16
  # e.g. 'SomeText:' (allowing for leading whitespace)
17
17
  WELLFORMED_LINE_REGEXP = /^\s*[a-zA-Z]+:/
@@ -43,19 +43,26 @@ module Bibliothecary
43
43
  }
44
44
  end
45
45
 
46
- def parse_spdx_tag_value(file_contents, options: {})
46
+ def self.platform_name
47
+ raise "Spdx is a multi-parser and does not have a platform name."
48
+ end
49
+
50
+ def self.parse_spdx_tag_value(file_contents, options: {})
47
51
  entries = try_cache(options, options[:filename]) do
48
- parse_spdx_tag_value_file_contents(file_contents, options.fetch(:filename, nil))
52
+ parse_spdx_tag_value_file_contents(
53
+ file_contents,
54
+ options.fetch(:filename, nil)
55
+ )
49
56
  end
50
57
 
51
58
  raise NoEntries if entries.empty?
52
59
 
53
- Bibliothecary::ParserResult.new(dependencies: entries[platform_name.to_sym] || [])
60
+ Bibliothecary::ParserResult.new(dependencies: entries.to_a)
54
61
  end
55
62
 
56
- def parse_spdx_tag_value_file_contents(file_contents, source = nil)
57
- entries = {}
58
- spdx_name = spdx_version = platform = purl_name = purl_version = nil
63
+ def self.parse_spdx_tag_value_file_contents(file_contents, source = nil)
64
+ entries = Set.new
65
+ spdx_name = spdx_version = platform = purl_name = purl_version = purl_type = nil
59
66
 
60
67
  file_contents.each_line do |line|
61
68
  stripped_line = line.strip
@@ -68,10 +75,10 @@ module Bibliothecary
68
75
  # > A new package Information section is denoted by the package name (7.1) field.
69
76
  add_entry(entries: entries, platform: platform, purl_name: purl_name,
70
77
  spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version,
71
- source: source)
78
+ source: source, purl_type: purl_type)
72
79
 
73
80
  # reset for this new package
74
- spdx_name = spdx_version = platform = purl_name = purl_version = nil
81
+ spdx_name = spdx_version = platform = purl_name = purl_version = purl_type = nil
75
82
 
76
83
  # capture the new package's name
77
84
  spdx_name = match[1]
@@ -79,65 +86,123 @@ module Bibliothecary
79
86
  spdx_version = match[1]
80
87
  elsif (match = stripped_line.match(PURL_REGEXP))
81
88
  purl = PackageURL.parse(match[1])
82
- platform ||= PurlUtil::PURL_TYPE_MAPPING[purl.type]
89
+ purl_type ||= purl&.type
90
+ # Use the mapped purl->bibliothecary platform, or else fall back to original platform itself.
91
+ platform = PurlUtil::PURL_TYPE_MAPPING.fetch(purl_type, purl_type)
83
92
  purl_name ||= PurlUtil.full_name(purl)
84
- purl_version ||= purl.version
93
+ purl_version ||= purl&.version
85
94
  end
86
95
  end
87
96
 
88
97
  add_entry(entries: entries, platform: platform, purl_name: purl_name,
89
98
  spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version,
90
- source: source)
99
+ source: source, purl_type: purl_type)
91
100
 
92
101
  entries
93
102
  end
94
103
 
95
- def skip_tag_value_line?(stripped_line)
104
+ def self.skip_tag_value_line?(stripped_line)
96
105
  # Ignore blank lines and comments
97
106
  stripped_line.empty? || stripped_line.start_with?("#")
98
107
  end
99
108
 
100
- def parse_spdx_json(file_contents, options: {})
109
+ def self.parse_spdx_json(file_contents, options: {})
101
110
  entries = try_cache(options, options[:filename]) do
102
- parse_spdx_json_file_contents(file_contents, options.fetch(:filename, nil))
111
+ parse_spdx_json_file_contents(
112
+ file_contents,
113
+ options.fetch(:filename, nil)
114
+ )
103
115
  end
104
116
 
105
117
  raise NoEntries if entries.empty?
106
118
 
107
- Bibliothecary::ParserResult.new(dependencies: entries[platform_name.to_sym] || [])
119
+ Bibliothecary::ParserResult.new(dependencies: entries.to_a)
108
120
  end
109
121
 
110
- def parse_spdx_json_file_contents(file_contents, source = nil)
111
- entries = {}
122
+ def self.parse_spdx_json_file_contents(file_contents, source = nil)
112
123
  manifest = JSON.parse(file_contents)
113
124
 
125
+ if manifest.key?("spdxVersion")
126
+ parse_spdx_2_json_file_contents(manifest, source)
127
+ elsif manifest.key?("@context")
128
+ parse_spdx_3_json_file_contents(manifest, source)
129
+ else
130
+ Set.new
131
+ end
132
+ end
133
+
134
+ def self.parse_spdx_2_json_file_contents(manifest, source)
135
+ entries = Set.new
114
136
  manifest["packages"]&.each do |package|
115
137
  spdx_name = package["name"]
116
138
  spdx_version = package["versionInfo"]
117
139
 
118
140
  first_purl_string = package["externalRefs"]&.find { |ref| ref["referenceType"] == "purl" }&.dig("referenceLocator")
119
141
  purl = first_purl_string && PackageURL.parse(first_purl_string)
120
- platform = PurlUtil::PURL_TYPE_MAPPING[purl&.type]
142
+ purl_type = purl&.type
143
+ # Use the mapped purl->bibliothecary platform, or else fall back to original platform itself.
144
+ platform = PurlUtil::PURL_TYPE_MAPPING.fetch(purl_type, purl_type)
121
145
  purl_name = PurlUtil.full_name(purl)
122
146
  purl_version = purl&.version
123
147
 
124
148
  add_entry(entries: entries, platform: platform, purl_name: purl_name,
125
149
  spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version,
126
- source: source)
150
+ source: source, purl_type: purl_type)
127
151
  end
152
+ entries
153
+ end
154
+
155
+ def self.parse_spdx_3_json_file_contents(manifest, source)
156
+ entries = Set.new
157
+ manifest.fetch("@graph", [])
158
+ .select do |element|
159
+ types = Array(element["type"] || element["@type"])
160
+ # "software_Package" is the common one, but these may differ and include namespaces
161
+ types.any? { |t| t.to_s.match?(/Package$/i) }
162
+ end
163
+ .each do |element|
164
+ spdx_name = element["name"]
165
+ spdx_version = element["software_packageVersion"] || element["packageVersion"] || element["versionInfo"]
166
+
167
+ purl_string = element["externalIdentifier"]&.find do |ext_id|
168
+ ext_id_type = ext_id["externalIdentifierType"] || ext_id["identifierType"]
169
+ ext_id_type&.match?(/purl/i)
170
+ end&.dig("identifier")
171
+
172
+ purl_string ||= element.fetch("externalRef", [])
173
+ .map { |ref| ref.fetch("locator", nil) }
174
+ .compact
175
+ .map(&:first)
176
+ .find { |locator| locator.start_with?("pkg:") }
177
+
178
+ purl_string ||= element.fetch("software_packageUrl", nil)
179
+
180
+ next unless purl_string
181
+
182
+ purl = PackageURL.parse(purl_string)
183
+ purl_type = purl&.type
184
+ # Use the mapped purl->bibliothecary platform, or else fall back to original platform itself.
185
+ platform = PurlUtil::PURL_TYPE_MAPPING.fetch(purl_type, purl_type)
186
+ purl_name = PurlUtil.full_name(purl)
187
+ purl_version = purl&.version
188
+
189
+ add_entry(entries: entries, platform: platform, purl_name: purl_name,
190
+ spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version,
191
+ source: source, purl_type: purl_type)
192
+ end
128
193
 
129
194
  entries
130
195
  end
131
196
 
132
- def add_entry(entries:, platform:, purl_name:, spdx_name:, purl_version:, spdx_version:, source: nil)
197
+ def self.add_entry(entries:, platform:, purl_name:, spdx_name:, purl_version:, spdx_version:, source: nil, purl_type: nil)
133
198
  package_name = purl_name || spdx_name
134
199
  package_version = purl_version || spdx_version
135
200
 
136
- return unless platform && package_name && package_version
201
+ return unless package_name && package_version
202
+ return unless platform
137
203
 
138
- entries[platform.to_sym] ||= []
139
- entries[platform.to_sym] << Dependency.new(
140
- platform: platform.to_s,
204
+ entries << Dependency.new(
205
+ platform: platform ? platform.to_s : purl_type,
141
206
  name: package_name,
142
207
  requirement: package_version,
143
208
  type: "lockfile",
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bibliothecary
4
- module MultiParsers
4
+ module ParserMixins
5
5
  module BundlerLikeManifest
6
6
  # this takes parsed Bundler and Bundler-like (CocoaPods)
7
7
  # manifests and turns them into a list of dependencies.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bibliothecary
4
- module MultiParsers
4
+ module ParserMixins
5
5
  # Provide JSON Runtime Manifest parsing
6
6
  module JSONRuntime
7
7
  def parse_json_runtime_manifest(file_contents, options: {})
@@ -16,8 +16,6 @@ module Bibliothecary
16
16
  }
17
17
  end
18
18
 
19
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
20
-
21
19
  def self.parse_manifest(file_contents, options: {})
22
20
  json = JSON.parse(file_contents)
23
21
  dependencies = map_dependencies(json, "dependencies", "runtime", options.fetch(:filename, nil)) +
@@ -18,10 +18,6 @@ module Bibliothecary
18
18
  }
19
19
  end
20
20
 
21
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
22
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
23
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
24
-
25
21
  def self.parse_manifest(file_contents, options: {})
26
22
  manifest = Tomlrb.parse(file_contents)
27
23
 
@@ -7,7 +7,7 @@ module Bibliothecary
7
7
  module Parsers
8
8
  class CocoaPods
9
9
  include Bibliothecary::Analyser
10
- extend Bibliothecary::MultiParsers::BundlerLikeManifest
10
+ extend Bibliothecary::ParserMixins::BundlerLikeManifest
11
11
 
12
12
  NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'
13
13
  NAME_VERSION_4 = /^ {4}#{NAME_VERSION}$/
@@ -35,8 +35,6 @@ module Bibliothecary
35
35
  }
36
36
  end
37
37
 
38
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
39
-
40
38
  def self.parse_podfile_lock(file_contents, options: {})
41
39
  manifest = YAML.load file_contents
42
40
  dependencies = manifest["PODS"].map do |row|
@@ -25,10 +25,6 @@ module Bibliothecary
25
25
  }
26
26
  end
27
27
 
28
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
29
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
30
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
31
-
32
28
  def self.parse_conanfile_py(file_contents, options: {})
33
29
  dependencies = []
34
30
 
@@ -20,10 +20,6 @@ module Bibliothecary
20
20
  }
21
21
  end
22
22
 
23
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
24
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
25
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
26
-
27
23
  def self.parse_conda(file_contents, options: {})
28
24
  manifest = YAML.load(file_contents)
29
25
  deps = manifest["dependencies"]
@@ -21,8 +21,6 @@ module Bibliothecary
21
21
  }
22
22
  end
23
23
 
24
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
25
-
26
24
  def self.parse_json_manifest(file_contents, options: {})
27
25
  manifest = JSON.parse file_contents
28
26
  dependencies = manifest["prereqs"].map do |_group, deps|
@@ -18,10 +18,6 @@ module Bibliothecary
18
18
  }
19
19
  end
20
20
 
21
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
22
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
23
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
24
-
25
21
  def self.parse_description(file_contents, options: {})
26
22
  manifest = DebControl::ControlFileBase.parse(file_contents)
27
23
  dependencies = parse_section(manifest, "Depends", options.fetch(:filename, nil)) +
@@ -7,7 +7,7 @@ module Bibliothecary
7
7
  module Parsers
8
8
  class Dub
9
9
  include Bibliothecary::Analyser
10
- extend Bibliothecary::MultiParsers::JSONRuntime
10
+ extend Bibliothecary::ParserMixins::JSONRuntime
11
11
 
12
12
  def self.mapping
13
13
  {
@@ -22,8 +22,6 @@ module Bibliothecary
22
22
  }
23
23
  end
24
24
 
25
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
26
-
27
25
  def self.parse_sdl_manifest(file_contents, options: {})
28
26
  ParserResult.new(
29
27
  dependencies: SdlParser.new(:runtime, file_contents, platform_name, options.fetch(:filename, nil)).dependencies
@@ -6,7 +6,7 @@ module Bibliothecary
6
6
  module Parsers
7
7
  class Elm
8
8
  include Bibliothecary::Analyser
9
- extend Bibliothecary::MultiParsers::JSONRuntime
9
+ extend Bibliothecary::ParserMixins::JSONRuntime
10
10
 
11
11
  def self.mapping
12
12
  {
@@ -21,8 +21,6 @@ module Bibliothecary
21
21
  }
22
22
  end
23
23
 
24
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
25
-
26
24
  def self.parse_json_lock(file_contents, options: {})
27
25
  manifest = JSON.parse file_contents
28
26
  dependencies = manifest.map do |name, requirement|
@@ -72,10 +72,6 @@ module Bibliothecary
72
72
  }
73
73
  end
74
74
 
75
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
76
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
77
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
78
-
79
75
  def self.parse_godep_json(file_contents, options: {})
80
76
  manifest = JSON.parse file_contents
81
77
  dependencies = map_dependencies(manifest, "Deps", "ImportPath", "Rev", "runtime", options.fetch(:filename, nil))
@@ -6,7 +6,7 @@ module Bibliothecary
6
6
  module Parsers
7
7
  class Haxelib
8
8
  include Bibliothecary::Analyser
9
- extend Bibliothecary::MultiParsers::JSONRuntime
9
+ extend Bibliothecary::ParserMixins::JSONRuntime
10
10
 
11
11
  def self.mapping
12
12
  {
@@ -16,8 +16,6 @@ module Bibliothecary
16
16
  },
17
17
  }
18
18
  end
19
-
20
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
21
19
  end
22
20
  end
23
21
  end
@@ -14,8 +14,6 @@ module Bibliothecary
14
14
  }
15
15
  end
16
16
 
17
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
18
-
19
17
  def self.parse_require(file_contents, options: {})
20
18
  deps = []
21
19
  file_contents.split("\n").each do |line|
@@ -133,10 +133,6 @@ module Bibliothecary
133
133
  }
134
134
  end
135
135
 
136
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
137
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
138
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
139
-
140
136
  def self.parse_ivy_manifest(file_contents, options: {})
141
137
  manifest = Ox.parse file_contents
142
138
  dependencies = manifest.dependencies.locate("dependency").map do |dependency|
@@ -6,7 +6,7 @@ module Bibliothecary
6
6
  module Parsers
7
7
  class Meteor
8
8
  include Bibliothecary::Analyser
9
- extend Bibliothecary::MultiParsers::JSONRuntime
9
+ extend Bibliothecary::ParserMixins::JSONRuntime
10
10
 
11
11
  def self.mapping
12
12
  {
@@ -16,8 +16,6 @@ module Bibliothecary
16
16
  },
17
17
  }
18
18
  end
19
-
20
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
21
19
  end
22
20
  end
23
21
  end
@@ -43,10 +43,6 @@ module Bibliothecary
43
43
  }
44
44
  end
45
45
 
46
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
47
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
48
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
49
-
50
46
  def self.parse_package_lock(file_contents, options: {})
51
47
  manifest = JSON.parse(file_contents)
52
48
  # https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json#lockfileversion
@@ -7,7 +7,7 @@ module Bibliothecary
7
7
  module Parsers
8
8
  class Nuget
9
9
  include Bibliothecary::Analyser
10
- extend Bibliothecary::MultiParsers::JSONRuntime
10
+ extend Bibliothecary::ParserMixins::JSONRuntime
11
11
 
12
12
  def self.mapping
13
13
  {
@@ -46,10 +46,6 @@ module Bibliothecary
46
46
  }
47
47
  end
48
48
 
49
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
50
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
51
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
52
-
53
49
  def self.parse_project_lock_json(file_contents, options: {})
54
50
  manifest = JSON.parse file_contents
55
51
  dependencies = manifest.fetch("libraries", []).map do |name, _requirement|
@@ -68,32 +64,32 @@ module Bibliothecary
68
64
  def self.parse_packages_lock_json(file_contents, options: {})
69
65
  manifest = JSON.parse file_contents
70
66
 
71
- frameworks = {}
72
- manifest.fetch("dependencies", []).each do |framework, deps|
73
- frameworks[framework] = deps
74
- .reject { |_name, details| details["type"] == "Project" } # Projects do not have versions
75
- .map do |name, details|
76
- Dependency.new(
77
- name: name,
78
- # 'resolved' has been set in all examples so far
79
- # so fallback to requested is pure paranoia
80
- requirement: details.fetch("resolved", details.fetch("requested", "*")),
81
- type: "runtime",
82
- source: options.fetch(:filename, nil),
83
- platform: platform_name
84
- )
85
- end
86
- end
87
-
88
- unless frameworks.empty?
89
- # we should really return multiple manifests, but bibliothecary doesn't
90
- # do that yet so at least pick deterministically.
67
+ # NOTE: here we are merging dependencies from potentially >1 target framework. The versions
68
+ # across target frameworks in package.lock.json are not guaranteed to be the same, so e.g. a
69
+ # single packages.lock.json may include both "Newtonsoft.Json@13.01" and "Newtonsoft.Json@12.0.3". This
70
+ # should be more comprehensive than just returning one arbitrary framework's deps, but we're losing the
71
+ # fidelity of which target framework a given dependency was used in. Someday, bibliothecary could
72
+ # include a new Dependency field like "architecture" or "framework" and add the metadata for each dep there.
73
+ dependencies = manifest
74
+ .fetch("dependencies", [])
75
+ .flat_map do |_framework, framework_dependencies|
76
+ framework_dependencies
77
+ .reject { |_name, details| details["type"] == "Project" } # Projects do not have versions
78
+ .map do |name, details|
79
+ Dependency.new(
80
+ name: name,
81
+ # 'resolved' has been set in all examples so far
82
+ # so fallback to requested is pure paranoia
83
+ requirement: details.fetch("resolved", details.fetch("requested", "*")),
84
+ type: "runtime",
85
+ source: options.fetch(:filename, nil),
86
+ platform: platform_name
87
+ )
88
+ end
89
+ end
90
+ .uniq
91
91
 
92
- # Note, frameworks can be empty, so remove empty ones and then return the last sorted item if any
93
- frameworks.delete_if { |_k, v| v.empty? }
94
- return ParserResult.new(dependencies: frameworks[frameworks.keys.max]) unless frameworks.empty?
95
- end
96
- ParserResult.new(dependencies: [])
92
+ ParserResult.new(dependencies: dependencies)
97
93
  end
98
94
 
99
95
  def self.parse_packages_config(file_contents, options: {})
@@ -20,10 +20,6 @@ module Bibliothecary
20
20
  }
21
21
  end
22
22
 
23
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
24
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
25
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
26
-
27
23
  def self.parse_lockfile(file_contents, options: {})
28
24
  manifest = JSON.parse file_contents
29
25
  dependencies = manifest.fetch("packages", []).map do |dependency|
@@ -20,8 +20,6 @@ module Bibliothecary
20
20
  }
21
21
  end
22
22
 
23
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
24
-
25
23
  def self.parse_yaml_manifest(file_contents, options: {})
26
24
  manifest = YAML.load file_contents
27
25
  dependencies = map_dependencies(manifest, "dependencies", "runtime", options.fetch(:filename, nil)) +
@@ -84,10 +84,6 @@ module Bibliothecary
84
84
  }
85
85
  end
86
86
 
87
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
88
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
89
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
90
-
91
87
  def self.parser_pylock(file_contents, options: {})
92
88
  lockfile = Tomlrb.parse(file_contents)
93
89
  dependencies = lockfile["packages"].map do |d|
@@ -6,7 +6,7 @@ module Bibliothecary
6
6
  module Parsers
7
7
  class Rubygems
8
8
  include Bibliothecary::Analyser
9
- extend Bibliothecary::MultiParsers::BundlerLikeManifest
9
+ extend Bibliothecary::ParserMixins::BundlerLikeManifest
10
10
 
11
11
  NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'
12
12
  NAME_VERSION_4 = /^ {4}#{NAME_VERSION}$/
@@ -32,10 +32,6 @@ module Bibliothecary
32
32
  }
33
33
  end
34
34
 
35
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
36
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
37
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
38
-
39
35
  def self.parse_gemfile_lock(file_contents, options: {})
40
36
  dependencies = file_contents.lines(chomp: true).map do |line|
41
37
  match = line.match(NAME_VERSION_4)
@@ -20,8 +20,6 @@ module Bibliothecary
20
20
  }
21
21
  end
22
22
 
23
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
24
-
25
23
  def self.parse_yaml_lockfile(file_contents, options: {})
26
24
  manifest = YAML.load file_contents
27
25
  dependencies = map_dependencies(manifest, "shards", "runtime", options.fetch(:filename, nil))
@@ -19,10 +19,6 @@ module Bibliothecary
19
19
  }
20
20
  end
21
21
 
22
- add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
23
- add_multi_parser(Bibliothecary::MultiParsers::Spdx)
24
- add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
25
-
26
22
  def self.parse_vcpkg_json(file_contents, options: {})
27
23
  dependencies = []
28
24
  manifest = JSON.parse(file_contents)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Bibliothecary
4
4
  class RelatedFilesInfo
5
- attr_reader :path, :platform, :manifests, :lockfiles
5
+ attr_reader :path, :parser, :manifests, :lockfiles
6
6
 
7
7
  # Create a set of RelatedFilesInfo for the provided file_infos,
8
8
  # where each RelatedFilesInfo contains all the file_infos
@@ -18,10 +18,10 @@ module Bibliothecary
18
18
  returns.append(RelatedFilesInfo.new([file_info]))
19
19
  end
20
20
 
21
- file_infos_by_directory_by_package_manager = groupable.group_by(&:package_manager)
21
+ file_infos_by_directory_by_parser = groupable.group_by(&:parser)
22
22
 
23
- file_infos_by_directory_by_package_manager.each_value do |file_infos_in_directory_for_package_manager|
24
- returns.append(RelatedFilesInfo.new(file_infos_in_directory_for_package_manager))
23
+ file_infos_by_directory_by_parser.each_value do |file_infos_in_directory_for_parser|
24
+ returns.append(RelatedFilesInfo.new(file_infos_in_directory_for_parser))
25
25
  end
26
26
  end
27
27
 
@@ -29,34 +29,38 @@ module Bibliothecary
29
29
  end
30
30
 
31
31
  def initialize(file_infos)
32
- package_manager = file_infos.first.package_manager
32
+ parser = file_infos.first.parser
33
33
  ordered_file_infos = file_infos
34
34
 
35
- if package_manager.respond_to?(:lockfile_preference_order)
36
- ordered_file_infos = package_manager.lockfile_preference_order(file_infos)
35
+ if parser.respond_to?(:lockfile_preference_order)
36
+ ordered_file_infos = parser.lockfile_preference_order(file_infos)
37
37
  end
38
38
 
39
- @platform = package_manager.platform_name
39
+ @parser = parser.parser_name
40
40
  @path = Pathname.new(File.dirname(file_infos.first.relative_path)).cleanpath.to_path
41
41
 
42
- @manifests = filter_file_infos_by_package_manager_type(
42
+ @manifests = filter_file_infos_by_parser_type(
43
43
  file_infos: ordered_file_infos,
44
- package_manager: package_manager,
44
+ parser: parser,
45
45
  type: "manifest"
46
46
  )
47
47
 
48
- @lockfiles = filter_file_infos_by_package_manager_type(
48
+ @lockfiles = filter_file_infos_by_parser_type(
49
49
  file_infos: ordered_file_infos,
50
- package_manager: package_manager,
50
+ parser: parser,
51
51
  type: "lockfile"
52
52
  )
53
53
  end
54
54
 
55
+ def platform
56
+ raise "Bibliothecary::RelatedFileInfo#platform() has been removed in bibliothecary 15.0.0. Use parser() instead, which now includes MultiParsers."
57
+ end
58
+
55
59
  private
56
60
 
57
- def filter_file_infos_by_package_manager_type(file_infos:, package_manager:, type:)
58
- # `package_manager.determine_kind_from_info(info)` can be an Array, so use include? which also works for string
59
- file_infos.select { |info| package_manager.determine_kind_from_info(info).include?(type) }.map(&:relative_path)
61
+ def filter_file_infos_by_parser_type(file_infos:, parser:, type:)
62
+ # `parser.determine_kind_from_info(info)` can be an Array, so use include? which also works for string
63
+ file_infos.select { |info| parser.determine_kind_from_info(info).include?(type) }.map(&:relative_path)
60
64
  end
61
65
  end
62
66
  end