bibliothecary 7.3.4 → 8.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/.circleci/config.yml +1 -1
- data/README.md +8 -0
- data/bibliothecary.gemspec +1 -0
- data/lib/bibliothecary/analyser/analysis.rb +110 -0
- data/lib/bibliothecary/analyser/determinations.rb +27 -0
- data/lib/bibliothecary/analyser/matchers.rb +64 -0
- data/lib/bibliothecary/analyser.rb +32 -188
- data/lib/bibliothecary/cli.rb +3 -3
- data/lib/bibliothecary/file_info.rb +2 -0
- data/lib/bibliothecary/multi_parsers/bundler_like_manifest.rb +22 -0
- data/lib/bibliothecary/multi_parsers/cyclonedx.rb +138 -0
- data/lib/bibliothecary/multi_parsers/json_runtime.rb +16 -0
- data/lib/bibliothecary/parsers/bower.rb +2 -2
- data/lib/bibliothecary/parsers/cargo.rb +4 -2
- data/lib/bibliothecary/parsers/carthage.rb +6 -6
- data/lib/bibliothecary/parsers/clojars.rb +2 -2
- data/lib/bibliothecary/parsers/cocoapods.rb +5 -4
- data/lib/bibliothecary/parsers/conda.rb +11 -5
- data/lib/bibliothecary/parsers/cpan.rb +2 -2
- data/lib/bibliothecary/parsers/cran.rb +3 -1
- data/lib/bibliothecary/parsers/dub.rb +3 -2
- data/lib/bibliothecary/parsers/elm.rb +2 -1
- data/lib/bibliothecary/parsers/generic.rb +3 -3
- data/lib/bibliothecary/parsers/go.rb +13 -11
- data/lib/bibliothecary/parsers/hackage.rb +4 -2
- data/lib/bibliothecary/parsers/haxelib.rb +1 -0
- data/lib/bibliothecary/parsers/hex.rb +6 -4
- data/lib/bibliothecary/parsers/julia.rb +2 -2
- data/lib/bibliothecary/parsers/maven.rb +27 -10
- data/lib/bibliothecary/parsers/meteor.rb +1 -0
- data/lib/bibliothecary/parsers/npm.rb +7 -5
- data/lib/bibliothecary/parsers/nuget.rb +10 -7
- data/lib/bibliothecary/parsers/packagist.rb +4 -2
- data/lib/bibliothecary/parsers/pub.rb +2 -2
- data/lib/bibliothecary/parsers/pypi.rb +11 -9
- data/lib/bibliothecary/parsers/rubygems.rb +7 -4
- data/lib/bibliothecary/parsers/shard.rb +2 -2
- data/lib/bibliothecary/parsers/swift_pm.rb +4 -2
- data/lib/bibliothecary/runner.rb +8 -3
- data/lib/bibliothecary/version.rb +1 -1
- data/lib/bibliothecary.rb +3 -0
- metadata +26 -6
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'ox'
|
|
3
|
+
|
|
4
|
+
# packageurl-ruby uses pattern-matching (https://docs.ruby-lang.org/en/2.7.0/NEWS.html#label-Pattern+matching)
|
|
5
|
+
# which warns a whole bunch in Ruby 2.7 as being an experimental feature, but has
|
|
6
|
+
# been accepted in Ruby 3.0 (https://rubyreferences.github.io/rubychanges/3.0.html#pattern-matching).
|
|
7
|
+
Warning[:experimental] = false
|
|
8
|
+
require 'package_url'
|
|
9
|
+
Warning[:experimental] = true
|
|
10
|
+
|
|
11
|
+
module Bibliothecary
|
|
12
|
+
module MultiParsers
|
|
13
|
+
module CycloneDX
|
|
14
|
+
include Bibliothecary::Analyser
|
|
15
|
+
include Bibliothecary::Analyser::TryCache
|
|
16
|
+
|
|
17
|
+
NoComponents = Class.new(StandardError)
|
|
18
|
+
|
|
19
|
+
class ManifestEntries
|
|
20
|
+
# If a purl type (key) exists, it will be used in a manifest for
|
|
21
|
+
# the key's value. If not, it's ignored.
|
|
22
|
+
#
|
|
23
|
+
# https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst
|
|
24
|
+
PURL_TYPE_MAPPING = {
|
|
25
|
+
"golang" => :go,
|
|
26
|
+
"maven" => :maven,
|
|
27
|
+
"npm" => :npm,
|
|
28
|
+
"cargo" => :cargo,
|
|
29
|
+
"composer" => :packagist,
|
|
30
|
+
"conda" => :conda,
|
|
31
|
+
"cran" => :cran,
|
|
32
|
+
"gem" => :rubygems,
|
|
33
|
+
"hackage" => :hackage,
|
|
34
|
+
"hex" => :hex,
|
|
35
|
+
"nuget" => :nuget,
|
|
36
|
+
"pypi" => :pypi,
|
|
37
|
+
"swift" => :swift_pm
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
attr_reader :manifests
|
|
41
|
+
|
|
42
|
+
def initialize
|
|
43
|
+
@manifests = {}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def <<(purl)
|
|
47
|
+
mapping = PURL_TYPE_MAPPING[purl.type]
|
|
48
|
+
return unless mapping
|
|
49
|
+
|
|
50
|
+
@manifests[mapping] ||= Set.new
|
|
51
|
+
@manifests[mapping] << {
|
|
52
|
+
name: self.class.full_name_for_purl(purl),
|
|
53
|
+
requirement: purl.version,
|
|
54
|
+
type: 'lockfile'
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def [](key)
|
|
59
|
+
@manifests[key]&.to_a
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @return [String] The properly namespaced package name
|
|
63
|
+
def self.full_name_for_purl(purl)
|
|
64
|
+
parts = [purl.namespace, purl.name].compact
|
|
65
|
+
|
|
66
|
+
case purl.type
|
|
67
|
+
when "maven"
|
|
68
|
+
parts.join(':')
|
|
69
|
+
else
|
|
70
|
+
parts.join('/')
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.mapping
|
|
76
|
+
{
|
|
77
|
+
match_filename('cyclonedx.json') => {
|
|
78
|
+
kind: 'lockfile',
|
|
79
|
+
parser: :parse_cyclonedx_json
|
|
80
|
+
},
|
|
81
|
+
match_filename('cyclonedx.xml') => {
|
|
82
|
+
kind: 'lockfile',
|
|
83
|
+
parser: :parse_cyclonedx_xml
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def parse_cyclonedx_json(file_contents, options: {})
|
|
89
|
+
manifest = nil
|
|
90
|
+
|
|
91
|
+
manifest = try_cache(options, options[:filename]) do
|
|
92
|
+
JSON.parse(file_contents)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
raise NoComponents unless manifest["components"]
|
|
96
|
+
|
|
97
|
+
entries = ManifestEntries.new
|
|
98
|
+
|
|
99
|
+
manifest["components"].each_with_object(entries) do |component, obj|
|
|
100
|
+
next unless component["purl"]
|
|
101
|
+
|
|
102
|
+
purl = PackageURL.parse(component["purl"])
|
|
103
|
+
|
|
104
|
+
obj << purl
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
entries[platform_name.to_sym]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def parse_cyclonedx_xml(file_contents, options: {})
|
|
111
|
+
manifest = try_cache(options, options[:filename]) do
|
|
112
|
+
Ox.parse(file_contents)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
root = manifest
|
|
116
|
+
if root.respond_to?(:bom)
|
|
117
|
+
root = root.bom
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
raise NoComponents unless root.locate('components').first
|
|
121
|
+
|
|
122
|
+
entries = ManifestEntries.new
|
|
123
|
+
|
|
124
|
+
root.locate('components/*').each_with_object(entries) do |component, obj|
|
|
125
|
+
purl_node = component.locate("purl").first
|
|
126
|
+
|
|
127
|
+
next unless purl_node
|
|
128
|
+
|
|
129
|
+
purl = PackageURL.parse(purl_node.text)
|
|
130
|
+
|
|
131
|
+
obj << purl
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
entries[platform_name.to_sym]
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Bibliothecary
|
|
2
|
+
module MultiParsers
|
|
3
|
+
# Provide JSON Runtime Manifest parsing
|
|
4
|
+
module JSONRuntime
|
|
5
|
+
def parse_json_runtime_manifest(file_contents, options: {})
|
|
6
|
+
JSON.parse(file_contents).fetch('dependencies',[]).map do |name, requirement|
|
|
7
|
+
{
|
|
8
|
+
name: name,
|
|
9
|
+
requirement: requirement,
|
|
10
|
+
type: 'runtime'
|
|
11
|
+
}
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -14,8 +14,8 @@ module Bibliothecary
|
|
|
14
14
|
}
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def self.parse_manifest(
|
|
18
|
-
json = JSON.parse(
|
|
17
|
+
def self.parse_manifest(file_contents, options: {})
|
|
18
|
+
json = JSON.parse(file_contents)
|
|
19
19
|
map_dependencies(json, 'dependencies', 'runtime') +
|
|
20
20
|
map_dependencies(json, 'devDependencies', 'development')
|
|
21
21
|
end
|
|
@@ -16,7 +16,9 @@ module Bibliothecary
|
|
|
16
16
|
}
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
20
|
+
|
|
21
|
+
def self.parse_manifest(file_contents, options: {})
|
|
20
22
|
manifest = Tomlrb.parse(file_contents)
|
|
21
23
|
manifest.fetch('dependencies', []).map do |name, requirement|
|
|
22
24
|
if requirement.respond_to?(:fetch)
|
|
@@ -31,7 +33,7 @@ module Bibliothecary
|
|
|
31
33
|
.compact
|
|
32
34
|
end
|
|
33
35
|
|
|
34
|
-
def self.parse_lockfile(file_contents)
|
|
36
|
+
def self.parse_lockfile(file_contents, options: {})
|
|
35
37
|
manifest = Tomlrb.parse(file_contents)
|
|
36
38
|
manifest.fetch('package',[]).map do |dependency|
|
|
37
39
|
next if not dependency['source'] or not dependency['source'].start_with?('registry+')
|
|
@@ -20,16 +20,16 @@ module Bibliothecary
|
|
|
20
20
|
}
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def self.parse_cartfile(
|
|
24
|
-
map_dependencies(
|
|
23
|
+
def self.parse_cartfile(file_contents, options: {})
|
|
24
|
+
map_dependencies(file_contents, 'cartfile')
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
def self.parse_cartfile_private(
|
|
28
|
-
map_dependencies(
|
|
27
|
+
def self.parse_cartfile_private(file_contents, options: {})
|
|
28
|
+
map_dependencies(file_contents, 'cartfile.private')
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def self.parse_cartfile_resolved(
|
|
32
|
-
map_dependencies(
|
|
31
|
+
def self.parse_cartfile_resolved(file_contents, options: {})
|
|
32
|
+
map_dependencies(file_contents, 'cartfile.resolved')
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def self.map_dependencies(manifest, path)
|
|
@@ -15,8 +15,8 @@ module Bibliothecary
|
|
|
15
15
|
}
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def self.parse_manifest(
|
|
19
|
-
response = Typhoeus.post("#{Bibliothecary.configuration.clojars_parser_host}/project.clj", body:
|
|
18
|
+
def self.parse_manifest(file_contents, options: {})
|
|
19
|
+
response = Typhoeus.post("#{Bibliothecary.configuration.clojars_parser_host}/project.clj", body: file_contents)
|
|
20
20
|
raise Bibliothecary::RemoteParsingError.new("Http Error #{response.response_code} when contacting: #{Bibliothecary.configuration.clojars_parser_host}/project.clj", response.response_code) unless response.success?
|
|
21
21
|
json = JSON.parse response.body
|
|
22
22
|
index = json.index("dependencies")
|
|
@@ -5,6 +5,7 @@ module Bibliothecary
|
|
|
5
5
|
module Parsers
|
|
6
6
|
class CocoaPods
|
|
7
7
|
include Bibliothecary::Analyser
|
|
8
|
+
extend Bibliothecary::MultiParsers::BundlerLikeManifest
|
|
8
9
|
|
|
9
10
|
NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'.freeze
|
|
10
11
|
NAME_VERSION_4 = /^ {4}#{NAME_VERSION}$/
|
|
@@ -32,7 +33,7 @@ module Bibliothecary
|
|
|
32
33
|
}
|
|
33
34
|
end
|
|
34
35
|
|
|
35
|
-
def self.parse_podfile_lock(file_contents)
|
|
36
|
+
def self.parse_podfile_lock(file_contents, options: {})
|
|
36
37
|
manifest = YAML.load file_contents
|
|
37
38
|
manifest['PODS'].map do |row|
|
|
38
39
|
pod = row.is_a?(String) ? row : row.keys.first
|
|
@@ -45,17 +46,17 @@ module Bibliothecary
|
|
|
45
46
|
end.compact
|
|
46
47
|
end
|
|
47
48
|
|
|
48
|
-
def self.parse_podspec(file_contents)
|
|
49
|
+
def self.parse_podspec(file_contents, options: {})
|
|
49
50
|
manifest = Gemnasium::Parser.send(:podspec, file_contents)
|
|
50
51
|
parse_ruby_manifest(manifest)
|
|
51
52
|
end
|
|
52
53
|
|
|
53
|
-
def self.parse_podfile(file_contents)
|
|
54
|
+
def self.parse_podfile(file_contents, options: {})
|
|
54
55
|
manifest = Gemnasium::Parser.send(:podfile, file_contents)
|
|
55
56
|
parse_ruby_manifest(manifest)
|
|
56
57
|
end
|
|
57
58
|
|
|
58
|
-
def self.parse_json_manifest(file_contents)
|
|
59
|
+
def self.parse_json_manifest(file_contents, options: {})
|
|
59
60
|
manifest = JSON.parse(file_contents)
|
|
60
61
|
manifest['dependencies'].inject([]) do |deps, dep|
|
|
61
62
|
deps.push({
|
|
@@ -26,13 +26,19 @@ module Bibliothecary
|
|
|
26
26
|
}
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
30
|
+
|
|
31
|
+
def self.parse_conda(file_contents, options: {})
|
|
32
|
+
parse_conda_with_kind(file_contents, "manifest")
|
|
32
33
|
end
|
|
33
34
|
|
|
34
|
-
def self.parse_conda_lockfile(
|
|
35
|
-
|
|
35
|
+
def self.parse_conda_lockfile(file_contents, options: {})
|
|
36
|
+
parse_conda_with_kind(file_contents, "lockfile")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.parse_conda_with_kind(info, kind)
|
|
40
|
+
dependencies = call_conda_parser_web(info, kind)[kind.to_sym]
|
|
41
|
+
dependencies.map { |dep| dep.merge(type: "runtime") }
|
|
36
42
|
end
|
|
37
43
|
|
|
38
44
|
private_class_method def self.call_conda_parser_web(file_contents, kind)
|
|
@@ -19,14 +19,14 @@ module Bibliothecary
|
|
|
19
19
|
}
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def self.parse_json_manifest(file_contents)
|
|
22
|
+
def self.parse_json_manifest(file_contents, options: {})
|
|
23
23
|
manifest = JSON.parse file_contents
|
|
24
24
|
manifest['prereqs'].map do |_group, deps|
|
|
25
25
|
map_dependencies(deps, 'requires', 'runtime')
|
|
26
26
|
end.flatten
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def self.parse_yaml_manifest(file_contents)
|
|
29
|
+
def self.parse_yaml_manifest(file_contents, options: {})
|
|
30
30
|
manifest = YAML.load file_contents
|
|
31
31
|
map_dependencies(manifest, 'requires', 'runtime')
|
|
32
32
|
end
|
|
@@ -16,7 +16,9 @@ module Bibliothecary
|
|
|
16
16
|
}
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
20
|
+
|
|
21
|
+
def self.parse_description(file_contents, options: {})
|
|
20
22
|
manifest = DebControl::ControlFileBase.parse(file_contents)
|
|
21
23
|
parse_section(manifest, 'Depends') +
|
|
22
24
|
parse_section(manifest, 'Imports') +
|
|
@@ -5,6 +5,7 @@ module Bibliothecary
|
|
|
5
5
|
module Parsers
|
|
6
6
|
class Dub
|
|
7
7
|
include Bibliothecary::Analyser
|
|
8
|
+
extend Bibliothecary::MultiParsers::JSONRuntime
|
|
8
9
|
|
|
9
10
|
def self.mapping
|
|
10
11
|
{
|
|
@@ -19,8 +20,8 @@ module Bibliothecary
|
|
|
19
20
|
}
|
|
20
21
|
end
|
|
21
22
|
|
|
22
|
-
def self.parse_sdl_manifest(
|
|
23
|
-
SdlParser.new(:runtime,
|
|
23
|
+
def self.parse_sdl_manifest(file_contents, options: {})
|
|
24
|
+
SdlParser.new(:runtime, file_contents).dependencies
|
|
24
25
|
end
|
|
25
26
|
end
|
|
26
27
|
end
|
|
@@ -4,6 +4,7 @@ module Bibliothecary
|
|
|
4
4
|
module Parsers
|
|
5
5
|
class Elm
|
|
6
6
|
include Bibliothecary::Analyser
|
|
7
|
+
extend Bibliothecary::MultiParsers::JSONRuntime
|
|
7
8
|
|
|
8
9
|
def self.mapping
|
|
9
10
|
{
|
|
@@ -18,7 +19,7 @@ module Bibliothecary
|
|
|
18
19
|
}
|
|
19
20
|
end
|
|
20
21
|
|
|
21
|
-
def self.parse_json_lock(file_contents)
|
|
22
|
+
def self.parse_json_lock(file_contents, options: {})
|
|
22
23
|
manifest = JSON.parse file_contents
|
|
23
24
|
manifest.map do |name, requirement|
|
|
24
25
|
{
|
|
@@ -14,7 +14,7 @@ module Bibliothecary
|
|
|
14
14
|
}
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def self.parse_lockfile(file_contents)
|
|
17
|
+
def self.parse_lockfile(file_contents, options: {})
|
|
18
18
|
table = CSV.parse(file_contents, headers: true)
|
|
19
19
|
|
|
20
20
|
required_headers = ["platform", "name", "requirement"]
|
|
@@ -22,9 +22,9 @@ module Bibliothecary
|
|
|
22
22
|
raise "Missing headers #{missing_headers} in CSV" unless missing_headers.empty?
|
|
23
23
|
|
|
24
24
|
table.map.with_index do |row, idx|
|
|
25
|
-
line = idx + 1
|
|
25
|
+
line = idx + 2 # use 1-based index just like the 'csv' std lib, and count the headers as first row.
|
|
26
26
|
required_headers.each do |h|
|
|
27
|
-
raise "missing field '#{h}' on line #{line}" if row[h].empty?
|
|
27
|
+
raise "missing field '#{h}' on line #{line}" if row[h].nil? || row[h].empty?
|
|
28
28
|
end
|
|
29
29
|
{
|
|
30
30
|
platform: row['platform'],
|
|
@@ -65,12 +65,14 @@ module Bibliothecary
|
|
|
65
65
|
}
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
69
|
+
|
|
70
|
+
def self.parse_godep_json(file_contents, options: {})
|
|
69
71
|
manifest = JSON.parse file_contents
|
|
70
72
|
map_dependencies(manifest, 'Deps', 'ImportPath', 'Rev', 'runtime')
|
|
71
73
|
end
|
|
72
74
|
|
|
73
|
-
def self.parse_gpm(file_contents)
|
|
75
|
+
def self.parse_gpm(file_contents, options: {})
|
|
74
76
|
deps = []
|
|
75
77
|
file_contents.split("\n").each do |line|
|
|
76
78
|
match = line.gsub(/(\#(.*))/, '').match(GPM_REGEXP)
|
|
@@ -84,38 +86,38 @@ module Bibliothecary
|
|
|
84
86
|
deps
|
|
85
87
|
end
|
|
86
88
|
|
|
87
|
-
def self.parse_govendor(file_contents)
|
|
89
|
+
def self.parse_govendor(file_contents, options: {})
|
|
88
90
|
manifest = JSON.load file_contents
|
|
89
91
|
map_dependencies(manifest, 'package', 'path', 'revision', 'runtime')
|
|
90
92
|
end
|
|
91
93
|
|
|
92
|
-
def self.parse_glide_yaml(file_contents)
|
|
94
|
+
def self.parse_glide_yaml(file_contents, options: {})
|
|
93
95
|
manifest = YAML.load file_contents
|
|
94
96
|
map_dependencies(manifest, 'import', 'package', 'version', 'runtime') +
|
|
95
97
|
map_dependencies(manifest, 'devImports', 'package', 'version', 'development')
|
|
96
98
|
end
|
|
97
99
|
|
|
98
|
-
def self.parse_glide_lockfile(file_contents)
|
|
100
|
+
def self.parse_glide_lockfile(file_contents, options: {})
|
|
99
101
|
manifest = YAML.load file_contents
|
|
100
102
|
map_dependencies(manifest, 'imports', 'name', 'version', 'runtime')
|
|
101
103
|
end
|
|
102
104
|
|
|
103
|
-
def self.parse_gb_manifest(file_contents)
|
|
105
|
+
def self.parse_gb_manifest(file_contents, options: {})
|
|
104
106
|
manifest = JSON.parse file_contents
|
|
105
107
|
map_dependencies(manifest, 'dependencies', 'importpath', 'revision', 'runtime')
|
|
106
108
|
end
|
|
107
109
|
|
|
108
|
-
def self.parse_dep_toml(file_contents)
|
|
110
|
+
def self.parse_dep_toml(file_contents, options: {})
|
|
109
111
|
manifest = Tomlrb.parse file_contents
|
|
110
112
|
map_dependencies(manifest, 'constraint', 'name', 'version', 'runtime')
|
|
111
113
|
end
|
|
112
114
|
|
|
113
|
-
def self.parse_dep_lockfile(file_contents)
|
|
115
|
+
def self.parse_dep_lockfile(file_contents, options: {})
|
|
114
116
|
manifest = Tomlrb.parse file_contents
|
|
115
117
|
map_dependencies(manifest, 'projects', 'name', 'revision', 'runtime')
|
|
116
118
|
end
|
|
117
119
|
|
|
118
|
-
def self.parse_go_mod(file_contents)
|
|
120
|
+
def self.parse_go_mod(file_contents, options: {})
|
|
119
121
|
deps = []
|
|
120
122
|
file_contents.lines.map(&:strip).each do |line|
|
|
121
123
|
next if line.match(GOMOD_IGNORABLE_REGEX)
|
|
@@ -130,7 +132,7 @@ module Bibliothecary
|
|
|
130
132
|
deps
|
|
131
133
|
end
|
|
132
134
|
|
|
133
|
-
def self.parse_go_sum(file_contents)
|
|
135
|
+
def self.parse_go_sum(file_contents, options: {})
|
|
134
136
|
deps = []
|
|
135
137
|
file_contents.lines.map(&:strip).each do |line|
|
|
136
138
|
if match = line.match(GOSUM_REGEX)
|
|
@@ -144,7 +146,7 @@ module Bibliothecary
|
|
|
144
146
|
deps.uniq
|
|
145
147
|
end
|
|
146
148
|
|
|
147
|
-
def self.parse_go_resolved(file_contents)
|
|
149
|
+
def self.parse_go_resolved(file_contents, options: {})
|
|
148
150
|
JSON.parse(file_contents)
|
|
149
151
|
.select { |dep| dep["Main"] != "true" }
|
|
150
152
|
.map { |dep| { name: dep["Path"], requirement: dep["Version"], type: 'runtime' } }
|
|
@@ -19,7 +19,9 @@ module Bibliothecary
|
|
|
19
19
|
}
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
23
|
+
|
|
24
|
+
def self.parse_cabal(file_contents, options: {})
|
|
23
25
|
headers = {
|
|
24
26
|
'Content-Type' => "text/plain;charset=utf-8"
|
|
25
27
|
}
|
|
@@ -30,7 +32,7 @@ module Bibliothecary
|
|
|
30
32
|
JSON.parse(response.body, symbolize_names: true)
|
|
31
33
|
end
|
|
32
34
|
|
|
33
|
-
def self.parse_cabal_config(file_contents)
|
|
35
|
+
def self.parse_cabal_config(file_contents, options: {})
|
|
34
36
|
manifest = DebControl::ControlFileBase.parse(file_contents)
|
|
35
37
|
deps = manifest.first['constraints'].delete("\n").split(',').map(&:strip)
|
|
36
38
|
deps.map do |dependency|
|
|
@@ -18,8 +18,10 @@ module Bibliothecary
|
|
|
18
18
|
}
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
add_multi_parser(Bibliothecary::MultiParsers::CycloneDX)
|
|
22
|
+
|
|
23
|
+
def self.parse_mix(file_contents, options: {})
|
|
24
|
+
response = Typhoeus.post("#{Bibliothecary.configuration.mix_parser_host}/", body: file_contents)
|
|
23
25
|
raise Bibliothecary::RemoteParsingError.new("Http Error #{response.response_code} when contacting: #{Bibliothecary.configuration.mix_parser_host}/", response.response_code) unless response.success?
|
|
24
26
|
json = JSON.parse response.body
|
|
25
27
|
|
|
@@ -32,8 +34,8 @@ module Bibliothecary
|
|
|
32
34
|
end
|
|
33
35
|
end
|
|
34
36
|
|
|
35
|
-
def self.parse_mix_lock(
|
|
36
|
-
response = Typhoeus.post("#{Bibliothecary.configuration.mix_parser_host}/lock", body:
|
|
37
|
+
def self.parse_mix_lock(file_contents, options: {})
|
|
38
|
+
response = Typhoeus.post("#{Bibliothecary.configuration.mix_parser_host}/lock", body: file_contents)
|
|
37
39
|
raise Bibliothecary::RemoteParsingError.new("Http Error #{response.response_code} when contacting: #{Bibliothecary.configuration.mix_parser_host}/", response.response_code) unless response.success?
|
|
38
40
|
json = JSON.parse response.body
|
|
39
41
|
|
|
@@ -12,9 +12,9 @@ module Bibliothecary
|
|
|
12
12
|
}
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def self.parse_require(
|
|
15
|
+
def self.parse_require(file_contents, options: {})
|
|
16
16
|
deps = []
|
|
17
|
-
|
|
17
|
+
file_contents.split("\n").each do |line|
|
|
18
18
|
next if line.match(/^#/) || line.empty?
|
|
19
19
|
split = line.split(/\s/)
|
|
20
20
|
if line.match(/^@/)
|
|
@@ -38,12 +38,16 @@ module Bibliothecary
|
|
|
38
38
|
},
|
|
39
39
|
match_filename("pom.xml", case_insensitive: true) => {
|
|
40
40
|
kind: 'manifest',
|
|
41
|
-
parser: :
|
|
41
|
+
parser: :parse_standalone_pom_manifest
|
|
42
42
|
},
|
|
43
43
|
match_filename("build.gradle", case_insensitive: true) => {
|
|
44
44
|
kind: 'manifest',
|
|
45
45
|
parser: :parse_gradle
|
|
46
46
|
},
|
|
47
|
+
match_filename("build.gradle.kts", case_insensitive: true) => {
|
|
48
|
+
kind: 'manifest',
|
|
49
|
+
parser: :parse_gradle_kts
|
|
50
|
+
},
|
|
47
51
|
match_extension(".xml", case_insensitive: true) => {
|
|
48
52
|
content_matcher: :ivy_report?,
|
|
49
53
|
kind: 'lockfile',
|
|
@@ -68,7 +72,9 @@ module Bibliothecary
|
|
|
68
72
|
}
|
|
69
73
|
end
|
|
70
74
|
|
|
71
|
-
|
|
75
|
+
add_multi_parser Bibliothecary::MultiParsers::CycloneDX
|
|
76
|
+
|
|
77
|
+
def self.parse_ivy_manifest(file_contents, options: {})
|
|
72
78
|
manifest = Ox.parse file_contents
|
|
73
79
|
manifest.dependencies.locate('dependency').map do |dependency|
|
|
74
80
|
attrs = dependency.attributes
|
|
@@ -91,7 +97,7 @@ module Bibliothecary
|
|
|
91
97
|
false
|
|
92
98
|
end
|
|
93
99
|
|
|
94
|
-
def self.parse_ivy_report(file_contents)
|
|
100
|
+
def self.parse_ivy_report(file_contents, options: {})
|
|
95
101
|
doc = Ox.parse file_contents
|
|
96
102
|
root = doc.locate("ivy-report").first
|
|
97
103
|
raise "ivy-report document does not have ivy-report at the root" if root.nil?
|
|
@@ -116,7 +122,7 @@ module Bibliothecary
|
|
|
116
122
|
end.compact
|
|
117
123
|
end
|
|
118
124
|
|
|
119
|
-
def self.parse_gradle_resolved(file_contents)
|
|
125
|
+
def self.parse_gradle_resolved(file_contents, options: {})
|
|
120
126
|
type = nil
|
|
121
127
|
file_contents.split("\n").map do |line|
|
|
122
128
|
type_match = GRADLE_TYPE_REGEX.match(line)
|
|
@@ -147,7 +153,7 @@ module Bibliothecary
|
|
|
147
153
|
end.compact.uniq {|item| [item[:name], item[:requirement], item[:type]]}
|
|
148
154
|
end
|
|
149
155
|
|
|
150
|
-
def self.parse_maven_resolved(file_contents)
|
|
156
|
+
def self.parse_maven_resolved(file_contents, options: {})
|
|
151
157
|
Strings::ANSI.sanitize(file_contents)
|
|
152
158
|
.split("\n")
|
|
153
159
|
.map(&method(:parse_resolved_dep_line))
|
|
@@ -155,7 +161,7 @@ module Bibliothecary
|
|
|
155
161
|
.uniq
|
|
156
162
|
end
|
|
157
163
|
|
|
158
|
-
def self.parse_maven_tree(file_contents)
|
|
164
|
+
def self.parse_maven_tree(file_contents, options: {})
|
|
159
165
|
file_contents = file_contents.gsub(/\r\n?/, "\n")
|
|
160
166
|
captures = file_contents.scan(/^\[INFO\](?:(?:\+-)|\||(?:\\-)|\s)+((?:[\w\.-]+:)+[\w\.\-${}]+)/).flatten.uniq
|
|
161
167
|
|
|
@@ -191,7 +197,13 @@ module Bibliothecary
|
|
|
191
197
|
}
|
|
192
198
|
end
|
|
193
199
|
|
|
194
|
-
def self.
|
|
200
|
+
def self.parse_standalone_pom_manifest(file_contents, options: {})
|
|
201
|
+
parse_pom_manifest(file_contents, {}, options: options)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# parent_properties is used by Libraries:
|
|
205
|
+
# https://github.com/librariesio/libraries.io/blob/e970925aade2596a03268b6e1be785eba8502c62/app/models/package_manager/maven.rb#L129
|
|
206
|
+
def self.parse_pom_manifest(file_contents, parent_properties = {}, options: {})
|
|
195
207
|
manifest = Ox.parse file_contents
|
|
196
208
|
xml = manifest.respond_to?('project') ? manifest.project : manifest
|
|
197
209
|
[].tap do |deps|
|
|
@@ -207,8 +219,8 @@ module Bibliothecary
|
|
|
207
219
|
end
|
|
208
220
|
end
|
|
209
221
|
|
|
210
|
-
def self.parse_gradle(
|
|
211
|
-
response = Typhoeus.post("#{Bibliothecary.configuration.gradle_parser_host}/parse", body:
|
|
222
|
+
def self.parse_gradle(file_contents, options: {})
|
|
223
|
+
response = Typhoeus.post("#{Bibliothecary.configuration.gradle_parser_host}/parse", body: file_contents)
|
|
212
224
|
raise Bibliothecary::RemoteParsingError.new("Http Error #{response.response_code} when contacting: #{Bibliothecary.configuration.gradle_parser_host}/parse", response.response_code) unless response.success?
|
|
213
225
|
json = JSON.parse(response.body)
|
|
214
226
|
return [] unless json['dependencies']
|
|
@@ -223,6 +235,11 @@ module Bibliothecary
|
|
|
223
235
|
end.compact
|
|
224
236
|
end
|
|
225
237
|
|
|
238
|
+
def self.parse_gradle_kts(file_contents, options: {})
|
|
239
|
+
# TODO: the gradle-parser side needs to be implemented for this, coming soon.
|
|
240
|
+
[]
|
|
241
|
+
end
|
|
242
|
+
|
|
226
243
|
def self.gradle_dependency_name(group, name)
|
|
227
244
|
if group.empty? && name.include?(":")
|
|
228
245
|
group, name = name.split(":", 2)
|
|
@@ -298,7 +315,7 @@ module Bibliothecary
|
|
|
298
315
|
end
|
|
299
316
|
end
|
|
300
317
|
|
|
301
|
-
def self.parse_sbt_update_full(file_contents)
|
|
318
|
+
def self.parse_sbt_update_full(file_contents, options: {})
|
|
302
319
|
all_deps = []
|
|
303
320
|
type = nil
|
|
304
321
|
lines = file_contents.split("\n")
|