bibliothecary 12.0.0 → 12.1.1
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 +2 -1
- data/.rubocop.yml +10 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +13 -0
- data/Gemfile +16 -1
- data/Rakefile +2 -0
- data/bibliothecary.gemspec +11 -13
- data/bin/bibliothecary +2 -1
- data/bin/console +1 -0
- data/lib/bibliothecary/analyser/analysis.rb +13 -8
- data/lib/bibliothecary/analyser/determinations.rb +2 -0
- data/lib/bibliothecary/analyser/matchers.rb +17 -17
- data/lib/bibliothecary/analyser.rb +11 -8
- data/lib/bibliothecary/cli.rb +3 -1
- data/lib/bibliothecary/configuration.rb +3 -8
- data/lib/bibliothecary/dependency.rb +17 -15
- data/lib/bibliothecary/exceptions.rb +6 -2
- data/lib/bibliothecary/file_info.rb +9 -11
- data/lib/bibliothecary/multi_parsers/bundler_like_manifest.rb +13 -10
- data/lib/bibliothecary/multi_parsers/cyclonedx.rb +10 -8
- data/lib/bibliothecary/multi_parsers/dependencies_csv.rb +11 -4
- data/lib/bibliothecary/multi_parsers/json_runtime.rb +5 -2
- data/lib/bibliothecary/multi_parsers/spdx.rb +24 -19
- data/lib/bibliothecary/parsers/bower.rb +5 -3
- data/lib/bibliothecary/parsers/cargo.rb +10 -4
- data/lib/bibliothecary/parsers/cocoapods.rb +15 -11
- data/lib/bibliothecary/parsers/conda.rb +20 -18
- data/lib/bibliothecary/parsers/cpan.rb +6 -4
- data/lib/bibliothecary/parsers/cran.rb +10 -6
- data/lib/bibliothecary/parsers/dub.rb +4 -2
- data/lib/bibliothecary/parsers/elm.rb +4 -1
- data/lib/bibliothecary/parsers/go.rb +51 -43
- data/lib/bibliothecary/parsers/haxelib.rb +2 -1
- data/lib/bibliothecary/parsers/julia.rb +5 -1
- data/lib/bibliothecary/parsers/maven.rb +93 -77
- data/lib/bibliothecary/parsers/meteor.rb +2 -0
- data/lib/bibliothecary/parsers/npm.rb +89 -75
- data/lib/bibliothecary/parsers/nuget.rb +37 -28
- data/lib/bibliothecary/parsers/packagist.rb +21 -11
- data/lib/bibliothecary/parsers/pub.rb +4 -2
- data/lib/bibliothecary/parsers/pypi.rb +48 -29
- data/lib/bibliothecary/parsers/rubygems.rb +16 -12
- data/lib/bibliothecary/parsers/shard.rb +10 -7
- data/lib/bibliothecary/purl_util.rb +2 -1
- data/lib/bibliothecary/related_files_info.rb +7 -8
- data/lib/bibliothecary/runner/multi_manifest_filter.rb +5 -4
- data/lib/bibliothecary/runner.rb +13 -10
- data/lib/bibliothecary/version.rb +3 -1
- data/lib/bibliothecary.rb +7 -4
- data/lib/sdl_parser.rb +11 -6
- metadata +19 -106
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# packageurl-ruby uses pattern-matching (https://docs.ruby-lang.org/en/2.7.0/NEWS.html#label-Pattern+matching)
|
2
4
|
# which warns a whole bunch in Ruby 2.7 as being an experimental feature, but has
|
3
5
|
# been accepted in Ruby 3.0 (https://rubyreferences.github.io/rubychanges/3.0.html#pattern-matching).
|
@@ -43,7 +45,7 @@ module Bibliothecary
|
|
43
45
|
|
44
46
|
def parse_spdx_tag_value(file_contents, options: {})
|
45
47
|
entries = try_cache(options, options[:filename]) do
|
46
|
-
parse_spdx_tag_value_file_contents(file_contents)
|
48
|
+
parse_spdx_tag_value_file_contents(file_contents, options.fetch(:filename, nil))
|
47
49
|
end
|
48
50
|
|
49
51
|
raise NoEntries if entries.empty?
|
@@ -51,7 +53,7 @@ module Bibliothecary
|
|
51
53
|
entries[platform_name.to_sym]
|
52
54
|
end
|
53
55
|
|
54
|
-
def parse_spdx_tag_value_file_contents(file_contents)
|
56
|
+
def parse_spdx_tag_value_file_contents(file_contents, source = nil)
|
55
57
|
entries = {}
|
56
58
|
spdx_name = spdx_version = platform = purl_name = purl_version = nil
|
57
59
|
|
@@ -65,13 +67,14 @@ module Bibliothecary
|
|
65
67
|
# Per the spec:
|
66
68
|
# > A new package Information section is denoted by the package name (7.1) field.
|
67
69
|
add_entry(entries: entries, platform: platform, purl_name: purl_name,
|
68
|
-
spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version
|
70
|
+
spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version,
|
71
|
+
source: source)
|
69
72
|
|
70
73
|
# reset for this new package
|
71
74
|
spdx_name = spdx_version = platform = purl_name = purl_version = nil
|
72
75
|
|
73
76
|
# capture the new package's name
|
74
|
-
|
77
|
+
spdx_name = match[1]
|
75
78
|
elsif (match = stripped_line.match(PACKAGE_VERSION_REGEXP))
|
76
79
|
spdx_version = match[1]
|
77
80
|
elsif (match = stripped_line.match(PURL_REGEXP))
|
@@ -83,7 +86,8 @@ module Bibliothecary
|
|
83
86
|
end
|
84
87
|
|
85
88
|
add_entry(entries: entries, platform: platform, purl_name: purl_name,
|
86
|
-
spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version
|
89
|
+
spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version,
|
90
|
+
source: source)
|
87
91
|
|
88
92
|
entries
|
89
93
|
end
|
@@ -95,7 +99,7 @@ module Bibliothecary
|
|
95
99
|
|
96
100
|
def parse_spdx_json(file_contents, options: {})
|
97
101
|
entries = try_cache(options, options[:filename]) do
|
98
|
-
parse_spdx_json_file_contents(file_contents)
|
102
|
+
parse_spdx_json_file_contents(file_contents, options.fetch(:filename, nil))
|
99
103
|
end
|
100
104
|
|
101
105
|
raise NoEntries if entries.empty?
|
@@ -103,7 +107,7 @@ module Bibliothecary
|
|
103
107
|
entries[platform_name.to_sym]
|
104
108
|
end
|
105
109
|
|
106
|
-
def parse_spdx_json_file_contents(file_contents)
|
110
|
+
def parse_spdx_json_file_contents(file_contents, source = nil)
|
107
111
|
entries = {}
|
108
112
|
manifest = JSON.parse(file_contents)
|
109
113
|
|
@@ -111,33 +115,34 @@ module Bibliothecary
|
|
111
115
|
spdx_name = package["name"]
|
112
116
|
spdx_version = package["versionInfo"]
|
113
117
|
|
114
|
-
first_purl_string = package
|
118
|
+
first_purl_string = package["externalRefs"]&.find { |ref| ref["referenceType"] == "purl" }&.dig("referenceLocator")
|
115
119
|
purl = first_purl_string && PackageURL.parse(first_purl_string)
|
116
120
|
platform = PurlUtil::PURL_TYPE_MAPPING[purl&.type]
|
117
121
|
purl_name = PurlUtil.full_name(purl)
|
118
122
|
purl_version = purl&.version
|
119
123
|
|
120
124
|
add_entry(entries: entries, platform: platform, purl_name: purl_name,
|
121
|
-
spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version
|
125
|
+
spdx_name: spdx_name, purl_version: purl_version, spdx_version: spdx_version,
|
126
|
+
source: source)
|
122
127
|
end
|
123
128
|
|
124
129
|
entries
|
125
130
|
end
|
126
131
|
|
127
|
-
def add_entry(entries:, platform:, purl_name:, spdx_name:, purl_version:, spdx_version:)
|
132
|
+
def add_entry(entries:, platform:, purl_name:, spdx_name:, purl_version:, spdx_version:, source: nil)
|
128
133
|
package_name = purl_name || spdx_name
|
129
134
|
package_version = purl_version || spdx_version
|
130
135
|
|
131
|
-
|
132
|
-
entries[platform.to_sym] ||= []
|
133
|
-
entries[platform.to_sym] << Dependency.new(
|
134
|
-
name: package_name,
|
135
|
-
requirement: package_version,
|
136
|
-
type: "lockfile"
|
137
|
-
)
|
138
|
-
end
|
139
|
-
end
|
136
|
+
return unless platform && package_name && package_version
|
140
137
|
|
138
|
+
entries[platform.to_sym] ||= []
|
139
|
+
entries[platform.to_sym] << Dependency.new(
|
140
|
+
name: package_name,
|
141
|
+
requirement: package_version,
|
142
|
+
type: "lockfile",
|
143
|
+
source: source
|
144
|
+
)
|
145
|
+
end
|
141
146
|
end
|
142
147
|
end
|
143
148
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "json"
|
2
4
|
|
3
5
|
module Bibliothecary
|
@@ -16,10 +18,10 @@ module Bibliothecary
|
|
16
18
|
|
17
19
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
18
20
|
|
19
|
-
def self.parse_manifest(file_contents, options: {})
|
21
|
+
def self.parse_manifest(file_contents, options: {})
|
20
22
|
json = JSON.parse(file_contents)
|
21
|
-
map_dependencies(json, "dependencies", "runtime") +
|
22
|
-
|
23
|
+
map_dependencies(json, "dependencies", "runtime", options.fetch(:filename, nil)) +
|
24
|
+
map_dependencies(json, "devDependencies", "development", options.fetch(:filename, nil))
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Bibliothecary
|
2
4
|
module Parsers
|
3
5
|
class Cargo
|
@@ -20,7 +22,7 @@ module Bibliothecary
|
|
20
22
|
add_multi_parser(Bibliothecary::MultiParsers::Spdx)
|
21
23
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
22
24
|
|
23
|
-
def self.parse_manifest(file_contents, options: {})
|
25
|
+
def self.parse_manifest(file_contents, options: {})
|
24
26
|
manifest = Tomlrb.parse(file_contents)
|
25
27
|
|
26
28
|
parsed_dependencies = []
|
@@ -30,10 +32,12 @@ module Bibliothecary
|
|
30
32
|
if requirement.respond_to?(:fetch)
|
31
33
|
requirement = requirement["version"] or next
|
32
34
|
end
|
35
|
+
|
33
36
|
Dependency.new(
|
34
37
|
name: name,
|
35
38
|
requirement: requirement,
|
36
39
|
type: index.zero? ? "runtime" : "development",
|
40
|
+
source: options.fetch(:filename, nil)
|
37
41
|
)
|
38
42
|
end
|
39
43
|
end
|
@@ -41,14 +45,16 @@ module Bibliothecary
|
|
41
45
|
parsed_dependencies.flatten.compact
|
42
46
|
end
|
43
47
|
|
44
|
-
def self.parse_lockfile(file_contents, options: {})
|
48
|
+
def self.parse_lockfile(file_contents, options: {})
|
45
49
|
manifest = Tomlrb.parse(file_contents)
|
46
|
-
manifest.fetch("package",[]).map do |dependency|
|
47
|
-
next if
|
50
|
+
manifest.fetch("package", []).map do |dependency|
|
51
|
+
next if !dependency["source"] || !dependency["source"].start_with?("registry+")
|
52
|
+
|
48
53
|
Dependency.new(
|
49
54
|
name: dependency["name"],
|
50
55
|
requirement: dependency["version"],
|
51
56
|
type: "runtime",
|
57
|
+
source: options.fetch(:filename, nil)
|
52
58
|
)
|
53
59
|
end
|
54
60
|
.compact
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemnasium/parser"
|
2
4
|
require "yaml"
|
3
5
|
|
@@ -7,7 +9,7 @@ module Bibliothecary
|
|
7
9
|
include Bibliothecary::Analyser
|
8
10
|
extend Bibliothecary::MultiParsers::BundlerLikeManifest
|
9
11
|
|
10
|
-
NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'
|
12
|
+
NAME_VERSION = '(?! )(.*?)(?: \(([^-]*)(?:-(.*))?\))?'
|
11
13
|
NAME_VERSION_4 = /^ {4}#{NAME_VERSION}$/
|
12
14
|
|
13
15
|
def self.mapping
|
@@ -35,7 +37,7 @@ module Bibliothecary
|
|
35
37
|
|
36
38
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
37
39
|
|
38
|
-
def self.parse_podfile_lock(file_contents, options: {})
|
40
|
+
def self.parse_podfile_lock(file_contents, options: {})
|
39
41
|
manifest = YAML.load file_contents
|
40
42
|
manifest["PODS"].map do |row|
|
41
43
|
pod = row.is_a?(String) ? row : row.keys.first
|
@@ -44,28 +46,30 @@ module Bibliothecary
|
|
44
46
|
name: match[1].split("/").first,
|
45
47
|
requirement: match[2],
|
46
48
|
type: "runtime",
|
49
|
+
source: options.fetch(:filename, nil)
|
47
50
|
)
|
48
51
|
end.compact
|
49
52
|
end
|
50
53
|
|
51
|
-
def self.parse_podspec(file_contents, options: {})
|
54
|
+
def self.parse_podspec(file_contents, options: {})
|
52
55
|
manifest = Gemnasium::Parser.send(:podspec, file_contents)
|
53
|
-
parse_ruby_manifest(manifest)
|
56
|
+
parse_ruby_manifest(manifest, options.fetch(:filename, nil))
|
54
57
|
end
|
55
58
|
|
56
|
-
def self.parse_podfile(file_contents, options: {})
|
59
|
+
def self.parse_podfile(file_contents, options: {})
|
57
60
|
manifest = Gemnasium::Parser.send(:podfile, file_contents)
|
58
|
-
parse_ruby_manifest(manifest)
|
61
|
+
parse_ruby_manifest(manifest, options.fetch(:filename, nil))
|
59
62
|
end
|
60
63
|
|
61
|
-
def self.parse_json_manifest(file_contents, options: {})
|
64
|
+
def self.parse_json_manifest(file_contents, options: {})
|
62
65
|
manifest = JSON.parse(file_contents)
|
63
66
|
manifest["dependencies"].inject([]) do |deps, dep|
|
64
67
|
deps.push(Dependency.new(
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
68
|
+
name: dep[0],
|
69
|
+
requirement: dep[1],
|
70
|
+
type: "runtime",
|
71
|
+
source: options.fetch(:filename, nil)
|
72
|
+
))
|
69
73
|
end.uniq
|
70
74
|
end
|
71
75
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "yaml"
|
2
4
|
|
3
5
|
module Bibliothecary
|
@@ -22,39 +24,39 @@ module Bibliothecary
|
|
22
24
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
23
25
|
add_multi_parser(Bibliothecary::MultiParsers::Spdx)
|
24
26
|
|
25
|
-
def self.parse_conda(file_contents, options: {})
|
27
|
+
def self.parse_conda(file_contents, options: {})
|
26
28
|
manifest = YAML.load(file_contents)
|
27
|
-
deps = manifest
|
29
|
+
deps = manifest["dependencies"]
|
28
30
|
deps.map do |dep|
|
29
31
|
next unless dep.is_a? String # only deal with strings to skip parsing pip stuff
|
30
32
|
|
31
33
|
parsed = parse_name_requirement_from_matchspec(dep)
|
32
|
-
Dependency.new(**parsed
|
34
|
+
Dependency.new(**parsed, type: "runtime", source: options.fetch(:filename, nil))
|
33
35
|
end.compact
|
34
36
|
end
|
35
37
|
|
36
|
-
def self.parse_name_requirement_from_matchspec(
|
38
|
+
def self.parse_name_requirement_from_matchspec(matchspec)
|
37
39
|
# simplified version of the implementation in conda to handle what we care about
|
38
40
|
# https://github.com/conda/conda/blob/main/conda/models/match_spec.py#L598
|
39
41
|
# (channel(/subdir):(namespace):)name(version(build))[key1=value1,key2=value2]
|
40
|
-
return if
|
42
|
+
return if matchspec.end_with?("@")
|
41
43
|
|
42
44
|
# strip off comments and optional features
|
43
|
-
|
44
|
-
|
45
|
+
matchspec = matchspec.split("#", 2).first
|
46
|
+
matchspec = matchspec.split(" if ", 2).first
|
45
47
|
|
46
48
|
# strip off brackets
|
47
|
-
|
49
|
+
matchspec = matchspec.match(/^(.*)(?:\[(.*)\])?$/)[1]
|
48
50
|
|
49
51
|
# strip off any parens
|
50
|
-
|
52
|
+
matchspec = matchspec.match(/^(.*)(?:(\(.*\)))?$/)[1]
|
51
53
|
|
52
54
|
# deal with channel and namespace, I wish there was rsplit in ruby
|
53
|
-
split =
|
54
|
-
|
55
|
+
split = matchspec.reverse.split(":", 2)
|
56
|
+
matchspec = split.last.reverse
|
55
57
|
|
56
58
|
# split the name from the version/build combo
|
57
|
-
matches =
|
59
|
+
matches = matchspec.match(/([^ =<>!~]+)?([><!=~ ].+)?/)
|
58
60
|
name = matches[1]
|
59
61
|
version_build = matches[2]
|
60
62
|
|
@@ -64,19 +66,19 @@ module Bibliothecary
|
|
64
66
|
# and now deal with getting the version from version/build
|
65
67
|
matches = version_build.match(/((?:.+?)[^><!,|]?)(?:(?<![=!|,<>~])(?:[ =])([^-=,|<>~]+?))?$/)
|
66
68
|
version = if matches
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
69
|
+
matches[1].strip
|
70
|
+
else
|
71
|
+
version_build.strip
|
72
|
+
end
|
71
73
|
end
|
72
74
|
# if it's an exact requirement, lose the =
|
73
75
|
if version&.start_with?("==")
|
74
76
|
version = version[2..]
|
75
77
|
elsif version&.start_with?("=")
|
76
|
-
|
78
|
+
version = version[1..]
|
77
79
|
end
|
78
80
|
|
79
|
-
|
81
|
+
{
|
80
82
|
name: name,
|
81
83
|
requirement: version || "", # NOTE: this ignores build info
|
82
84
|
}
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "yaml"
|
2
4
|
require "json"
|
3
5
|
|
@@ -21,16 +23,16 @@ module Bibliothecary
|
|
21
23
|
|
22
24
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
23
25
|
|
24
|
-
def self.parse_json_manifest(file_contents, options: {})
|
26
|
+
def self.parse_json_manifest(file_contents, options: {})
|
25
27
|
manifest = JSON.parse file_contents
|
26
28
|
manifest["prereqs"].map do |_group, deps|
|
27
|
-
map_dependencies(deps, "requires", "runtime")
|
29
|
+
map_dependencies(deps, "requires", "runtime", options.fetch(:filename, nil))
|
28
30
|
end.flatten
|
29
31
|
end
|
30
32
|
|
31
|
-
def self.parse_yaml_manifest(file_contents, options: {})
|
33
|
+
def self.parse_yaml_manifest(file_contents, options: {})
|
32
34
|
manifest = YAML.load file_contents
|
33
|
-
map_dependencies(manifest, "requires", "runtime")
|
35
|
+
map_dependencies(manifest, "requires", "runtime", options.fetch(:filename, nil))
|
34
36
|
end
|
35
37
|
end
|
36
38
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "deb_control"
|
2
4
|
|
3
5
|
module Bibliothecary
|
@@ -20,16 +22,17 @@ module Bibliothecary
|
|
20
22
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
21
23
|
add_multi_parser(Bibliothecary::MultiParsers::Spdx)
|
22
24
|
|
23
|
-
def self.parse_description(file_contents, options: {})
|
25
|
+
def self.parse_description(file_contents, options: {})
|
24
26
|
manifest = DebControl::ControlFileBase.parse(file_contents)
|
25
|
-
parse_section(manifest, "Depends") +
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
parse_section(manifest, "Depends", options.fetch(:filename, nil)) +
|
28
|
+
parse_section(manifest, "Imports", options.fetch(:filename, nil)) +
|
29
|
+
parse_section(manifest, "Suggests", options.fetch(:filename, nil)) +
|
30
|
+
parse_section(manifest, "Enhances", options.fetch(:filename, nil))
|
29
31
|
end
|
30
32
|
|
31
|
-
def self.parse_section(manifest, name)
|
33
|
+
def self.parse_section(manifest, name, source = nil)
|
32
34
|
return [] unless manifest.first[name]
|
35
|
+
|
33
36
|
deps = manifest.first[name].delete("\n").split(",").map(&:strip)
|
34
37
|
deps.map do |dependency|
|
35
38
|
dep = dependency.match(REQUIRE_REGEXP)
|
@@ -37,6 +40,7 @@ module Bibliothecary
|
|
37
40
|
name: dep[1],
|
38
41
|
requirement: dep[2],
|
39
42
|
type: name.downcase,
|
43
|
+
source: source
|
40
44
|
)
|
41
45
|
end
|
42
46
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "json"
|
2
4
|
require "sdl_parser"
|
3
5
|
|
@@ -22,8 +24,8 @@ module Bibliothecary
|
|
22
24
|
|
23
25
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
24
26
|
|
25
|
-
def self.parse_sdl_manifest(file_contents, options: {})
|
26
|
-
SdlParser.new(:runtime, file_contents).dependencies
|
27
|
+
def self.parse_sdl_manifest(file_contents, options: {})
|
28
|
+
SdlParser.new(:runtime, file_contents, options.fetch(:filename, nil)).dependencies
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "json"
|
2
4
|
|
3
5
|
module Bibliothecary
|
@@ -21,13 +23,14 @@ module Bibliothecary
|
|
21
23
|
|
22
24
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
23
25
|
|
24
|
-
def self.parse_json_lock(file_contents, options: {})
|
26
|
+
def self.parse_json_lock(file_contents, options: {})
|
25
27
|
manifest = JSON.parse file_contents
|
26
28
|
manifest.map do |name, requirement|
|
27
29
|
Dependency.new(
|
28
30
|
name: name,
|
29
31
|
requirement: requirement,
|
30
32
|
type: "runtime",
|
33
|
+
source: options.fetch(:filename, nil)
|
31
34
|
)
|
32
35
|
end
|
33
36
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "yaml"
|
2
4
|
require "json"
|
3
5
|
|
@@ -74,60 +76,63 @@ module Bibliothecary
|
|
74
76
|
add_multi_parser(Bibliothecary::MultiParsers::Spdx)
|
75
77
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
76
78
|
|
77
|
-
def self.parse_godep_json(file_contents, options: {})
|
79
|
+
def self.parse_godep_json(file_contents, options: {})
|
78
80
|
manifest = JSON.parse file_contents
|
79
|
-
map_dependencies(manifest, "Deps", "ImportPath", "Rev", "runtime")
|
81
|
+
map_dependencies(manifest, "Deps", "ImportPath", "Rev", "runtime", options.fetch(:filename, nil))
|
80
82
|
end
|
81
83
|
|
82
|
-
def self.parse_gpm(file_contents, options: {})
|
84
|
+
def self.parse_gpm(file_contents, options: {})
|
83
85
|
deps = []
|
84
86
|
file_contents.split("\n").each do |line|
|
85
87
|
match = line.gsub(/(\#(.*))/, "").match(GPM_REGEXP)
|
86
88
|
next unless match
|
89
|
+
|
87
90
|
deps << Dependency.new(
|
88
91
|
name: match[1].strip,
|
89
92
|
requirement: match[2].strip,
|
90
93
|
type: "runtime",
|
94
|
+
source: options.fetch(:filename, nil)
|
91
95
|
)
|
92
96
|
end
|
93
97
|
deps
|
94
98
|
end
|
95
99
|
|
96
|
-
def self.parse_govendor(file_contents, options: {})
|
97
|
-
manifest = JSON.
|
98
|
-
map_dependencies(manifest, "package", "path", "revision", "runtime")
|
100
|
+
def self.parse_govendor(file_contents, options: {})
|
101
|
+
manifest = JSON.parse file_contents
|
102
|
+
map_dependencies(manifest, "package", "path", "revision", "runtime", options.fetch(:filename, nil))
|
99
103
|
end
|
100
104
|
|
101
|
-
def self.parse_glide_yaml(file_contents, options: {})
|
105
|
+
def self.parse_glide_yaml(file_contents, options: {})
|
102
106
|
manifest = YAML.load file_contents
|
103
|
-
map_dependencies(manifest, "import", "package", "version", "runtime") +
|
104
|
-
|
107
|
+
map_dependencies(manifest, "import", "package", "version", "runtime", options.fetch(:filename, nil)) +
|
108
|
+
map_dependencies(manifest, "devImports", "package", "version", "development", options.fetch(:filename, nil))
|
105
109
|
end
|
106
110
|
|
107
|
-
def self.parse_glide_lockfile(file_contents, options: {})
|
108
|
-
|
109
|
-
|
111
|
+
def self.parse_glide_lockfile(file_contents, options: {})
|
112
|
+
# glide.lock files contain an "updated" Time field, but Ruby 3.2+ requires us to safelist that class
|
113
|
+
manifest = YAML.load file_contents, permitted_classes: [Time]
|
114
|
+
map_dependencies(manifest, "imports", "name", "version", "runtime", options.fetch(:filename, nil))
|
110
115
|
end
|
111
116
|
|
112
|
-
def self.parse_gb_manifest(file_contents, options: {})
|
117
|
+
def self.parse_gb_manifest(file_contents, options: {})
|
113
118
|
manifest = JSON.parse file_contents
|
114
|
-
map_dependencies(manifest, "dependencies", "importpath", "revision", "runtime")
|
119
|
+
map_dependencies(manifest, "dependencies", "importpath", "revision", "runtime", options.fetch(:filename, nil))
|
115
120
|
end
|
116
121
|
|
117
|
-
def self.parse_dep_toml(file_contents, options: {})
|
122
|
+
def self.parse_dep_toml(file_contents, options: {})
|
118
123
|
manifest = Tomlrb.parse file_contents
|
119
|
-
map_dependencies(manifest, "constraint", "name", "version", "runtime")
|
124
|
+
map_dependencies(manifest, "constraint", "name", "version", "runtime", options.fetch(:filename, nil))
|
120
125
|
end
|
121
126
|
|
122
|
-
def self.parse_dep_lockfile(file_contents, options: {})
|
127
|
+
def self.parse_dep_lockfile(file_contents, options: {})
|
123
128
|
manifest = Tomlrb.parse file_contents
|
124
|
-
map_dependencies(manifest, "projects", "name", "revision", "runtime")
|
129
|
+
map_dependencies(manifest, "projects", "name", "revision", "runtime", options.fetch(:filename, nil))
|
125
130
|
end
|
126
131
|
|
127
|
-
def self.parse_go_mod(file_contents, options: {})
|
128
|
-
categorized_deps = parse_go_mod_categorized_deps(file_contents)
|
132
|
+
def self.parse_go_mod(file_contents, options: {})
|
133
|
+
categorized_deps = parse_go_mod_categorized_deps(file_contents, options.fetch(:filename, nil))
|
129
134
|
|
130
|
-
|
135
|
+
categorized_deps["require"]
|
131
136
|
.map do |dep|
|
132
137
|
# NOTE: A "replace" directive doesn't add the dep to the module graph unless the original dep is also in a "require" directive,
|
133
138
|
# so we need to track down replacements here and use those instead of the originals, if present.
|
@@ -143,11 +148,9 @@ module Bibliothecary
|
|
143
148
|
|
144
149
|
replaced_dep || dep
|
145
150
|
end
|
146
|
-
|
147
|
-
return deps
|
148
151
|
end
|
149
152
|
|
150
|
-
def self.parse_go_mod_categorized_deps(file_contents)
|
153
|
+
def self.parse_go_mod_categorized_deps(file_contents, source)
|
151
154
|
current_multiline_category = nil
|
152
155
|
# docs: https://go.dev/ref/mod#go-mod-file-require
|
153
156
|
categorized_deps = {
|
@@ -159,38 +162,39 @@ module Bibliothecary
|
|
159
162
|
file_contents
|
160
163
|
.lines
|
161
164
|
.map(&:strip)
|
162
|
-
.
|
165
|
+
.grep_v(/^#{GOMOD_COMMENT_REGEXP}/) # ignore comment lines
|
163
166
|
.each do |line|
|
164
167
|
if line.match(GOMOD_MULTILINE_END_REGEXP) # detect the end of a multiline
|
165
168
|
current_multiline_category = nil
|
166
169
|
elsif (match = line.match(GOMOD_MULTILINE_START_REGEXP)) # or, detect the start of a multiline
|
167
170
|
current_multiline_category = match[1]
|
168
171
|
elsif (match = line.match(GOMOD_SINGLELINE_DEP_REGEXP)) # or, detect a singleline dep
|
169
|
-
categorized_deps[match[:category]] << go_mod_category_relative_dep(category: match[:category], line: line, match: match)
|
170
|
-
elsif
|
171
|
-
categorized_deps[current_multiline_category] << go_mod_category_relative_dep(category: current_multiline_category, line: line, match: match)
|
172
|
+
categorized_deps[match[:category]] << go_mod_category_relative_dep(category: match[:category], line: line, match: match, source: source)
|
173
|
+
elsif current_multiline_category && (match = line.match(GOMOD_MULTILINE_DEP_REGEXP)) # otherwise, parse the multiline dep
|
174
|
+
categorized_deps[current_multiline_category] << go_mod_category_relative_dep(category: current_multiline_category, line: line, match: match, source: source)
|
172
175
|
end
|
173
176
|
end
|
174
177
|
categorized_deps
|
175
178
|
end
|
176
179
|
|
177
|
-
def self.parse_go_sum(file_contents, options: {})
|
180
|
+
def self.parse_go_sum(file_contents, options: {})
|
178
181
|
deps = []
|
179
182
|
file_contents.lines.map(&:strip).each do |line|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
183
|
+
next unless (match = line.match(GOSUM_REGEXP))
|
184
|
+
|
185
|
+
deps << Dependency.new(
|
186
|
+
name: match[1].strip,
|
187
|
+
requirement: match[2].strip.split("/").first,
|
188
|
+
type: "runtime",
|
189
|
+
source: options.fetch(:filename, nil)
|
190
|
+
)
|
187
191
|
end
|
188
192
|
deps.uniq
|
189
193
|
end
|
190
194
|
|
191
|
-
def self.parse_go_resolved(file_contents, options: {})
|
195
|
+
def self.parse_go_resolved(file_contents, options: {})
|
192
196
|
JSON.parse(file_contents)
|
193
|
-
.
|
197
|
+
.reject { |dep| dep["Main"] == "true" }
|
194
198
|
.map do |dep|
|
195
199
|
if dep["Replace"].is_a?(String) && dep["Replace"] != "<nil>" && dep["Replace"] != ""
|
196
200
|
# NOTE: The "replace" directive doesn't actually change the version reported from Go (e.g. "go mod graph"), it only changes
|
@@ -199,28 +203,29 @@ module Bibliothecary
|
|
199
203
|
name, requirement = dep["Replace"].split(" ", 2)
|
200
204
|
requirement = "*" if requirement.to_s.strip == ""
|
201
205
|
Dependency.new(
|
202
|
-
name: name, requirement: requirement, original_name: dep["Path"], original_requirement: dep["Version"], type: dep.fetch("Scope"
|
206
|
+
name: name, requirement: requirement, original_name: dep["Path"], original_requirement: dep["Version"], type: dep.fetch("Scope", "runtime"), source: options.fetch(:filename, nil)
|
203
207
|
)
|
204
208
|
else
|
205
209
|
Dependency.new(
|
206
|
-
name: dep["Path"], requirement: dep["Version"], type: dep.fetch("Scope"
|
210
|
+
name: dep["Path"], requirement: dep["Version"], type: dep.fetch("Scope", "runtime"), source: options.fetch(:filename, nil)
|
207
211
|
)
|
208
212
|
end
|
209
213
|
end
|
210
214
|
end
|
211
215
|
|
212
|
-
def self.map_dependencies(manifest, attr_name, dep_attr_name, version_attr_name, type)
|
213
|
-
manifest.fetch(attr_name,[]).map do |dependency|
|
216
|
+
def self.map_dependencies(manifest, attr_name, dep_attr_name, version_attr_name, type, source = nil)
|
217
|
+
manifest.fetch(attr_name, []).map do |dependency|
|
214
218
|
Dependency.new(
|
215
219
|
name: dependency[dep_attr_name],
|
216
220
|
requirement: dependency[version_attr_name],
|
217
221
|
type: type,
|
222
|
+
source: source
|
218
223
|
)
|
219
224
|
end
|
220
225
|
end
|
221
226
|
|
222
227
|
# Returns our standard-ish dep Hash based on the category of dep matched ("require", "replace", etc.)
|
223
|
-
def self.go_mod_category_relative_dep(category:, line:, match:)
|
228
|
+
def self.go_mod_category_relative_dep(category:, line:, match:, source: nil)
|
224
229
|
case category
|
225
230
|
when "replace"
|
226
231
|
replacement_dep = line.split(GOMOD_REPLACEMENT_SEPARATOR_REGEXP, 2).last
|
@@ -232,6 +237,7 @@ module Bibliothecary
|
|
232
237
|
requirement: replacement_match[:requirement],
|
233
238
|
type: "runtime",
|
234
239
|
direct: !match[:indirect],
|
240
|
+
source: source
|
235
241
|
)
|
236
242
|
when "retract"
|
237
243
|
Dependency.new(
|
@@ -240,6 +246,7 @@ module Bibliothecary
|
|
240
246
|
type: "runtime",
|
241
247
|
deprecated: true,
|
242
248
|
direct: !match[:indirect],
|
249
|
+
source: source
|
243
250
|
)
|
244
251
|
else
|
245
252
|
Dependency.new(
|
@@ -247,6 +254,7 @@ module Bibliothecary
|
|
247
254
|
requirement: match[:requirement],
|
248
255
|
type: "runtime",
|
249
256
|
direct: !match[:indirect],
|
257
|
+
source: source
|
250
258
|
)
|
251
259
|
end
|
252
260
|
end
|