pray-cli 1.25.0 → 1.26.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/CHANGELOG.md +11 -0
- data/README.md +1 -0
- data/lib/pray/cli/commands/packages.rb +7 -1
- data/lib/pray/cli/commands/search.rb +43 -0
- data/lib/pray/cli/commands/workflow.rb +1 -1
- data/lib/pray/cli/help.rb +3 -1
- data/lib/pray/cli/helpers.rb +3 -3
- data/lib/pray/cli/parse.rb +27 -0
- data/lib/pray/cli.rb +2 -0
- data/lib/pray/lockfile.rb +1 -1
- data/lib/pray/materialize.rb +2 -2
- data/lib/pray/package_relation.rb +44 -0
- data/lib/pray/package_spec.rb +4 -2
- data/lib/pray/package_spec_render.rb +3 -0
- data/lib/pray/path_safety.rb +4 -2
- data/lib/pray/plan.rb +4 -3
- data/lib/pray/registry.rb +3 -3
- data/lib/pray/registry_search.rb +73 -0
- data/lib/pray/render_dest.rb +7 -6
- data/lib/pray/render_layout.rb +3 -2
- data/lib/pray/render_patch.rb +25 -3
- data/lib/pray/render_reconcile.rb +60 -0
- data/lib/pray/resolve.rb +1 -0
- data/lib/pray/resolve_deps.rb +18 -1
- data/lib/pray/url_redaction.rb +20 -0
- data/lib/pray/verify.rb +13 -7
- data/lib/pray/version.rb +2 -2
- data/lib/pray.rb +4 -0
- metadata +6 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7a2524f61bfecb06bcdcf1656ed618e104d854a2d0386c791c3bf3989b9894d1
|
|
4
|
+
data.tar.gz: d20780c7dd5cb5a9f14448fcb793e2bb42007ec8c29db9a390fbe3d4c9dd27b5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3f721c1a473ce6e07b726c6be47f6b98da4dcd83a6f6da6e3afcf6f80d18d50a7f47ed1b42f3bdde9b4922e16c05784ef5c32f69e1255cb7ae521f7f6ade8dbe
|
|
7
|
+
data.tar.gz: aeeaaade1743bf0b15511ec45704692fed58ed65b2f2f4ccca6d848481b23bd958bee3e433bb944632828ed029391f638c1ffaf31699bb73251763e8654f0c9b
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 1.26.1 (2026-11-02)
|
|
6
|
+
|
|
7
|
+
- Show optional package referrals separately in `pray explain`, exclude them from dependency cycles and trees, and validate their constraints when another declaration selects the target.
|
|
8
|
+
- Keep drift, render checks, planning, and writes consistent for managed files that contain local content.
|
|
9
|
+
|
|
10
|
+
## 1.26.0 (2026-10-30)
|
|
11
|
+
|
|
12
|
+
- Add validated `related` references to prayspec parsing, rendering, and `pray explain`.
|
|
13
|
+
- Make `render --check`, frozen install, and `plan` compare destinations with the bytes the write path would produce. Remove unchanged managed spans retired by the previous lock while preserving edited or unknown spans for explicit review.
|
|
14
|
+
- Add `pray search` parity with the stable distribution-index contract. Search package names by substring through a declared source, local distribution root, or registry URL, and label catalog summaries as unverified claims in help.
|
|
15
|
+
|
|
5
16
|
## 1.25.0 (2026-10-26)
|
|
6
17
|
|
|
7
18
|
- Bump the gem version to 1.25.0 with the coordinated language-registry cut.
|
data/README.md
CHANGED
|
@@ -84,7 +84,13 @@ module Pray
|
|
|
84
84
|
end
|
|
85
85
|
lines << "source: #{package_source_summary(package)}"
|
|
86
86
|
lines << "exports: #{format_list(package.selected_exports)}"
|
|
87
|
-
|
|
87
|
+
required_dependencies = package.spec.dependencies.reject(&:optional).map(&:name)
|
|
88
|
+
optional_referrals = package.spec.dependencies.select(&:optional).map do |dependency|
|
|
89
|
+
"#{dependency.name} (#{dependency.constraint})"
|
|
90
|
+
end
|
|
91
|
+
lines << "dependencies: #{format_list(required_dependencies)}"
|
|
92
|
+
lines << "optional referrals: #{format_list(optional_referrals)}"
|
|
93
|
+
lines << "related prayers: #{format_list(package.spec.related)}"
|
|
88
94
|
lines << "tree hash: #{package.tree_hash}"
|
|
89
95
|
lines << "artifact hash: #{package.artifact_hash}"
|
|
90
96
|
if lockfile_package
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module CLI
|
|
5
|
+
def search_command(query:, source:, root:, url:)
|
|
6
|
+
hits = if root
|
|
7
|
+
RegistrySearch.search_local_registry(root, query)
|
|
8
|
+
elsif url
|
|
9
|
+
RegistrySearch.search_http_registry(url, query)
|
|
10
|
+
else
|
|
11
|
+
search_declared_source(query, source)
|
|
12
|
+
end
|
|
13
|
+
if hits.empty?
|
|
14
|
+
puts "no packages matched"
|
|
15
|
+
else
|
|
16
|
+
hits.each { |hit| puts(hit.summary ? "#{hit.name} — #{hit.summary}" : hit.name) }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def search_declared_source(query, source_name)
|
|
21
|
+
manifest = Pray.parse_manifest(Pray.read_manifest_text(manifest_path))
|
|
22
|
+
source = source_name ? manifest.sources.find { |entry| entry.name == source_name } : searchable_source(manifest)
|
|
23
|
+
raise Error.resolution("unknown source: #{source_name}") if source_name && !source
|
|
24
|
+
unless source
|
|
25
|
+
raise Error.resolution("Prayfile has no searchable sources; pass --root PATH or --url URL")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
case source.kind
|
|
29
|
+
when "path"
|
|
30
|
+
root = File.expand_path(source.url, File.dirname(manifest_path))
|
|
31
|
+
RegistrySearch.search_local_registry(root, query)
|
|
32
|
+
when "registry", "static index"
|
|
33
|
+
RegistrySearch.search_http_registry(source.url, query)
|
|
34
|
+
else
|
|
35
|
+
raise Error.unsupported("search does not support source kind #{source.kind}")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def searchable_source(manifest)
|
|
40
|
+
manifest.sources.find { |source| %w[registry static\ index].include?(source.kind) } || manifest.sources.first
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/pray/cli/help.rb
CHANGED
|
@@ -36,6 +36,7 @@ module Pray
|
|
|
36
36
|
|
|
37
37
|
INSPECT_COMMANDS = [
|
|
38
38
|
"list list declared packages",
|
|
39
|
+
"search <query> [--source|--root|--url] find packages in a distribution index",
|
|
39
40
|
"outdated [--remote] show constraint vs resolved versions",
|
|
40
41
|
"explain <package> show why a package was selected",
|
|
41
42
|
"tree print the dependency tree"
|
|
@@ -102,7 +103,7 @@ module Pray
|
|
|
102
103
|
|
|
103
104
|
Without --check, render writes dest. It does not write Prayfile.lock.
|
|
104
105
|
Use pray plan to preview a write.
|
|
105
|
-
--check writes nothing. It fails
|
|
106
|
+
--check writes nothing. It fails when render would change dest.
|
|
106
107
|
TEXT
|
|
107
108
|
"format" => <<~TEXT.strip,
|
|
108
109
|
rewrite Prayfile to recommended destination DSL
|
|
@@ -187,6 +188,7 @@ module Pray
|
|
|
187
188
|
Subcommands: list, show, add-key, remove-key, set-signed, set-allow, import-repo, import-registry, check
|
|
188
189
|
TEXT
|
|
189
190
|
"list" => "list declared packages\n\nUsage: pray list",
|
|
191
|
+
"search" => "search a distribution index for package names\n\nUsage: pray search <query> [--source NAME | --root PATH | --url URL]\n\nMatches package names by case-insensitive substring. Summaries are unverified catalog claims.",
|
|
190
192
|
"outdated" => <<~TEXT.strip,
|
|
191
193
|
show constraint vs resolved versions
|
|
192
194
|
|
data/lib/pray/cli/helpers.rb
CHANGED
|
@@ -59,8 +59,8 @@ module Pray
|
|
|
59
59
|
def ensure_rendered_outputs_current(project, rendered)
|
|
60
60
|
rendered.each do |target|
|
|
61
61
|
path = File.join(project.project_root, target.path)
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
retired = RenderReconcile.retired_span_checksums(project.previous_lockfile, target)
|
|
63
|
+
unless RenderReconcile.current?(path, target.path, target.content, retired)
|
|
64
64
|
raise Error.render("#{path} is stale; rerun pray install to regenerate it or pray plan to inspect the diff")
|
|
65
65
|
end
|
|
66
66
|
end
|
|
@@ -152,7 +152,7 @@ module Pray
|
|
|
152
152
|
lines << "#{indent}#{package.declaration.name} #{package.spec.recorded_version}"
|
|
153
153
|
return unless ancestry.add?(package.declaration.name)
|
|
154
154
|
|
|
155
|
-
package.spec.dependencies.each do |dependency|
|
|
155
|
+
package.spec.dependencies.reject(&:optional).each do |dependency|
|
|
156
156
|
resolved = package_map[dependency.name]
|
|
157
157
|
if resolved
|
|
158
158
|
if ancestry.include?(resolved.declaration.name)
|
data/lib/pray/cli/parse.rb
CHANGED
|
@@ -64,6 +64,7 @@ module Pray
|
|
|
64
64
|
when "serve" then [:serve, parse_serve_arguments(arguments)]
|
|
65
65
|
when "confess" then [:confess, parse_confess_arguments(arguments)]
|
|
66
66
|
when "list" then [:list]
|
|
67
|
+
when "search" then [:search, parse_search_arguments(arguments)]
|
|
67
68
|
when "outdated" then [:outdated, arguments]
|
|
68
69
|
when "explain" then [:explain, arguments.shift]
|
|
69
70
|
when "vendor" then [:vendor]
|
|
@@ -121,6 +122,32 @@ module Pray
|
|
|
121
122
|
{unused: unused}
|
|
122
123
|
end
|
|
123
124
|
|
|
125
|
+
def parse_search_arguments(arguments)
|
|
126
|
+
options = {query: nil, source: nil, root: nil, url: nil}
|
|
127
|
+
while (argument = arguments.shift)
|
|
128
|
+
case argument
|
|
129
|
+
when "--source" then options[:source] = search_option_value(arguments, argument)
|
|
130
|
+
when "--root" then options[:root] = search_option_value(arguments, argument)
|
|
131
|
+
when "--url" then options[:url] = search_option_value(arguments, argument)
|
|
132
|
+
when /^--/ then raise Error.usage("unknown search flag: #{argument}")
|
|
133
|
+
else
|
|
134
|
+
raise Error.usage("unexpected search argument: #{argument}") if options[:query]
|
|
135
|
+
|
|
136
|
+
options[:query] = argument
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
raise Error.usage("search requires a query") unless options[:query]
|
|
140
|
+
|
|
141
|
+
options
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def search_option_value(arguments, flag)
|
|
145
|
+
value = arguments.shift
|
|
146
|
+
raise Error.usage("#{flag} requires a value") unless value && !value.start_with?("--")
|
|
147
|
+
|
|
148
|
+
value
|
|
149
|
+
end
|
|
150
|
+
|
|
124
151
|
def parse_add_arguments(arguments)
|
|
125
152
|
name = arguments.shift
|
|
126
153
|
raise Error.unsupported("add requires a package name") unless name
|
data/lib/pray/cli.rb
CHANGED
|
@@ -14,6 +14,7 @@ require_relative "cli/commands/init_prayer"
|
|
|
14
14
|
require_relative "cli/commands/workflow"
|
|
15
15
|
require_relative "cli/commands/update_latest"
|
|
16
16
|
require_relative "cli/commands/packages"
|
|
17
|
+
require_relative "cli/commands/search"
|
|
17
18
|
require_relative "cli/commands/distribution"
|
|
18
19
|
require_relative "cli/commands/trust"
|
|
19
20
|
require_relative "cli/commands/auth"
|
|
@@ -119,6 +120,7 @@ module Pray
|
|
|
119
120
|
in [:confess, confess_args] then confess_command(**confess_args)
|
|
120
121
|
in [:sync, sync_args] then sync_command(**sync_args)
|
|
121
122
|
in [:list] then list_command
|
|
123
|
+
in [:search, search_args] then search_command(**search_args)
|
|
122
124
|
in [:outdated, arguments] then outdated_command(arguments)
|
|
123
125
|
in [:explain, name] then explain_command(name)
|
|
124
126
|
in [:vendor] then raise Error.unsupported("vendor is not implemented yet in pray-cli Ruby")
|
data/lib/pray/lockfile.rb
CHANGED
|
@@ -169,7 +169,7 @@ module Pray
|
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
def build_lockfile(manifest_hash, environment, project_root, manifest_sources, manifest_targets, rendered, packages, source_revisions, source_host_keys, project = nil)
|
|
172
|
-
rendered = Render.layout_rendered_targets(project, rendered) if project
|
|
172
|
+
rendered = Render.layout_rendered_targets(project, rendered, project.previous_lockfile) if project
|
|
173
173
|
lockfile = Lockfile.new(
|
|
174
174
|
manifest_hash: manifest_hash,
|
|
175
175
|
environment: environment,
|
data/lib/pray/materialize.rb
CHANGED
|
@@ -90,8 +90,8 @@ module Pray
|
|
|
90
90
|
if frozen
|
|
91
91
|
rendered.each do |target|
|
|
92
92
|
path = File.join(project.project_root, target.path)
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
retired = RenderReconcile.retired_span_checksums(existing, target)
|
|
94
|
+
unless RenderReconcile.current?(path, target.path, target.content, retired)
|
|
95
95
|
raise Error.render(
|
|
96
96
|
"#{path} is stale; rerun install to regenerate it or plan to inspect the diff"
|
|
97
97
|
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module PackageRelation
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def canonicalize(references)
|
|
8
|
+
Array(references).map(&:strip).uniq.sort.tap do |canonical|
|
|
9
|
+
invalid = canonical.find { |reference| !valid?(reference) }
|
|
10
|
+
raise Error.parse("prayspec", "invalid related prayer reference") if invalid
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def valid?(reference)
|
|
15
|
+
return false if reference.empty? || reference.match?(/[\\[:cntrl:]]/)
|
|
16
|
+
if reference.match?(/\A[A-Za-z][A-Za-z0-9+.-]*:.+\z/)
|
|
17
|
+
return !uri_has_userinfo?(reference)
|
|
18
|
+
end
|
|
19
|
+
if reference.start_with?("/")
|
|
20
|
+
path = locator_path(reference)
|
|
21
|
+
return path.length > 1 && !path.start_with?("//")
|
|
22
|
+
end
|
|
23
|
+
if reference.start_with?("./", "../")
|
|
24
|
+
return locator_path(reference).split("/").any? do |segment|
|
|
25
|
+
!segment.empty? && ![".", ".."].include?(segment)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
return false if reference.match?(/[?#]/)
|
|
30
|
+
|
|
31
|
+
segments = reference.split("/", -1)
|
|
32
|
+
segments.length == 2 && segments.none? { |segment| segment.empty? || [".", ".."].include?(segment) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def locator_path(reference)
|
|
36
|
+
reference.split(/[?#]/, 2).first
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def uri_has_userinfo?(reference)
|
|
40
|
+
after_scheme = reference.split("://", 2)[1]
|
|
41
|
+
after_scheme && after_scheme.split(%r{[/?#]}, 2).first.include?("@")
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/pray/package_spec.rb
CHANGED
|
@@ -14,13 +14,13 @@ module Pray
|
|
|
14
14
|
PackageSpec = Struct.new(
|
|
15
15
|
:name, :version, :summary, :description, :authors, :maintainers, :license, :homepage,
|
|
16
16
|
:source_code_uri, :changelog_uri, :prayfile_version, :files, :exports,
|
|
17
|
-
:skills, :templates, :adapters, :targets, :dependencies, :metadata, :upstream
|
|
17
|
+
:skills, :templates, :adapters, :targets, :related, :dependencies, :metadata, :upstream
|
|
18
18
|
) do
|
|
19
19
|
def initialize(
|
|
20
20
|
name: "", version: "", summary: nil, description: nil, authors: [], maintainers: [], license: nil,
|
|
21
21
|
homepage: nil, source_code_uri: nil, changelog_uri: nil, prayfile_version: nil,
|
|
22
22
|
files: [], exports: {}, skills: {}, templates: {}, adapters: {}, targets: [],
|
|
23
|
-
dependencies: [], metadata: {}, upstream: nil
|
|
23
|
+
related: [], dependencies: [], metadata: {}, upstream: nil
|
|
24
24
|
)
|
|
25
25
|
super
|
|
26
26
|
end
|
|
@@ -50,6 +50,7 @@ module Pray
|
|
|
50
50
|
copy.authors = Array(authors).sort
|
|
51
51
|
copy.maintainers = Array(maintainers).sort
|
|
52
52
|
copy.targets = Array(targets).sort
|
|
53
|
+
copy.related = PackageRelation.canonicalize(related)
|
|
53
54
|
copy.dependencies = dependencies.sort_by { |dependency| [dependency.name, dependency.constraint, dependency.optional] }
|
|
54
55
|
end
|
|
55
56
|
end
|
|
@@ -258,6 +259,7 @@ module Pray
|
|
|
258
259
|
when "maintainers" then spec.maintainers = array_of_strings(value)
|
|
259
260
|
when "files" then spec.files = array_of_strings(value)
|
|
260
261
|
when "targets" then spec.targets = array_of_strings(value)
|
|
262
|
+
when "related" then spec.related = array_of_strings(value)
|
|
261
263
|
when "exports" then spec.exports = parse_exports(value)
|
|
262
264
|
when "skills" then spec.skills = parse_skills(value)
|
|
263
265
|
when "templates" then spec.templates = parse_templates(value)
|
|
@@ -51,6 +51,9 @@ module Pray
|
|
|
51
51
|
push_named_paths(lines, "templates", spec.templates)
|
|
52
52
|
push_string_map(lines, "adapters", spec.adapters)
|
|
53
53
|
push_array(lines, "targets", spec.targets) unless spec.targets.nil? || spec.targets.empty?
|
|
54
|
+
unless spec.related.nil? || spec.related.empty?
|
|
55
|
+
push_array(lines, "related", spec.related)
|
|
56
|
+
end
|
|
54
57
|
end
|
|
55
58
|
|
|
56
59
|
def push_relation_fields(lines, spec)
|
data/lib/pray/path_safety.rb
CHANGED
|
@@ -21,8 +21,10 @@ module Pray
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def reject_unsafe_package_name!(package_name)
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
segments = package_name&.split("/", -1)
|
|
25
|
+
if segments&.length != 2 || segments.any? do |segment|
|
|
26
|
+
segment.empty? || [".", ".."].include?(segment) || segment.include?("\0") || segment.include?("\\")
|
|
27
|
+
end
|
|
26
28
|
raise Error.resolution("invalid package name: #{package_name.inspect}")
|
|
27
29
|
end
|
|
28
30
|
|
data/lib/pray/plan.rb
CHANGED
|
@@ -16,7 +16,7 @@ module Pray
|
|
|
16
16
|
package_lines: ApplyReport.local_summary_lines(previous_lockfile, project) +
|
|
17
17
|
package_summary_lines(previous_lockfile, lockfile, project),
|
|
18
18
|
lockfile: lockfile_change_status(previous_lockfile, lockfile),
|
|
19
|
-
targets: rendered.map { |target| target_change(project, target) },
|
|
19
|
+
targets: rendered.map { |target| target_change(project, target, previous_lockfile) },
|
|
20
20
|
provisioned: destinations.map { |file, status| [file.path, status.to_s] },
|
|
21
21
|
warnings: []
|
|
22
22
|
)
|
|
@@ -57,11 +57,12 @@ module Pray
|
|
|
57
57
|
Pray.lockfiles_equivalent?(lockfile, existing) ? "unchanged" : "update"
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
def target_change(project, target)
|
|
60
|
+
def target_change(project, target, previous_lockfile)
|
|
61
61
|
path = File.join(project.project_root, target.path)
|
|
62
|
+
retired = RenderReconcile.retired_span_checksums(previous_lockfile, target)
|
|
62
63
|
change = if !File.exist?(path)
|
|
63
64
|
"write"
|
|
64
|
-
elsif
|
|
65
|
+
elsif RenderReconcile.current?(path, target.path, target.content, retired)
|
|
65
66
|
"unchanged"
|
|
66
67
|
else
|
|
67
68
|
"update"
|
data/lib/pray/registry.rb
CHANGED
|
@@ -276,7 +276,7 @@ module Pray
|
|
|
276
276
|
|
|
277
277
|
def http_get(url)
|
|
278
278
|
uri = URI(url)
|
|
279
|
-
bounded_http_exchange(uri, Net::HTTP::Get.new(uri), "HTTP request failed for #{url}")
|
|
279
|
+
bounded_http_exchange(uri, Net::HTTP::Get.new(uri), "HTTP request failed for #{UrlRedaction.redact_userinfo(url)}")
|
|
280
280
|
end
|
|
281
281
|
|
|
282
282
|
def http_put(url, content_type, body)
|
|
@@ -284,7 +284,7 @@ module Pray
|
|
|
284
284
|
request = Net::HTTP::Put.new(uri)
|
|
285
285
|
request["Content-Type"] = content_type
|
|
286
286
|
request.body = body
|
|
287
|
-
bounded_http_exchange(uri, request, "HTTP upload failed for #{url}")
|
|
287
|
+
bounded_http_exchange(uri, request, "HTTP upload failed for #{UrlRedaction.redact_userinfo(url)}")
|
|
288
288
|
end
|
|
289
289
|
|
|
290
290
|
def http_post(url, content_type, body)
|
|
@@ -292,7 +292,7 @@ module Pray
|
|
|
292
292
|
request = Net::HTTP::Post.new(uri)
|
|
293
293
|
request["Content-Type"] = content_type
|
|
294
294
|
request.body = body
|
|
295
|
-
bounded_http_exchange(uri, request, "HTTP request failed for #{url}")
|
|
295
|
+
bounded_http_exchange(uri, request, "HTTP request failed for #{UrlRedaction.redact_userinfo(url)}")
|
|
296
296
|
end
|
|
297
297
|
|
|
298
298
|
def bounded_http_exchange(uri, request, failure_message)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Pray
|
|
6
|
+
RegistrySearchHit = Struct.new(:name, :summary, keyword_init: true)
|
|
7
|
+
|
|
8
|
+
module RegistrySearch
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def search_local_registry(root, query, include_summary: true)
|
|
12
|
+
index = parse_index(File.read(File.join(root, "v1", "index.json"), encoding: "UTF-8"))
|
|
13
|
+
search_index_names(index, query).map do |name|
|
|
14
|
+
metadata_path = Registry.registry_metadata_path(root, name)
|
|
15
|
+
metadata = Registry.parse_metadata(File.read(metadata_path, encoding: "UTF-8")) if include_summary && File.file?(metadata_path)
|
|
16
|
+
search_hit(name, metadata)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def search_http_registry(url, query, include_summary: true)
|
|
21
|
+
index = parse_index(Registry.http_get(Registry.join_url(url, "v1/index.json")))
|
|
22
|
+
search_index_names(index, query).map do |name|
|
|
23
|
+
PathSafety.reject_unsafe_package_name!(name)
|
|
24
|
+
metadata = fetch_http_metadata(url, name) if include_summary
|
|
25
|
+
search_hit(name, metadata)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def search_index_names(index, query)
|
|
30
|
+
needle = query.strip.downcase
|
|
31
|
+
index.fetch("packages").select do |name|
|
|
32
|
+
raise Error.parse("registry index", "package names must be strings") unless name.is_a?(String)
|
|
33
|
+
|
|
34
|
+
PathSafety.reject_unsafe_package_name!(name)
|
|
35
|
+
name.downcase.include?(needle)
|
|
36
|
+
end.sort
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def latest_non_yanked_summary(metadata)
|
|
40
|
+
return unless metadata
|
|
41
|
+
|
|
42
|
+
latest = metadata.versions.reject(&:yanked).max_by { |version| Gem::Version.new(version.version) }
|
|
43
|
+
summary = latest&.derived_metadata&.fetch("summary", nil).to_s.strip
|
|
44
|
+
summary unless summary.empty?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def parse_index(text)
|
|
48
|
+
index = JSON.parse(text)
|
|
49
|
+
unless index["spec"] == "prayfile-distribution-1" && index["packages"].is_a?(Array)
|
|
50
|
+
raise Error.parse("registry index", "expected prayfile-distribution-1 with a packages array")
|
|
51
|
+
end
|
|
52
|
+
index
|
|
53
|
+
rescue JSON::ParserError => error
|
|
54
|
+
raise Error.parse("registry index", error.message)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def fetch_http_metadata(url, name)
|
|
58
|
+
path = "v1/packages/#{name}.json"
|
|
59
|
+
Registry.parse_metadata(Registry.http_get(Registry.join_url(url, path)))
|
|
60
|
+
rescue Error => error
|
|
61
|
+
raise unless error.category == :resolution
|
|
62
|
+
|
|
63
|
+
nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def search_hit(name, metadata)
|
|
67
|
+
if metadata && metadata.name != name
|
|
68
|
+
raise Error.integrity("registry metadata name mismatch for #{name}")
|
|
69
|
+
end
|
|
70
|
+
RegistrySearchHit.new(name: name, summary: latest_non_yanked_summary(metadata))
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/pray/render_dest.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "fileutils"
|
|
4
|
-
require "pathname"
|
|
5
4
|
|
|
6
5
|
module Pray
|
|
7
6
|
module RenderDest
|
|
@@ -9,13 +8,15 @@ module Pray
|
|
|
9
8
|
|
|
10
9
|
def write_rendered_targets(project, rendered, previous_lockfile = nil)
|
|
11
10
|
validate_destinations!(project, previous_lockfile)
|
|
11
|
+
RenderReconcile.reject_managed_span_conflicts!(project, rendered, previous_lockfile) if previous_lockfile
|
|
12
12
|
rendered.each do |target|
|
|
13
13
|
PathSafety.validate_destination_path!(target.path)
|
|
14
14
|
ensure_safe_destination_ancestors!(project.project_root, target.path, target.path)
|
|
15
15
|
path = File.join(project.project_root, target.path)
|
|
16
16
|
FileUtils.mkdir_p(File.dirname(path))
|
|
17
17
|
ensure_safe_destination_ancestors!(project.project_root, target.path, target.path)
|
|
18
|
-
|
|
18
|
+
retired = RenderReconcile.retired_span_checksums(previous_lockfile, target)
|
|
19
|
+
write_rendered_content(path, target.path, target.content, retired)
|
|
19
20
|
end
|
|
20
21
|
materialize(project, previous_lockfile)
|
|
21
22
|
end
|
|
@@ -147,7 +148,7 @@ module Pray
|
|
|
147
148
|
end
|
|
148
149
|
end
|
|
149
150
|
|
|
150
|
-
def layout_rendered_content(path, display, fresh)
|
|
151
|
+
def layout_rendered_content(path, display, fresh, retired = {})
|
|
151
152
|
kind = destination_kind(path)
|
|
152
153
|
return fresh if kind == :missing
|
|
153
154
|
|
|
@@ -155,15 +156,15 @@ module Pray
|
|
|
155
156
|
unless kind == :regular
|
|
156
157
|
raise Error.render("refusing to write `#{display}`; destination is not a regular file")
|
|
157
158
|
end
|
|
158
|
-
|
|
159
|
+
RenderReconcile.reconcile_content(decode_utf8(read_regular_bytes(path, display), display), fresh, retired)
|
|
159
160
|
end
|
|
160
161
|
|
|
161
|
-
def write_rendered_content(path, display, fresh)
|
|
162
|
+
def write_rendered_content(path, display, fresh, retired = {})
|
|
162
163
|
return create_bytes(path, display, fresh) if destination_kind(path) == :missing
|
|
163
164
|
|
|
164
165
|
open_regular(path, display, File::RDWR) do |file|
|
|
165
166
|
existing = decode_utf8(read_destination_bytes(file, display), display)
|
|
166
|
-
content =
|
|
167
|
+
content = RenderReconcile.reconcile_content(existing, fresh, retired)
|
|
167
168
|
return if Transaction.replace(path, existing.b, content.b)
|
|
168
169
|
|
|
169
170
|
file.rewind
|
data/lib/pray/render_layout.rb
CHANGED
|
@@ -4,12 +4,13 @@ module Pray
|
|
|
4
4
|
module Render
|
|
5
5
|
module_function
|
|
6
6
|
|
|
7
|
-
def layout_rendered_targets(project, rendered)
|
|
7
|
+
def layout_rendered_targets(project, rendered, previous_lockfile = project.previous_lockfile)
|
|
8
8
|
rendered.map do |target|
|
|
9
9
|
PathSafety.validate_destination_path!(target.path)
|
|
10
10
|
RenderDest.ensure_safe_destination_ancestors!(project.project_root, target.path, target.path)
|
|
11
11
|
path = File.join(project.project_root, target.path)
|
|
12
|
-
|
|
12
|
+
retired = RenderReconcile.retired_span_checksums(previous_lockfile, target)
|
|
13
|
+
content = RenderDest.layout_rendered_content(path, target.path, target.content, retired)
|
|
13
14
|
RenderedTarget.new(
|
|
14
15
|
path: target.path,
|
|
15
16
|
content: content,
|
data/lib/pray/render_patch.rb
CHANGED
|
@@ -4,11 +4,11 @@ module Pray
|
|
|
4
4
|
module RenderPatch
|
|
5
5
|
module_function
|
|
6
6
|
|
|
7
|
-
def patch_rendered_content(existing, fresh)
|
|
8
|
-
existing_segments = split_segments(existing)
|
|
7
|
+
def patch_rendered_content(existing, fresh, retired = {})
|
|
9
8
|
fresh_segments = split_segments(fresh)
|
|
10
9
|
fresh_managed = managed_bodies(fresh_segments)
|
|
11
|
-
|
|
10
|
+
existing_segments = drop_unchanged_retired(split_segments(existing), fresh_managed, retired)
|
|
11
|
+
return preserve_unmatched_managed(fresh, existing_segments, fresh_managed) unless overlapping_managed?(existing_segments, fresh_managed)
|
|
12
12
|
|
|
13
13
|
used = {}
|
|
14
14
|
output = +""
|
|
@@ -24,6 +24,28 @@ module Pray
|
|
|
24
24
|
output.end_with?("\n") ? output : "#{output}\n"
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
def drop_unchanged_retired(segments, fresh_managed, retired)
|
|
28
|
+
segments.reject do |segment|
|
|
29
|
+
next false unless segment[:kind] == :managed
|
|
30
|
+
next false if fresh_managed.key?(segment[:id])
|
|
31
|
+
|
|
32
|
+
expected = retired[segment[:id]]
|
|
33
|
+
expected && Hashing.checksum_managed_span_content(segment[:body]) == expected
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def preserve_unmatched_managed(fresh, segments, fresh_managed)
|
|
38
|
+
unmatched = segments.select do |segment|
|
|
39
|
+
segment[:kind] == :managed && !fresh_managed.key?(segment[:id])
|
|
40
|
+
end
|
|
41
|
+
return fresh if unmatched.empty?
|
|
42
|
+
|
|
43
|
+
output = fresh.dup
|
|
44
|
+
output << "\n" unless output.empty? || output.end_with?("\n")
|
|
45
|
+
unmatched.each { |segment| output << managed_segment(segment[:id], segment[:body]) }
|
|
46
|
+
output
|
|
47
|
+
end
|
|
48
|
+
|
|
27
49
|
def managed_bodies(segments)
|
|
28
50
|
segments.filter_map { |segment| [segment[:id], segment[:body]] if segment[:kind] == :managed }.to_h
|
|
29
51
|
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module RenderReconcile
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def reconcile_content(existing, fresh, retired = {})
|
|
8
|
+
RenderPatch.patch_rendered_content(existing, fresh, retired)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def current?(path, display, fresh, retired = {})
|
|
12
|
+
kind = RenderDest.destination_kind(path)
|
|
13
|
+
return false if kind == :missing
|
|
14
|
+
|
|
15
|
+
RenderDest.fail_if_symlink!(path, display)
|
|
16
|
+
unless kind == :regular
|
|
17
|
+
raise Error.render("refusing to read `#{display}`; destination is not a regular file")
|
|
18
|
+
end
|
|
19
|
+
existing = RenderDest.decode_utf8(RenderDest.read_regular_bytes(path, display), display)
|
|
20
|
+
existing == reconcile_content(existing, fresh, retired)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def retired_span_checksums(previous_lockfile, target)
|
|
24
|
+
current_ids = target.managed_spans.to_h { |span| [span.id, true] }
|
|
25
|
+
Array(previous_lockfile&.managed_span).filter_map do |span|
|
|
26
|
+
next unless span.target == target.path
|
|
27
|
+
next if current_ids[span.id]
|
|
28
|
+
|
|
29
|
+
[span.id, span.ideal_checksum]
|
|
30
|
+
end.to_h
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def reject_managed_span_conflicts!(project, rendered, previous_lockfile)
|
|
34
|
+
active_by_target = rendered.to_h do |target|
|
|
35
|
+
[target.path, target.managed_spans.to_h { |span| [span.id, true] }]
|
|
36
|
+
end
|
|
37
|
+
Array(previous_lockfile.managed_span).group_by(&:target).each do |target_path, spans|
|
|
38
|
+
active = active_by_target[target_path]
|
|
39
|
+
next unless active
|
|
40
|
+
|
|
41
|
+
PathSafety.validate_destination_path!(target_path)
|
|
42
|
+
RenderDest.ensure_safe_destination_ancestors!(project.project_root, target_path, target_path)
|
|
43
|
+
path = File.join(project.project_root, target_path)
|
|
44
|
+
next unless File.file?(path)
|
|
45
|
+
|
|
46
|
+
content = RenderDest.decode_utf8(RenderDest.read_regular_bytes(path, target_path), target_path)
|
|
47
|
+
bodies = RenderPatch.managed_bodies(RenderPatch.split_segments(content))
|
|
48
|
+
spans.each do |span|
|
|
49
|
+
next unless active[span.id] && bodies.key?(span.id)
|
|
50
|
+
next if Hashing.checksum_managed_span_content(bodies[span.id]) == span.ideal_checksum
|
|
51
|
+
|
|
52
|
+
raise Error.render(
|
|
53
|
+
"conflict: managed span `#{span.id}` in `#{target_path}` was edited " \
|
|
54
|
+
"(`#{span.package}::#{span.export}`)"
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/pray/resolve.rb
CHANGED
|
@@ -100,6 +100,7 @@ module Pray
|
|
|
100
100
|
raise Error.resolution(local_errors.join("\n")) unless local_errors.empty?
|
|
101
101
|
|
|
102
102
|
ResolveDeps.reject_dependency_cycles(packages)
|
|
103
|
+
ResolveDeps.validate_optional_referrals(packages)
|
|
103
104
|
source_revisions = git_sources.revisions
|
|
104
105
|
|
|
105
106
|
ResolvedProject.new(
|
data/lib/pray/resolve_deps.rb
CHANGED
|
@@ -7,12 +7,29 @@ module Pray
|
|
|
7
7
|
def reject_dependency_cycles(packages)
|
|
8
8
|
edges = {}
|
|
9
9
|
packages.each do |package|
|
|
10
|
-
edges[package.declaration.name] = package.spec.dependencies.map(&:name)
|
|
10
|
+
edges[package.declaration.name] = package.spec.dependencies.reject(&:optional).map(&:name)
|
|
11
11
|
end
|
|
12
12
|
cycle = DependencyGraph.find_dependency_cycle(edges)
|
|
13
13
|
return unless cycle
|
|
14
14
|
|
|
15
15
|
raise Error.resolution("dependency cycle detected: #{cycle.join(" -> ")}")
|
|
16
16
|
end
|
|
17
|
+
|
|
18
|
+
def validate_optional_referrals(packages)
|
|
19
|
+
packages_by_name = packages.to_h { |package| [package.declaration.name, package] }
|
|
20
|
+
packages.each do |package|
|
|
21
|
+
package.spec.dependencies.select(&:optional).each do |dependency|
|
|
22
|
+
target = packages_by_name[dependency.name]
|
|
23
|
+
next unless target
|
|
24
|
+
|
|
25
|
+
target.spec.satisfy_constraint!(dependency.constraint)
|
|
26
|
+
rescue Error
|
|
27
|
+
raise Error.resolution(
|
|
28
|
+
"optional referral #{package.declaration.name} -> #{dependency.name} requires " \
|
|
29
|
+
"#{dependency.constraint}, but selected version is #{target.spec.recorded_version}"
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
17
34
|
end
|
|
18
35
|
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
5
|
+
module Pray
|
|
6
|
+
module UrlRedaction
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def redact_userinfo(url)
|
|
10
|
+
uri = URI(url)
|
|
11
|
+
return url unless uri.user || uri.password
|
|
12
|
+
|
|
13
|
+
uri.user = "***"
|
|
14
|
+
uri.password = nil
|
|
15
|
+
uri.to_s
|
|
16
|
+
rescue URI::InvalidURIError
|
|
17
|
+
url
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/pray/verify.rb
CHANGED
|
@@ -36,11 +36,16 @@ module Pray
|
|
|
36
36
|
|
|
37
37
|
def drift_project(project, lockfile)
|
|
38
38
|
report, rendered_targets, fresh_targets = collect_verification_report(project, lockfile)
|
|
39
|
-
fresh_targets.each do |path,
|
|
40
|
-
normalized_fresh = Hashing.normalize_line_endings(fresh_content)
|
|
39
|
+
fresh_targets.each do |path, fresh_target|
|
|
41
40
|
on_disk = rendered_targets[path]
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
retired = RenderReconcile.retired_span_checksums(lockfile, fresh_target)
|
|
42
|
+
expected = if on_disk
|
|
43
|
+
RenderReconcile.reconcile_content(on_disk, fresh_target.content, retired)
|
|
44
|
+
else
|
|
45
|
+
fresh_target.content
|
|
46
|
+
end
|
|
47
|
+
normalized_on_disk = Hashing.normalize_line_endings(on_disk) if on_disk
|
|
48
|
+
unless normalized_on_disk == Hashing.normalize_line_endings(expected)
|
|
44
49
|
report.findings << VerificationFinding.new(
|
|
45
50
|
kind: "renderer_drift",
|
|
46
51
|
message: "#{path} differs from fresh render"
|
|
@@ -64,7 +69,7 @@ module Pray
|
|
|
64
69
|
def collect_verification_report(project, lockfile)
|
|
65
70
|
report = VerificationReport.new
|
|
66
71
|
rendered_targets = {}
|
|
67
|
-
fresh_targets = Render.render_project(project).to_h { |target| [target.path, target
|
|
72
|
+
fresh_targets = Render.render_project(project).to_h { |target| [target.path, target] }
|
|
68
73
|
|
|
69
74
|
if project.manifest_hash != lockfile.manifest_hash
|
|
70
75
|
report.findings << VerificationFinding.new(
|
|
@@ -104,6 +109,7 @@ module Pray
|
|
|
104
109
|
end
|
|
105
110
|
|
|
106
111
|
target_spans = lockfile.managed_span.group_by(&:target)
|
|
112
|
+
fresh_targets.each_key { |target_path| target_spans[target_path] ||= [] }
|
|
107
113
|
target_spans.each do |target_path, spans|
|
|
108
114
|
absolute_path = File.join(project.project_root, target_path)
|
|
109
115
|
unless File.exist?(absolute_path)
|
|
@@ -135,7 +141,7 @@ module Pray
|
|
|
135
141
|
end
|
|
136
142
|
end
|
|
137
143
|
end
|
|
138
|
-
fresh_lines = fresh_targets[target_path]&.lines(chomp: true)
|
|
144
|
+
fresh_lines = fresh_targets[target_path]&.content&.lines(chomp: true)
|
|
139
145
|
summary = VerifyPosition.summarize_position_drift(
|
|
140
146
|
target_path,
|
|
141
147
|
spans,
|
|
@@ -177,7 +183,7 @@ module Pray
|
|
|
177
183
|
|
|
178
184
|
VerificationFinding.new(
|
|
179
185
|
kind: "orphan_marker",
|
|
180
|
-
message: "`#{target_path}` contains marker `#{marker_id}` that is not tracked in `Prayfile.lock`.
|
|
186
|
+
message: "`#{target_path}` contains marker `#{marker_id}` that is not tracked in `Prayfile.lock`. Inspect and remove the block explicitly."
|
|
181
187
|
)
|
|
182
188
|
end
|
|
183
189
|
end
|
data/lib/pray/version.rb
CHANGED
data/lib/pray.rb
CHANGED
|
@@ -15,6 +15,7 @@ require_relative "pray/destination"
|
|
|
15
15
|
require_relative "pray/manifest"
|
|
16
16
|
require_relative "pray/format_serialize"
|
|
17
17
|
require_relative "pray/format_manifest"
|
|
18
|
+
require_relative "pray/package_relation"
|
|
18
19
|
require_relative "pray/package_spec"
|
|
19
20
|
require_relative "pray/package_spec_paths"
|
|
20
21
|
require_relative "pray/package_spec_version"
|
|
@@ -52,6 +53,7 @@ require_relative "pray/render_content"
|
|
|
52
53
|
require_relative "pray/render_managed"
|
|
53
54
|
require_relative "pray/render"
|
|
54
55
|
require_relative "pray/render_dest"
|
|
56
|
+
require_relative "pray/render_reconcile"
|
|
55
57
|
require_relative "pray/transaction"
|
|
56
58
|
require_relative "pray/render_layout"
|
|
57
59
|
require_relative "pray/verify_position"
|
|
@@ -60,9 +62,11 @@ require_relative "pray/verify"
|
|
|
60
62
|
require_relative "pray/verify_locked_dest"
|
|
61
63
|
require_relative "pray/resource_limits"
|
|
62
64
|
require_relative "pray/http_body"
|
|
65
|
+
require_relative "pray/url_redaction"
|
|
63
66
|
require_relative "pray/registry_install"
|
|
64
67
|
require_relative "pray/registry_integrity"
|
|
65
68
|
require_relative "pray/registry"
|
|
69
|
+
require_relative "pray/registry_search"
|
|
66
70
|
require_relative "pray/derived_metadata"
|
|
67
71
|
require_relative "pray/archive_unpack"
|
|
68
72
|
require_relative "pray/archive"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pray-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.26.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrei Makarov
|
|
@@ -115,6 +115,7 @@ files:
|
|
|
115
115
|
- lib/pray/cli/commands/init_prayer_manifest.rb
|
|
116
116
|
- lib/pray/cli/commands/meta.rb
|
|
117
117
|
- lib/pray/cli/commands/packages.rb
|
|
118
|
+
- lib/pray/cli/commands/search.rb
|
|
118
119
|
- lib/pray/cli/commands/trust.rb
|
|
119
120
|
- lib/pray/cli/commands/update_latest.rb
|
|
120
121
|
- lib/pray/cli/commands/workflow.rb
|
|
@@ -161,6 +162,7 @@ files:
|
|
|
161
162
|
- lib/pray/manifest_parser_helpers.rb
|
|
162
163
|
- lib/pray/manifest_parser_publish.rb
|
|
163
164
|
- lib/pray/materialize.rb
|
|
165
|
+
- lib/pray/package_relation.rb
|
|
164
166
|
- lib/pray/package_spec.rb
|
|
165
167
|
- lib/pray/package_spec_paths.rb
|
|
166
168
|
- lib/pray/package_spec_render.rb
|
|
@@ -176,6 +178,7 @@ files:
|
|
|
176
178
|
- lib/pray/registry_install.rb
|
|
177
179
|
- lib/pray/registry_integrity.rb
|
|
178
180
|
- lib/pray/registry_paths.rb
|
|
181
|
+
- lib/pray/registry_search.rb
|
|
179
182
|
- lib/pray/render.rb
|
|
180
183
|
- lib/pray/render_content.rb
|
|
181
184
|
- lib/pray/render_dest.rb
|
|
@@ -183,6 +186,7 @@ files:
|
|
|
183
186
|
- lib/pray/render_managed.rb
|
|
184
187
|
- lib/pray/render_patch.rb
|
|
185
188
|
- lib/pray/render_project.rb
|
|
189
|
+
- lib/pray/render_reconcile.rb
|
|
186
190
|
- lib/pray/resolve.rb
|
|
187
191
|
- lib/pray/resolve_context.rb
|
|
188
192
|
- lib/pray/resolve_deps.rb
|
|
@@ -216,6 +220,7 @@ files:
|
|
|
216
220
|
- lib/pray/upstream_merge.rb
|
|
217
221
|
- lib/pray/upstream_plan.rb
|
|
218
222
|
- lib/pray/upstream_refresh.rb
|
|
223
|
+
- lib/pray/url_redaction.rb
|
|
219
224
|
- lib/pray/verify.rb
|
|
220
225
|
- lib/pray/verify_locked_dest.rb
|
|
221
226
|
- lib/pray/verify_position.rb
|