bibliothecary 7.3.4 → 8.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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")
|