bibliothecary 12.0.0 → 12.1.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 +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 +12 -10
- data/lib/bibliothecary/version.rb +3 -1
- data/lib/bibliothecary.rb +7 -4
- data/lib/sdl_parser.rb +11 -6
- metadata +18 -101
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Bibliothecary
|
2
4
|
module Parsers
|
3
5
|
class Julia
|
@@ -14,10 +16,11 @@ module Bibliothecary
|
|
14
16
|
|
15
17
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
16
18
|
|
17
|
-
def self.parse_require(file_contents, options: {})
|
19
|
+
def self.parse_require(file_contents, options: {})
|
18
20
|
deps = []
|
19
21
|
file_contents.split("\n").each do |line|
|
20
22
|
next if line.match(/^#/) || line.empty?
|
23
|
+
|
21
24
|
split = line.split(/\s/)
|
22
25
|
if line.match(/^@/)
|
23
26
|
name = split[1]
|
@@ -33,6 +36,7 @@ module Bibliothecary
|
|
33
36
|
name: name,
|
34
37
|
requirement: reqs,
|
35
38
|
type: "runtime",
|
39
|
+
source: options.fetch(:filename, nil)
|
36
40
|
)
|
37
41
|
end
|
38
42
|
deps
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "ox"
|
2
4
|
|
3
5
|
# Known shortcomings and unimplemented Maven features:
|
@@ -26,7 +28,7 @@ module Bibliothecary
|
|
26
28
|
|
27
29
|
# Builtin methods: https://docs.gradle.org/current/userguide/java_plugin.html#tab:configurations
|
28
30
|
# Deprecated methods: https://docs.gradle.org/current/userguide/upgrading_version_6.html#sec:configuration_removal
|
29
|
-
GRADLE_DEPENDENCY_METHODS = %w
|
31
|
+
GRADLE_DEPENDENCY_METHODS = %w[api compile compileClasspath compileOnly compileOnlyApi implementation runtime runtimeClasspath runtimeOnly testCompile testCompileOnly testImplementation testRuntime testRuntimeOnly].freeze
|
30
32
|
|
31
33
|
# Intentionally overly-simplified regexes to scrape deps from build.gradle (Groovy) and build.gradle.kts (Kotlin) files.
|
32
34
|
# To be truly useful bibliothecary would need full Groovy / Kotlin parsers that speaks Gradle,
|
@@ -34,7 +36,7 @@ module Bibliothecary
|
|
34
36
|
GRADLE_VERSION_REGEXP = /[\w.-]+/ # e.g. '1.2.3'
|
35
37
|
GRADLE_VAR_INTERPOLATION_REGEXP = /\$\w+/ # e.g. '$myVersion'
|
36
38
|
GRADLE_CODE_INTERPOLATION_REGEXP = /\$\{.*\}/ # e.g. '${my-project-settings["version"]}'
|
37
|
-
GRADLE_GAV_REGEXP = /([\w.-]+)
|
39
|
+
GRADLE_GAV_REGEXP = /([\w.-]+):([\w.-]+)(?::(#{GRADLE_VERSION_REGEXP}|#{GRADLE_VAR_INTERPOLATION_REGEXP}|#{GRADLE_CODE_INTERPOLATION_REGEXP}))?/ # e.g. "group:artifactId:1.2.3"
|
38
40
|
GRADLE_GROOVY_SIMPLE_REGEXP = /(#{GRADLE_DEPENDENCY_METHODS.join('|')})\s*\(?\s*['"]#{GRADLE_GAV_REGEXP}['"]/m
|
39
41
|
GRADLE_KOTLIN_SIMPLE_REGEXP = /(#{GRADLE_DEPENDENCY_METHODS.join('|')})\s*\(\s*"#{GRADLE_GAV_REGEXP}"/m
|
40
42
|
|
@@ -56,7 +58,6 @@ module Bibliothecary
|
|
56
58
|
# e.g. "[info] "
|
57
59
|
SBT_IGNORE_REGEXP = /^\[info\]\s*$/
|
58
60
|
|
59
|
-
|
60
61
|
# Copied from the "strings-ansi" gem, because it seems abandoned: https://github.com/piotrmurach/strings-ansi/pull/2
|
61
62
|
# From: https://github.com/piotrmurach/strings-ansi/blob/35d0c9430cf0a8022dc12bdab005bce296cb9f00/lib/strings/ansi.rb#L14-L29
|
62
63
|
# License: MIT
|
@@ -75,8 +76,8 @@ module Bibliothecary
|
|
75
76
|
|
|
76
77
|
\]8;[^;]*;.*?(\033\\|\07) # hyperlink
|
77
78
|
))
|
78
|
-
}x
|
79
|
-
|
79
|
+
}x
|
80
|
+
|
80
81
|
def self.mapping
|
81
82
|
{
|
82
83
|
match_filename("ivy.xml", case_insensitive: true) => {
|
@@ -123,7 +124,7 @@ module Bibliothecary
|
|
123
124
|
add_multi_parser(Bibliothecary::MultiParsers::Spdx)
|
124
125
|
add_multi_parser(Bibliothecary::MultiParsers::DependenciesCSV)
|
125
126
|
|
126
|
-
def self.parse_ivy_manifest(file_contents, options: {})
|
127
|
+
def self.parse_ivy_manifest(file_contents, options: {})
|
127
128
|
manifest = Ox.parse file_contents
|
128
129
|
manifest.dependencies.locate("dependency").map do |dependency|
|
129
130
|
attrs = dependency.attributes
|
@@ -131,6 +132,7 @@ module Bibliothecary
|
|
131
132
|
name: "#{attrs[:org]}:#{attrs[:name]}",
|
132
133
|
requirement: attrs[:rev],
|
133
134
|
type: "runtime",
|
135
|
+
source: options.fetch(:filename, nil)
|
134
136
|
)
|
135
137
|
end
|
136
138
|
end
|
@@ -138,7 +140,7 @@ module Bibliothecary
|
|
138
140
|
def self.ivy_report?(file_contents)
|
139
141
|
doc = Ox.parse file_contents
|
140
142
|
root = doc&.locate("ivy-report")&.first
|
141
|
-
|
143
|
+
!root.nil?
|
142
144
|
rescue Exception # rubocop:disable Lint/RescueException
|
143
145
|
# We rescue exception here since native libs can throw a non-StandardError
|
144
146
|
# We don't want to throw errors during the matching phase, only during
|
@@ -146,12 +148,14 @@ module Bibliothecary
|
|
146
148
|
false
|
147
149
|
end
|
148
150
|
|
149
|
-
def self.parse_ivy_report(file_contents, options: {})
|
151
|
+
def self.parse_ivy_report(file_contents, options: {})
|
150
152
|
doc = Ox.parse file_contents
|
151
153
|
root = doc.locate("ivy-report").first
|
152
154
|
raise "ivy-report document does not have ivy-report at the root" if root.nil?
|
155
|
+
|
153
156
|
info = doc.locate("ivy-report/info").first
|
154
157
|
raise "ivy-report document lacks <info> element" if info.nil?
|
158
|
+
|
155
159
|
type = info.attributes[:conf]
|
156
160
|
type = "unknown" if type.nil?
|
157
161
|
modules = doc.locate("ivy-report/dependencies/module")
|
@@ -159,19 +163,20 @@ module Bibliothecary
|
|
159
163
|
attrs = mod.attributes
|
160
164
|
org = attrs[:organisation]
|
161
165
|
name = attrs[:name]
|
162
|
-
version = mod.locate("revision").first&.attributes[:name
|
166
|
+
version = mod.locate("revision").first&.attributes&.[](:name)
|
163
167
|
|
164
|
-
next nil if org.nil?
|
168
|
+
next nil if org.nil? || name.nil? || version.nil?
|
165
169
|
|
166
170
|
Dependency.new(
|
167
171
|
name: "#{org}:#{name}",
|
168
172
|
requirement: version,
|
169
173
|
type: type,
|
174
|
+
source: options.fetch(:filename, nil)
|
170
175
|
)
|
171
176
|
end.compact
|
172
177
|
end
|
173
178
|
|
174
|
-
def self.parse_gradle_resolved(file_contents, options: {})
|
179
|
+
def self.parse_gradle_resolved(file_contents, options: {})
|
175
180
|
current_type = nil
|
176
181
|
|
177
182
|
file_contents.split("\n").map do |line|
|
@@ -190,7 +195,7 @@ module Bibliothecary
|
|
190
195
|
next if project_match[1].nil?
|
191
196
|
|
192
197
|
# project names can have colons (e.g. for gradle projects in subfolders), which breaks maven artifact naming assumptions, so just replace them with hyphens.
|
193
|
-
project_name = project_match[1].gsub(
|
198
|
+
project_name = project_match[1].gsub(":", "-")
|
194
199
|
line = line.sub(GRADLE_PROJECT_REGEXP, "internal:#{project_name}:1.0.0")
|
195
200
|
end
|
196
201
|
|
@@ -209,20 +214,22 @@ module Bibliothecary
|
|
209
214
|
if dep.count == 6
|
210
215
|
# get name from renamed package resolution "org:name:version -> renamed_org:name:version"
|
211
216
|
Dependency.new(
|
212
|
-
original_name: dep[0,2].join(":"),
|
217
|
+
original_name: dep[0, 2].join(":"),
|
213
218
|
original_requirement: dep[2],
|
214
219
|
name: dep[-3..-2].join(":"),
|
215
220
|
requirement: dep[-1],
|
216
221
|
type: current_type,
|
222
|
+
source: options.fetch(:filename, nil)
|
217
223
|
)
|
218
224
|
elsif dep.count == 5
|
219
225
|
# get name from renamed package resolution "org:name -> renamed_org:name:version"
|
220
226
|
Dependency.new(
|
221
|
-
original_name: dep[0,2].join(":"),
|
227
|
+
original_name: dep[0, 2].join(":"),
|
222
228
|
original_requirement: "*",
|
223
229
|
name: dep[-3..-2].join(":"),
|
224
230
|
requirement: dep[-1],
|
225
231
|
type: current_type,
|
232
|
+
source: options.fetch(:filename, nil)
|
226
233
|
)
|
227
234
|
else
|
228
235
|
# get name from version conflict resolution ("org:name:version -> version") and no-resolution ("org:name:version")
|
@@ -230,6 +237,7 @@ module Bibliothecary
|
|
230
237
|
name: dep[0..1].join(":"),
|
231
238
|
requirement: dep[-1],
|
232
239
|
type: current_type,
|
240
|
+
source: options.fetch(:filename, nil)
|
233
241
|
)
|
234
242
|
end
|
235
243
|
end
|
@@ -237,16 +245,16 @@ module Bibliothecary
|
|
237
245
|
.uniq { |item| [item.name, item.requirement, item.type, item.original_name, item.original_requirement] }
|
238
246
|
end
|
239
247
|
|
240
|
-
def self.parse_maven_resolved(file_contents, options: {})
|
248
|
+
def self.parse_maven_resolved(file_contents, options: {})
|
241
249
|
file_contents
|
242
250
|
.gsub(ANSI_MATCHER, "")
|
243
251
|
.split("\n")
|
244
|
-
.map(
|
252
|
+
.map { |line| parse_resolved_dep_line(line, options: options) }
|
245
253
|
.compact
|
246
254
|
.uniq
|
247
255
|
end
|
248
256
|
|
249
|
-
def self.parse_maven_tree(file_contents, options: {})
|
257
|
+
def self.parse_maven_tree(file_contents, options: {})
|
250
258
|
captures = file_contents
|
251
259
|
.gsub(ANSI_MATCHER, "")
|
252
260
|
.gsub(/\r\n?/, "\n")
|
@@ -267,68 +275,71 @@ module Bibliothecary
|
|
267
275
|
name: parts[0..1].join(":"),
|
268
276
|
requirement: version,
|
269
277
|
type: type,
|
278
|
+
source: options.fetch(:filename, nil)
|
270
279
|
)
|
271
280
|
end
|
272
281
|
|
273
282
|
# First dep line will be the package itself (unless we're only analyzing a single line)
|
274
283
|
package = deps[0]
|
275
|
-
deps.size < 2 ? deps : deps[1
|
284
|
+
deps.size < 2 ? deps : deps[1..].reject { |d| d.name == package.name && d.requirement == package.requirement }
|
276
285
|
end
|
277
286
|
|
278
|
-
def self.parse_resolved_dep_line(line)
|
287
|
+
def self.parse_resolved_dep_line(line, options: {})
|
279
288
|
# filter out anything that doesn't look like a
|
280
289
|
# resolved dep line
|
281
290
|
return unless line[/ .*:[^-]+-- /]
|
282
291
|
|
283
292
|
dep_parts = line.strip.split(":")
|
284
293
|
return unless dep_parts.length == 5
|
294
|
+
|
285
295
|
# org.springframework.boot:spring-boot-starter-web:jar:2.0.3.RELEASE:compile[36m -- module spring.boot.starter.web[0;1m [auto][m
|
286
296
|
Dependency.new(
|
287
297
|
name: dep_parts[0, 2].join(":"),
|
288
298
|
requirement: dep_parts[3],
|
289
299
|
type: dep_parts[4].split("--").first.strip,
|
300
|
+
source: options.fetch(:filename, nil)
|
290
301
|
)
|
291
302
|
end
|
292
303
|
|
293
304
|
def self.parse_standalone_pom_manifest(file_contents, options: {})
|
294
|
-
parse_pom_manifest(file_contents, {}, options:
|
305
|
+
parse_pom_manifest(file_contents, {}, options:)
|
295
306
|
end
|
296
307
|
|
297
|
-
def self.parse_pom_manifest(file_contents, parent_properties = {}, options: {})
|
298
|
-
parse_pom_manifests([file_contents], parent_properties)
|
308
|
+
def self.parse_pom_manifest(file_contents, parent_properties = {}, options: {})
|
309
|
+
parse_pom_manifests([file_contents], parent_properties, options.fetch(:filename, nil))
|
299
310
|
end
|
300
311
|
|
301
312
|
# @param files [Array<String>] Ordered array of strings containing the
|
302
313
|
# pom.xml bodies. The first element should be the child file.
|
303
314
|
# @param merged_properties [Hash]
|
304
|
-
def self.parse_pom_manifests(files, merged_properties)
|
315
|
+
def self.parse_pom_manifests(files, merged_properties, source = nil)
|
305
316
|
documents = files.map do |file|
|
306
317
|
doc = Ox.parse(file)
|
307
318
|
doc.respond_to?("project") ? doc.project : doc
|
308
319
|
end
|
309
320
|
|
310
|
-
|
321
|
+
merged_dependency_managements = {}
|
311
322
|
documents.each do |document|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
323
|
+
document.locate("dependencyManagement/dependencies/dependency").each do |dep|
|
324
|
+
group_id = extract_pom_dep_info(document, dep, "groupId", merged_properties)
|
325
|
+
artifact_id = extract_pom_dep_info(document, dep, "artifactId", merged_properties)
|
326
|
+
key = "#{group_id}:#{artifact_id}"
|
327
|
+
merged_dependency_managements[key] ||=
|
328
|
+
{
|
329
|
+
groupId: group_id,
|
330
|
+
artifactId: artifact_id,
|
331
|
+
version: extract_pom_dep_info(document, dep, "version", merged_properties),
|
332
|
+
scope: extract_pom_dep_info(document, dep, "scope", merged_properties),
|
333
|
+
}
|
334
|
+
end
|
324
335
|
end
|
325
336
|
|
326
337
|
dep_hashes = {}
|
327
338
|
documents.each do |document|
|
328
339
|
document.locate("dependencies/dependency").each do |dep|
|
329
|
-
|
330
|
-
|
331
|
-
key = "#{
|
340
|
+
group_id = extract_pom_dep_info(document, dep, "groupId", merged_properties)
|
341
|
+
artifact_id = extract_pom_dep_info(document, dep, "artifactId", merged_properties)
|
342
|
+
key = "#{group_id}:#{artifact_id}"
|
332
343
|
unless dep_hashes.key?(key)
|
333
344
|
dep_hashes[key] = {
|
334
345
|
name: key,
|
@@ -353,41 +364,44 @@ module Bibliothecary
|
|
353
364
|
# Anything that wasn't covered by a dependency version, get from the
|
354
365
|
# dependencyManagements
|
355
366
|
dep_hashes.each do |key, dep_hash|
|
356
|
-
if (
|
357
|
-
dep_hash[:requirement] ||=
|
358
|
-
dep_hash[:type] ||=
|
367
|
+
if (dependency_management = merged_dependency_managements[key])
|
368
|
+
dep_hash[:requirement] ||= dependency_management[:version]
|
369
|
+
dep_hash[:type] ||= dependency_management[:scope]
|
359
370
|
end
|
360
371
|
|
361
372
|
dep_hash[:type] ||= "runtime"
|
373
|
+
dep_hash[:source] = source
|
362
374
|
end
|
363
375
|
|
364
|
-
dep_hashes.map{|
|
376
|
+
dep_hashes.map { |_key, dep_hash| Dependency.new(**dep_hash) }
|
365
377
|
end
|
366
378
|
|
367
|
-
def self.parse_gradle(file_contents, options: {})
|
379
|
+
def self.parse_gradle(file_contents, options: {})
|
368
380
|
file_contents
|
369
|
-
.scan(GRADLE_GROOVY_SIMPLE_REGEXP)
|
370
|
-
.reject { |(_type, group,
|
371
|
-
.map
|
381
|
+
.scan(GRADLE_GROOVY_SIMPLE_REGEXP) # match 'implementation "group:artifactId:version"'
|
382
|
+
.reject { |(_type, group, artifact_id, _version)| group.nil? || artifact_id.nil? } # remove any matches with missing group/artifactId
|
383
|
+
.map do |(type, group, artifact_id, version)|
|
372
384
|
Dependency.new(
|
373
|
-
name: [group,
|
385
|
+
name: [group, artifact_id].join(":"),
|
374
386
|
requirement: version,
|
375
387
|
type: type,
|
388
|
+
source: options.fetch(:filename, nil)
|
376
389
|
)
|
377
|
-
|
390
|
+
end
|
378
391
|
end
|
379
392
|
|
380
|
-
def self.parse_gradle_kts(file_contents, options: {})
|
393
|
+
def self.parse_gradle_kts(file_contents, options: {})
|
381
394
|
file_contents
|
382
|
-
.scan(GRADLE_KOTLIN_SIMPLE_REGEXP)
|
383
|
-
.reject { |(_type, group,
|
384
|
-
.map
|
395
|
+
.scan(GRADLE_KOTLIN_SIMPLE_REGEXP) # match 'implementation("group:artifactId:version")'
|
396
|
+
.reject { |(_type, group, artifact_id, _version)| group.nil? || artifact_id.nil? } # remove any matches with missing group/artifactId
|
397
|
+
.map do |(type, group, artifact_id, version)|
|
385
398
|
Dependency.new(
|
386
|
-
name: [group,
|
399
|
+
name: [group, artifact_id].join(":"),
|
387
400
|
requirement: version,
|
388
401
|
type: type,
|
402
|
+
source: options.fetch(:filename, nil)
|
389
403
|
)
|
390
|
-
|
404
|
+
end
|
391
405
|
end
|
392
406
|
|
393
407
|
def self.gradle_dependency_name(group, name)
|
@@ -420,11 +434,9 @@ module Bibliothecary
|
|
420
434
|
# whitespace in dependency tags should be ignored
|
421
435
|
value = value&.strip
|
422
436
|
match = value&.match(MAVEN_PROPERTY_REGEXP)
|
423
|
-
if match
|
424
|
-
|
425
|
-
|
426
|
-
return value
|
427
|
-
end
|
437
|
+
return extract_property(xml, match[1], value, parent_properties) if match
|
438
|
+
|
439
|
+
value
|
428
440
|
end
|
429
441
|
|
430
442
|
def self.replace_value_with_prop(original_value, property_value, property_name)
|
@@ -434,17 +446,16 @@ module Bibliothecary
|
|
434
446
|
def self.extract_property(xml, property_name, value, parent_properties = {}, depth = 0)
|
435
447
|
prop_value = property_value(xml, property_name, parent_properties)
|
436
448
|
return value unless prop_value
|
449
|
+
|
437
450
|
# don't resolve more than 5 levels deep to avoid potential circular references
|
438
451
|
|
439
452
|
resolved_value = replace_value_with_prop(value, prop_value, property_name)
|
440
453
|
# check to see if we just resolved to another property name
|
441
454
|
match = resolved_value.match(MAVEN_PROPERTY_REGEXP)
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
return resolved_value
|
447
|
-
end
|
455
|
+
return resolved_value unless match && depth < MAX_DEPTH
|
456
|
+
|
457
|
+
depth += 1
|
458
|
+
extract_property(xml, match[1], resolved_value, parent_properties, depth)
|
448
459
|
end
|
449
460
|
|
450
461
|
def self.property_value(xml, property_name, parent_properties)
|
@@ -453,9 +464,9 @@ module Bibliothecary
|
|
453
464
|
non_prop_name = property_name.gsub(".", "/").gsub("project/", "")
|
454
465
|
|
455
466
|
prop_field = xml.properties.locate(property_name).first if xml.respond_to?("properties")
|
456
|
-
parent_prop = parent_properties[property_name] ||
|
457
|
-
|
458
|
-
|
467
|
+
parent_prop = parent_properties[property_name] || # e.g. "${foo}"
|
468
|
+
parent_properties[property_name.sub(/^project\./, "")] || # e.g. "${project.foo}"
|
469
|
+
parent_properties[property_name.sub(/^project\.parent\./, "")] # e.g. "${project.parent.foo}"
|
459
470
|
|
460
471
|
if prop_field
|
461
472
|
prop_field.nodes.first
|
@@ -472,7 +483,7 @@ module Bibliothecary
|
|
472
483
|
end
|
473
484
|
end
|
474
485
|
|
475
|
-
def self.parse_sbt_update_full(file_contents, options: {})
|
486
|
+
def self.parse_sbt_update_full(file_contents, options: {})
|
476
487
|
all_deps = []
|
477
488
|
lines = file_contents.split("\n")
|
478
489
|
while lines.any?
|
@@ -480,6 +491,7 @@ module Bibliothecary
|
|
480
491
|
|
481
492
|
type_match = SBT_TYPE_REGEXP.match(line)
|
482
493
|
next unless type_match
|
494
|
+
|
483
495
|
type = type_match.captures[0]
|
484
496
|
|
485
497
|
deps = parse_sbt_deps(type, lines)
|
@@ -487,8 +499,8 @@ module Bibliothecary
|
|
487
499
|
end
|
488
500
|
|
489
501
|
# strip out evicted dependencies
|
490
|
-
all_deps.
|
491
|
-
dep[:fields]["evicted"]
|
502
|
+
all_deps.reject! do |dep|
|
503
|
+
dep[:fields]["evicted"] == "true"
|
492
504
|
end
|
493
505
|
|
494
506
|
# in the future, we could use "callers" in the fields to
|
@@ -498,19 +510,23 @@ module Bibliothecary
|
|
498
510
|
|
499
511
|
# clean out any duplicates (I'm pretty sure sbt will have done this for
|
500
512
|
# us so this is paranoia, basically)
|
501
|
-
squished = all_deps.compact.uniq {|item| [item[:name], item[:requirement], item[:type]]}
|
513
|
+
squished = all_deps.compact.uniq { |item| [item[:name], item[:requirement], item[:type]] }
|
502
514
|
|
503
515
|
# get rid of the fields
|
504
516
|
squished.each do |dep|
|
505
517
|
dep.delete(:fields)
|
506
518
|
end
|
507
519
|
|
508
|
-
|
520
|
+
squished.map do |dep_kvs|
|
521
|
+
Dependency.new(
|
522
|
+
**dep_kvs, source: options.fetch(:filename, nil)
|
523
|
+
)
|
524
|
+
end
|
509
525
|
end
|
510
526
|
|
511
527
|
def self.parse_sbt_deps(type, lines)
|
512
528
|
deps = []
|
513
|
-
while lines.any?
|
529
|
+
while lines.any? && !SBT_TYPE_REGEXP.match(lines[0])
|
514
530
|
line = lines.shift
|
515
531
|
|
516
532
|
next if SBT_IGNORE_REGEXP.match(line)
|
@@ -530,7 +546,7 @@ module Bibliothecary
|
|
530
546
|
|
531
547
|
def self.parse_sbt_versions(type, name, lines)
|
532
548
|
versions = []
|
533
|
-
while lines.any?
|
549
|
+
while lines.any? && !SBT_TYPE_REGEXP.match(lines[0])
|
534
550
|
line = lines.shift
|
535
551
|
|
536
552
|
version_match = SBT_VERSION_REGEXP.match(line)
|
@@ -547,7 +563,7 @@ module Bibliothecary
|
|
547
563
|
|
548
564
|
def self.parse_sbt_version(type, name, version, lines)
|
549
565
|
fields = {}
|
550
|
-
while lines.any?
|
566
|
+
while lines.any? && !SBT_TYPE_REGEXP.match(lines[0])
|
551
567
|
line = lines.shift
|
552
568
|
|
553
569
|
field_match = SBT_FIELD_REGEXP.match(line)
|