ecosystems-bibliothecary 14.3.0 → 15.0.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 +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +8 -23
- data/bibliothecary.gemspec +5 -9
- data/lib/bibliothecary/analyser.rb +0 -31
- data/lib/bibliothecary/cli.rb +35 -26
- data/lib/bibliothecary/configuration.rb +1 -6
- data/lib/bibliothecary/dependency.rb +1 -4
- data/lib/bibliothecary/parsers/bentoml.rb +0 -2
- data/lib/bibliothecary/parsers/bower.rb +0 -1
- data/lib/bibliothecary/parsers/cargo.rb +12 -10
- data/lib/bibliothecary/parsers/carthage.rb +51 -15
- data/lib/bibliothecary/parsers/clojars.rb +14 -18
- data/lib/bibliothecary/parsers/cocoapods.rb +100 -19
- data/lib/bibliothecary/parsers/cog.rb +0 -2
- data/lib/bibliothecary/parsers/conan.rb +156 -0
- data/lib/bibliothecary/parsers/conda.rb +0 -3
- data/lib/bibliothecary/parsers/cpan.rb +0 -2
- data/lib/bibliothecary/parsers/cran.rb +40 -19
- data/lib/bibliothecary/parsers/docker.rb +0 -2
- data/lib/bibliothecary/parsers/dub.rb +33 -8
- data/lib/bibliothecary/parsers/dvc.rb +0 -2
- data/lib/bibliothecary/parsers/elm.rb +13 -3
- data/lib/bibliothecary/parsers/go.rb +14 -5
- data/lib/bibliothecary/parsers/hackage.rb +132 -24
- data/lib/bibliothecary/parsers/haxelib.rb +14 -4
- data/lib/bibliothecary/parsers/hex.rb +37 -20
- data/lib/bibliothecary/parsers/homebrew.rb +0 -2
- data/lib/bibliothecary/parsers/julia.rb +0 -2
- data/lib/bibliothecary/parsers/maven.rb +35 -25
- data/lib/bibliothecary/parsers/meteor.rb +14 -4
- data/lib/bibliothecary/parsers/mlflow.rb +0 -2
- data/lib/bibliothecary/parsers/npm.rb +47 -59
- data/lib/bibliothecary/parsers/nuget.rb +22 -21
- data/lib/bibliothecary/parsers/ollama.rb +0 -2
- data/lib/bibliothecary/parsers/packagist.rb +0 -3
- data/lib/bibliothecary/parsers/pub.rb +0 -2
- data/lib/bibliothecary/parsers/pypi.rb +54 -35
- data/lib/bibliothecary/parsers/rubygems.rb +92 -27
- data/lib/bibliothecary/parsers/shard.rb +0 -1
- data/lib/bibliothecary/parsers/swift_pm.rb +77 -29
- data/lib/bibliothecary/parsers/vcpkg.rb +68 -17
- data/lib/bibliothecary/runner.rb +2 -15
- data/lib/bibliothecary/version.rb +1 -1
- data/lib/bibliothecary.rb +0 -4
- metadata +2 -110
- data/.codeclimate.yml +0 -25
- data/.github/CONTRIBUTING.md +0 -195
- data/.github/workflows/ci.yml +0 -25
- data/.gitignore +0 -10
- data/.rspec +0 -2
- data/.rubocop.yml +0 -69
- data/.ruby-version +0 -1
- data/.tidelift +0 -1
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -35
- data/Rakefile +0 -18
- data/bin/benchmark +0 -386
- data/bin/console +0 -15
- data/bin/setup +0 -8
- data/lib/bibliothecary/multi_parsers/bundler_like_manifest.rb +0 -26
- data/lib/bibliothecary/multi_parsers/cyclonedx.rb +0 -170
- data/lib/bibliothecary/multi_parsers/dependencies_csv.rb +0 -155
- data/lib/bibliothecary/multi_parsers/json_runtime.rb +0 -22
- data/lib/bibliothecary/multi_parsers/spdx.rb +0 -149
- data/lib/bibliothecary/purl_util.rb +0 -37
- data/lib/bibliothecary/runner/multi_manifest_filter.rb +0 -92
- data/lib/sdl_parser.rb +0 -30
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "gemnasium/parser"
|
|
4
3
|
require "yaml"
|
|
5
4
|
|
|
6
5
|
module Bibliothecary
|
|
7
6
|
module Parsers
|
|
8
7
|
class CocoaPods
|
|
9
8
|
include Bibliothecary::Analyser
|
|
10
|
-
extend Bibliothecary::MultiParsers::BundlerLikeManifest
|
|
11
9
|
|
|
12
10
|
NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'
|
|
13
11
|
NAME_VERSION_4 = /^ {4}#{NAME_VERSION}$/
|
|
14
12
|
|
|
13
|
+
# Podfile pattern: pod "Name", "version" or pod "Name"
|
|
14
|
+
# Matches: pod 'name' or pod "name" with optional version
|
|
15
|
+
POD_REGEXP = /^\s*pod\s+['"]([^'"]+)['"]\s*(?:,\s*['"]([^'"]+)['"])?/
|
|
16
|
+
|
|
17
|
+
# Podspec pattern: .dependency "Name", "version"
|
|
18
|
+
PODSPEC_DEPENDENCY = /\.dependency\s+['"]([^'"]+)['"]\s*(?:,\s*['"]([^'"]+)['"])?/
|
|
19
|
+
|
|
15
20
|
def self.mapping
|
|
16
21
|
{
|
|
17
22
|
match_filename("Podfile") => {
|
|
@@ -35,35 +40,111 @@ module Bibliothecary
|
|
|
35
40
|
}
|
|
36
41
|
end
|
|
37
42
|
|
|
38
|
-
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
39
|
-
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
|
40
43
|
|
|
41
44
|
def self.parse_podfile_lock(file_contents, options: {})
|
|
42
|
-
|
|
43
|
-
dependencies =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
source = options.fetch(:filename, nil)
|
|
46
|
+
dependencies = []
|
|
47
|
+
|
|
48
|
+
# Match pod entries: " - Name (version)" or " - Name/Subspec (version)"
|
|
49
|
+
# Only process lines in PODS section (before DEPENDENCIES section)
|
|
50
|
+
pods_section = file_contents.split(/^DEPENDENCIES:/)[0]
|
|
51
|
+
pods_section.scan(/^ - ([^\s(]+(?:\/[^\s(]+)?)\s+\(([^)]+)\)/) do |name, version|
|
|
52
|
+
# Take only the base package name (before any /)
|
|
53
|
+
base_name = name.split("/").first
|
|
54
|
+
dependencies << Dependency.new(
|
|
47
55
|
platform: platform_name,
|
|
48
|
-
name:
|
|
49
|
-
requirement:
|
|
56
|
+
name: base_name,
|
|
57
|
+
requirement: version,
|
|
50
58
|
type: "runtime",
|
|
51
|
-
source:
|
|
59
|
+
source: source
|
|
52
60
|
)
|
|
53
|
-
end
|
|
61
|
+
end
|
|
62
|
+
|
|
54
63
|
ParserResult.new(dependencies: dependencies)
|
|
55
64
|
end
|
|
56
65
|
|
|
57
66
|
def self.parse_podspec(file_contents, options: {})
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
source = options.fetch(:filename, nil)
|
|
68
|
+
deps = []
|
|
69
|
+
seen_names = Set.new
|
|
70
|
+
|
|
71
|
+
file_contents.each_line do |line|
|
|
72
|
+
match = line.match(PODSPEC_DEPENDENCY)
|
|
73
|
+
next unless match
|
|
74
|
+
|
|
75
|
+
name = match[1]
|
|
76
|
+
# Strip subspec path (e.g., "Foo/Bar" -> "Foo")
|
|
77
|
+
base_name = name.split("/").first
|
|
78
|
+
|
|
79
|
+
# Deduplicate by base name
|
|
80
|
+
next if seen_names.include?(base_name)
|
|
81
|
+
seen_names.add(base_name)
|
|
82
|
+
|
|
83
|
+
deps << Dependency.new(
|
|
84
|
+
platform: platform_name,
|
|
85
|
+
name: base_name,
|
|
86
|
+
requirement: ">= 0",
|
|
87
|
+
type: "runtime",
|
|
88
|
+
source: source
|
|
89
|
+
)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
ParserResult.new(dependencies: deps)
|
|
61
93
|
end
|
|
62
94
|
|
|
63
95
|
def self.parse_podfile(file_contents, options: {})
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
96
|
+
source = options.fetch(:filename, nil)
|
|
97
|
+
deps = []
|
|
98
|
+
in_conditional = false
|
|
99
|
+
conditional_depth = 0
|
|
100
|
+
|
|
101
|
+
file_contents.each_line do |line|
|
|
102
|
+
# Track if/else/elsif blocks to skip pods inside them
|
|
103
|
+
if line =~ /^\s*if\s+/
|
|
104
|
+
in_conditional = true
|
|
105
|
+
conditional_depth += 1
|
|
106
|
+
next
|
|
107
|
+
end
|
|
108
|
+
if line =~ /^\s*(elsif|else)\s*/
|
|
109
|
+
next
|
|
110
|
+
end
|
|
111
|
+
if line =~ /^\s*end\s*$/ && in_conditional
|
|
112
|
+
conditional_depth -= 1
|
|
113
|
+
in_conditional = false if conditional_depth == 0
|
|
114
|
+
next
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Skip pods inside conditionals
|
|
118
|
+
next if in_conditional
|
|
119
|
+
|
|
120
|
+
match = line.match(POD_REGEXP)
|
|
121
|
+
next unless match
|
|
122
|
+
|
|
123
|
+
name = match[1]
|
|
124
|
+
version = match[2]
|
|
125
|
+
|
|
126
|
+
# Skip pods with special characters like + or subspecs with /
|
|
127
|
+
next if name.include?("+") || name.include?("/")
|
|
128
|
+
|
|
129
|
+
requirement = version ? normalize_version(version) : ">= 0"
|
|
130
|
+
|
|
131
|
+
deps << Dependency.new(
|
|
132
|
+
platform: platform_name,
|
|
133
|
+
name: name,
|
|
134
|
+
requirement: requirement,
|
|
135
|
+
type: "runtime",
|
|
136
|
+
source: source
|
|
137
|
+
)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
ParserResult.new(dependencies: deps)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def self.normalize_version(version)
|
|
144
|
+
# If version already has an operator, use as-is
|
|
145
|
+
return version if version =~ /^[~>=<]/
|
|
146
|
+
# Otherwise treat as exact version
|
|
147
|
+
"= #{version}"
|
|
67
148
|
end
|
|
68
149
|
|
|
69
150
|
def self.parse_json_manifest(file_contents, options: {})
|
|
@@ -15,8 +15,6 @@ module Bibliothecary
|
|
|
15
15
|
}
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
19
|
-
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
|
20
18
|
|
|
21
19
|
def self.parse_cog_yaml(file_contents, options: {})
|
|
22
20
|
source = options.fetch(:filename, 'cog.yaml')
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bibliothecary
|
|
4
|
+
module Parsers
|
|
5
|
+
class Conan
|
|
6
|
+
include Bibliothecary::Analyser
|
|
7
|
+
|
|
8
|
+
def self.mapping
|
|
9
|
+
{
|
|
10
|
+
match_filename("conanfile.py") => {
|
|
11
|
+
kind: "manifest",
|
|
12
|
+
parser: :parse_conanfile_py,
|
|
13
|
+
},
|
|
14
|
+
match_filename("conanfile.txt") => {
|
|
15
|
+
kind: "manifest",
|
|
16
|
+
parser: :parse_conanfile_txt,
|
|
17
|
+
},
|
|
18
|
+
match_filename("conan.lock") => {
|
|
19
|
+
kind: "lockfile",
|
|
20
|
+
parser: :parse_lockfile,
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
REQUIRES_PATTERN = /self\.requires\(\s*["']([^"']+)["']/
|
|
27
|
+
|
|
28
|
+
def self.parse_conanfile_py(file_contents, options: {})
|
|
29
|
+
dependencies = []
|
|
30
|
+
|
|
31
|
+
file_contents.scan(REQUIRES_PATTERN).each do |match|
|
|
32
|
+
name, version = parse_conan_reference(match[0])
|
|
33
|
+
next if name.nil? || name.empty?
|
|
34
|
+
|
|
35
|
+
dependencies << Dependency.new(
|
|
36
|
+
name: name,
|
|
37
|
+
requirement: version || "*",
|
|
38
|
+
type: "runtime",
|
|
39
|
+
source: options.fetch(:filename, nil),
|
|
40
|
+
platform: platform_name
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
ParserResult.new(dependencies: dependencies)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.parse_conanfile_txt(file_contents, options: {})
|
|
48
|
+
dependencies = []
|
|
49
|
+
current_section = nil
|
|
50
|
+
|
|
51
|
+
file_contents.each_line do |line|
|
|
52
|
+
line = line.strip
|
|
53
|
+
next if line.empty? || line.start_with?("#")
|
|
54
|
+
|
|
55
|
+
if line.match?(/^\[([^\]]+)\]$/)
|
|
56
|
+
current_section = line[1..-2]
|
|
57
|
+
next
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
next unless %w[requires build_requires].include?(current_section)
|
|
61
|
+
|
|
62
|
+
name, version = parse_conan_reference(line)
|
|
63
|
+
next if name.nil? || name.empty?
|
|
64
|
+
|
|
65
|
+
dependencies << Dependency.new(
|
|
66
|
+
name: name,
|
|
67
|
+
requirement: version || "*",
|
|
68
|
+
type: current_section == "requires" ? "runtime" : "development",
|
|
69
|
+
source: options.fetch(:filename, nil),
|
|
70
|
+
platform: platform_name
|
|
71
|
+
)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
ParserResult.new(dependencies: dependencies)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def self.parse_lockfile(file_contents, options: {})
|
|
78
|
+
manifest = JSON.parse(file_contents)
|
|
79
|
+
|
|
80
|
+
if manifest.dig("graph_lock", "nodes")
|
|
81
|
+
parse_v1_lockfile(manifest, options: options)
|
|
82
|
+
else
|
|
83
|
+
parse_v2_lockfile(manifest, options: options)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.parse_v1_lockfile(lockfile, options: {})
|
|
88
|
+
dependencies = []
|
|
89
|
+
|
|
90
|
+
lockfile["graph_lock"]["nodes"].each_value do |node|
|
|
91
|
+
next if node["path"] && !node["path"].empty?
|
|
92
|
+
|
|
93
|
+
ref = node["pref"] || node["ref"]
|
|
94
|
+
next unless ref
|
|
95
|
+
|
|
96
|
+
name, version = parse_conan_reference(ref)
|
|
97
|
+
next if name.nil? || name.empty?
|
|
98
|
+
|
|
99
|
+
type = node["context"] == "build" ? "development" : "runtime"
|
|
100
|
+
|
|
101
|
+
dependencies << Dependency.new(
|
|
102
|
+
name: name,
|
|
103
|
+
requirement: version || "*",
|
|
104
|
+
type: type,
|
|
105
|
+
source: options.fetch(:filename, nil),
|
|
106
|
+
platform: platform_name
|
|
107
|
+
)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
ParserResult.new(dependencies: dependencies)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def self.parse_v2_lockfile(lockfile, options: {})
|
|
114
|
+
dependencies = []
|
|
115
|
+
|
|
116
|
+
parse_requires(dependencies, lockfile["requires"], "runtime", options)
|
|
117
|
+
parse_requires(dependencies, lockfile["build_requires"], "development", options)
|
|
118
|
+
parse_requires(dependencies, lockfile["python_requires"], "development", options)
|
|
119
|
+
|
|
120
|
+
ParserResult.new(dependencies: dependencies)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def self.parse_requires(dependencies, requires, type, options)
|
|
124
|
+
return unless requires&.any?
|
|
125
|
+
|
|
126
|
+
requires.each do |ref|
|
|
127
|
+
name, version = parse_conan_reference(ref)
|
|
128
|
+
next if name.nil? || name.empty?
|
|
129
|
+
|
|
130
|
+
dependencies << Dependency.new(
|
|
131
|
+
name: name,
|
|
132
|
+
requirement: version || "*",
|
|
133
|
+
type: type,
|
|
134
|
+
source: options.fetch(:filename, nil),
|
|
135
|
+
platform: platform_name
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Parse Conan reference format:
|
|
141
|
+
# name/version[@username[/channel]][#recipe_revision][:package_id[#package_revision]][%timestamp]
|
|
142
|
+
def self.parse_conan_reference(ref)
|
|
143
|
+
return [nil, nil] if ref.nil? || ref.empty? || !ref.include?("/")
|
|
144
|
+
|
|
145
|
+
# Strip timestamp, package info, recipe revision, and user/channel
|
|
146
|
+
ref = ref.split("%", 2)[0]
|
|
147
|
+
ref = ref.split(":", 2)[0]
|
|
148
|
+
ref = ref.split("#", 2)[0]
|
|
149
|
+
ref = ref.split("@", 2)[0]
|
|
150
|
+
|
|
151
|
+
parts = ref.split("/", 2)
|
|
152
|
+
[parts[0], parts[1]]
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -20,9 +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
23
|
|
|
27
24
|
def self.parse_conda(file_contents, options: {})
|
|
28
25
|
manifest = YAML.load(file_contents)
|
|
@@ -21,8 +21,6 @@ module Bibliothecary
|
|
|
21
21
|
}
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
25
|
-
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
|
26
24
|
|
|
27
25
|
def self.parse_json_manifest(file_contents, options: {})
|
|
28
26
|
manifest = JSON.parse file_contents
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "deb_control"
|
|
4
|
-
|
|
5
3
|
module Bibliothecary
|
|
6
4
|
module Parsers
|
|
7
5
|
class CRAN
|
|
@@ -18,33 +16,56 @@ module Bibliothecary
|
|
|
18
16
|
}
|
|
19
17
|
end
|
|
20
18
|
|
|
21
|
-
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
22
|
-
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
|
23
|
-
add_multi_parser(Bibliothecary::MultiParsers::Spdx)
|
|
24
19
|
|
|
25
20
|
def self.parse_description(file_contents, options: {})
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
source = options.fetch(:filename, nil)
|
|
22
|
+
fields = parse_rfc822(file_contents)
|
|
23
|
+
|
|
24
|
+
dependencies = parse_deps(fields["Depends"], "depends", source) +
|
|
25
|
+
parse_deps(fields["Imports"], "imports", source) +
|
|
26
|
+
parse_deps(fields["Suggests"], "suggests", source) +
|
|
27
|
+
parse_deps(fields["Enhances"], "enhances", source)
|
|
28
|
+
|
|
31
29
|
ParserResult.new(dependencies: dependencies)
|
|
32
30
|
end
|
|
33
31
|
|
|
34
|
-
def self.
|
|
35
|
-
|
|
32
|
+
def self.parse_rfc822(contents)
|
|
33
|
+
fields = {}
|
|
34
|
+
current_field = nil
|
|
35
|
+
|
|
36
|
+
contents.each_line do |line|
|
|
37
|
+
if line =~ /^([A-Za-z][A-Za-z0-9-]*):\s*(.*)/
|
|
38
|
+
current_field = $1
|
|
39
|
+
fields[current_field] = $2.strip
|
|
40
|
+
elsif line =~ /^\s+(.*)/ && current_field
|
|
41
|
+
# Continuation line
|
|
42
|
+
fields[current_field] += " " + $1.strip
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
fields
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.parse_deps(value, type, source)
|
|
50
|
+
return [] unless value
|
|
51
|
+
|
|
52
|
+
value.split(",").map(&:strip).map do |dep_str|
|
|
53
|
+
next if dep_str.empty?
|
|
54
|
+
|
|
55
|
+
match = dep_str.match(REQUIRE_REGEXP)
|
|
56
|
+
next unless match
|
|
57
|
+
|
|
58
|
+
# Normalize whitespace: collapse multiple spaces, but preserve single space after operator
|
|
59
|
+
requirement = match[2]&.gsub(/\s+/, " ")&.strip || "*"
|
|
36
60
|
|
|
37
|
-
deps = manifest.first[name].delete("\n").split(",").map(&:strip)
|
|
38
|
-
deps.map do |dependency|
|
|
39
|
-
dep = dependency.match(REQUIRE_REGEXP)
|
|
40
61
|
Dependency.new(
|
|
41
|
-
name:
|
|
42
|
-
requirement:
|
|
43
|
-
type:
|
|
62
|
+
name: match[1],
|
|
63
|
+
requirement: requirement,
|
|
64
|
+
type: type,
|
|
44
65
|
source: source,
|
|
45
66
|
platform: platform_name
|
|
46
67
|
)
|
|
47
|
-
end
|
|
68
|
+
end.compact
|
|
48
69
|
end
|
|
49
70
|
end
|
|
50
71
|
end
|
|
@@ -23,8 +23,6 @@ module Bibliothecary
|
|
|
23
23
|
}
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
27
|
-
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
|
28
26
|
|
|
29
27
|
def self.parse_docker_compose(file_contents, options: {})
|
|
30
28
|
source = options.fetch(:filename, 'docker-compose.yml')
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
-
require "sdl_parser"
|
|
5
4
|
|
|
6
5
|
module Bibliothecary
|
|
7
6
|
module Parsers
|
|
8
7
|
class Dub
|
|
9
8
|
include Bibliothecary::Analyser
|
|
10
|
-
|
|
9
|
+
|
|
10
|
+
SDL_DEPENDENCY_REGEXP = /^dependency\s+"([^"]+)"(?:\s+version="([^"]+)")?/
|
|
11
11
|
|
|
12
12
|
def self.mapping
|
|
13
13
|
{
|
|
14
14
|
match_filename("dub.json") => {
|
|
15
15
|
kind: "manifest",
|
|
16
|
-
parser: :
|
|
16
|
+
parser: :parse_json_manifest,
|
|
17
17
|
},
|
|
18
18
|
match_filename("dub.sdl") => {
|
|
19
19
|
kind: "manifest",
|
|
@@ -22,13 +22,38 @@ module Bibliothecary
|
|
|
22
22
|
}
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
def self.parse_json_manifest(file_contents, options: {})
|
|
26
|
+
manifest = JSON.parse(file_contents)
|
|
27
|
+
dependencies = manifest.fetch("dependencies", {}).map do |name, requirement|
|
|
28
|
+
Dependency.new(
|
|
29
|
+
name: name,
|
|
30
|
+
requirement: requirement,
|
|
31
|
+
type: "runtime",
|
|
32
|
+
source: options.fetch(:filename, nil),
|
|
33
|
+
platform: platform_name
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
ParserResult.new(dependencies: dependencies)
|
|
37
|
+
end
|
|
27
38
|
|
|
28
39
|
def self.parse_sdl_manifest(file_contents, options: {})
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
source = options.fetch(:filename, nil)
|
|
41
|
+
deps = []
|
|
42
|
+
|
|
43
|
+
file_contents.each_line do |line|
|
|
44
|
+
match = line.match(SDL_DEPENDENCY_REGEXP)
|
|
45
|
+
next unless match
|
|
46
|
+
|
|
47
|
+
deps << Dependency.new(
|
|
48
|
+
platform: platform_name,
|
|
49
|
+
name: match[1],
|
|
50
|
+
requirement: match[2] || ">= 0",
|
|
51
|
+
type: :runtime,
|
|
52
|
+
source: source
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
ParserResult.new(dependencies: deps.uniq)
|
|
32
57
|
end
|
|
33
58
|
end
|
|
34
59
|
end
|
|
@@ -15,8 +15,6 @@ module Bibliothecary
|
|
|
15
15
|
}
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
19
|
-
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
|
20
18
|
|
|
21
19
|
def self.parse_dvc_yaml(file_contents, options: {})
|
|
22
20
|
source = options.fetch(:filename, 'dvc.yaml')
|
|
@@ -6,7 +6,6 @@ module Bibliothecary
|
|
|
6
6
|
module Parsers
|
|
7
7
|
class Elm
|
|
8
8
|
include Bibliothecary::Analyser
|
|
9
|
-
extend Bibliothecary::MultiParsers::JSONRuntime
|
|
10
9
|
|
|
11
10
|
def self.mapping
|
|
12
11
|
{
|
|
@@ -21,8 +20,19 @@ module Bibliothecary
|
|
|
21
20
|
}
|
|
22
21
|
end
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
def self.parse_json_runtime_manifest(file_contents, options: {})
|
|
24
|
+
manifest = JSON.parse(file_contents)
|
|
25
|
+
dependencies = manifest.fetch("dependencies", {}).map do |name, requirement|
|
|
26
|
+
Dependency.new(
|
|
27
|
+
name: name,
|
|
28
|
+
requirement: requirement,
|
|
29
|
+
type: "runtime",
|
|
30
|
+
source: options.fetch(:filename, nil),
|
|
31
|
+
platform: platform_name
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
ParserResult.new(dependencies: dependencies)
|
|
35
|
+
end
|
|
26
36
|
|
|
27
37
|
def self.parse_json_lock(file_contents, options: {})
|
|
28
38
|
manifest = JSON.parse file_contents
|
|
@@ -72,9 +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
75
|
|
|
79
76
|
def self.parse_godep_json(file_contents, options: {})
|
|
80
77
|
manifest = JSON.parse file_contents
|
|
@@ -132,8 +129,20 @@ module Bibliothecary
|
|
|
132
129
|
end
|
|
133
130
|
|
|
134
131
|
def self.parse_dep_lockfile(file_contents, options: {})
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
dependencies = []
|
|
133
|
+
# Split into [[projects]] blocks and extract fields from each
|
|
134
|
+
file_contents.split(/\[\[projects\]\]/).drop(1).each do |block|
|
|
135
|
+
name = block[/name\s*=\s*"([^"]+)"/, 1]
|
|
136
|
+
revision = block[/revision\s*=\s*"([^"]+)"/, 1]
|
|
137
|
+
|
|
138
|
+
dependencies << Dependency.new(
|
|
139
|
+
platform: platform_name,
|
|
140
|
+
name: name,
|
|
141
|
+
requirement: revision,
|
|
142
|
+
type: "runtime",
|
|
143
|
+
source: options.fetch(:filename, nil)
|
|
144
|
+
)
|
|
145
|
+
end
|
|
137
146
|
ParserResult.new(dependencies: dependencies)
|
|
138
147
|
end
|
|
139
148
|
|