pray-cli 1.12.1 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/pray/cli/commands/workflow.rb +2 -0
- data/lib/pray/lockfile.rb +9 -5
- data/lib/pray/lockfile_serialize.rb +19 -0
- data/lib/pray/package_spec.rb +14 -2
- data/lib/pray/resolve.rb +9 -5
- data/lib/pray/upstream.rb +104 -0
- data/lib/pray/version.rb +2 -2
- data/lib/pray.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 55a5d9fd2741f9ecd2d6d41c18acf6c7358b8bedb15e874d3686ce4ac88c7898
|
|
4
|
+
data.tar.gz: 489b7b073d8194c8f90fbbbab0b757804cc05a9ee309d7e596ce8a894ead1666
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 005a627e411946e40ae7b782feb62737b8d49a3eef411fda42ecd90c705c252414e504f231f94f24f5e687b035562233ba68f424abe49d2d541700b281493406
|
|
7
|
+
data.tar.gz: 80f998bf51a0fa32bf40d36b38f9a1101affdd988a0cb938e34b637a8225d3903d5c98bb217a88dab2ceb99849cd11957748d22d612e4f593f082f0d40122132
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 1.13.0 (2026-09-08)
|
|
6
|
+
|
|
7
|
+
- Record and verify package upstream pins in `.prayspec` and `Prayfile.lock`. Refuse path-fork updates until this CLI can refresh the path tree safely (RFC 0114).
|
|
8
|
+
|
|
5
9
|
## 1.12.1 (2026-09-08)
|
|
6
10
|
|
|
7
11
|
- Refresh a locked git catalog during `pray install` when a newly declared package is missing from the pinned revision, and name that revision with `pray update` if it is still missing.
|
|
@@ -100,6 +100,8 @@ module Pray
|
|
|
100
100
|
raise Error.manifest("package #{package} not found")
|
|
101
101
|
end
|
|
102
102
|
end
|
|
103
|
+
current = resolve_current_project(ResolveOptions.new(offline: offline))
|
|
104
|
+
Upstream.ensure_update_supported!(current.packages, package)
|
|
103
105
|
install_command({locked: false, frozen: false, offline: offline, refresh: true})
|
|
104
106
|
end
|
|
105
107
|
|
data/lib/pray/lockfile.rb
CHANGED
|
@@ -8,14 +8,15 @@ module Pray
|
|
|
8
8
|
LockSource = Struct.new(:name, :kind, :url, :revision, :host_key_fingerprint)
|
|
9
9
|
LockedPackage = Struct.new(
|
|
10
10
|
:name, :version, :source, :path, :tree_hash, :artifact_hash, :artifact,
|
|
11
|
-
:exports, :dependencies, :signer_fingerprint
|
|
11
|
+
:exports, :dependencies, :signer_fingerprint, :upstream
|
|
12
12
|
) do
|
|
13
|
-
def initialize(exports: [], dependencies: [], signer_fingerprint: nil, source: nil, **kwargs)
|
|
14
|
-
super(**kwargs, exports: exports, dependencies: dependencies, signer_fingerprint: signer_fingerprint, source: source)
|
|
13
|
+
def initialize(exports: [], dependencies: [], signer_fingerprint: nil, source: nil, upstream: nil, **kwargs)
|
|
14
|
+
super(**kwargs, exports: exports, dependencies: dependencies, signer_fingerprint: signer_fingerprint, source: source, upstream: upstream)
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
LockedTarget = Struct.new(:name, :outputs)
|
|
19
|
+
LockedUpstream = Struct.new(:name, :version, :source, :tree_hash, :artifact_hash, keyword_init: true)
|
|
19
20
|
ManagedSpanRecord = Struct.new(
|
|
20
21
|
:id, :target, :open_line, :close_line, :ideal_checksum, :package, :export,
|
|
21
22
|
:source_checksum, :silenced
|
|
@@ -98,6 +99,7 @@ module Pray
|
|
|
98
99
|
}
|
|
99
100
|
hash["source"] = entry.source unless entry.source.nil?
|
|
100
101
|
hash["signer_fingerprint"] = entry.signer_fingerprint if entry.signer_fingerprint
|
|
102
|
+
hash["upstream"] = Upstream.to_lock_hash(entry.upstream) if entry.upstream
|
|
101
103
|
hash
|
|
102
104
|
end
|
|
103
105
|
|
|
@@ -185,7 +187,8 @@ module Pray
|
|
|
185
187
|
artifact: normalize_lockfile_artifact(project_root, package.artifact, package.root),
|
|
186
188
|
exports: package.selected_exports,
|
|
187
189
|
dependencies: package.spec.dependencies.map(&:name),
|
|
188
|
-
signer_fingerprint: package.signer_fingerprint
|
|
190
|
+
signer_fingerprint: package.signer_fingerprint,
|
|
191
|
+
upstream: package.upstream
|
|
189
192
|
)
|
|
190
193
|
end,
|
|
191
194
|
target: manifest_targets.map { |target| LockedTarget.new(name: target.name, outputs: target.outputs) },
|
|
@@ -224,7 +227,8 @@ module Pray
|
|
|
224
227
|
artifact: entry["artifact"],
|
|
225
228
|
exports: entry["exports"] || [],
|
|
226
229
|
dependencies: entry["dependencies"] || [],
|
|
227
|
-
signer_fingerprint: entry["signer_fingerprint"]
|
|
230
|
+
signer_fingerprint: entry["signer_fingerprint"],
|
|
231
|
+
upstream: Upstream.from_lock_hash(entry["upstream"])
|
|
228
232
|
)
|
|
229
233
|
end,
|
|
230
234
|
target: Array(data["target"]).map { |entry| LockedTarget.new(name: entry["name"], outputs: entry["outputs"] || []) },
|
|
@@ -66,6 +66,25 @@ module Pray
|
|
|
66
66
|
lines << "exports = #{format_string_array(entry.exports)}"
|
|
67
67
|
lines << "dependencies = #{format_string_array(entry.dependencies)}"
|
|
68
68
|
lines << "signer_fingerprint = #{format_string(entry.signer_fingerprint)}" if entry.signer_fingerprint
|
|
69
|
+
if entry.upstream
|
|
70
|
+
lines << ""
|
|
71
|
+
lines << "[package.upstream]"
|
|
72
|
+
append_scalars(
|
|
73
|
+
lines,
|
|
74
|
+
[
|
|
75
|
+
["name", entry.upstream.name],
|
|
76
|
+
["version", entry.upstream.version]
|
|
77
|
+
].tap do |scalars|
|
|
78
|
+
scalars << ["source", entry.upstream.source] unless entry.upstream.source.nil?
|
|
79
|
+
scalars.concat(
|
|
80
|
+
[
|
|
81
|
+
["tree_hash", entry.upstream.tree_hash],
|
|
82
|
+
["artifact_hash", entry.upstream.artifact_hash]
|
|
83
|
+
]
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
)
|
|
87
|
+
end
|
|
69
88
|
lines
|
|
70
89
|
end
|
|
71
90
|
|
data/lib/pray/package_spec.rb
CHANGED
|
@@ -9,17 +9,18 @@ module Pray
|
|
|
9
9
|
PackageSkill = Struct.new(:path, :summary)
|
|
10
10
|
PackageTemplate = Struct.new(:path, :summary)
|
|
11
11
|
PackageDependency = Struct.new(:name, :constraint, :optional)
|
|
12
|
+
PackageUpstream = Struct.new(:name, :constraint, keyword_init: true)
|
|
12
13
|
|
|
13
14
|
PackageSpec = Struct.new(
|
|
14
15
|
:name, :version, :summary, :description, :authors, :license, :homepage,
|
|
15
16
|
:source_code_uri, :changelog_uri, :prayfile_version, :files, :exports,
|
|
16
|
-
:skills, :templates, :adapters, :targets, :dependencies, :metadata
|
|
17
|
+
:skills, :templates, :adapters, :targets, :dependencies, :metadata, :upstream
|
|
17
18
|
) do
|
|
18
19
|
def initialize(
|
|
19
20
|
name: "", version: "", summary: nil, description: nil, authors: [], license: nil,
|
|
20
21
|
homepage: nil, source_code_uri: nil, changelog_uri: nil, prayfile_version: nil,
|
|
21
22
|
files: [], exports: {}, skills: {}, templates: {}, adapters: {}, targets: [],
|
|
22
|
-
dependencies: [], metadata: {}
|
|
23
|
+
dependencies: [], metadata: {}, upstream: nil
|
|
23
24
|
)
|
|
24
25
|
super
|
|
25
26
|
end
|
|
@@ -90,6 +91,13 @@ module Pray
|
|
|
90
91
|
)
|
|
91
92
|
end
|
|
92
93
|
|
|
94
|
+
def parse_upstream(rest)
|
|
95
|
+
values, _keywords = parse_call(rest)
|
|
96
|
+
name = string_from_value(values.first)
|
|
97
|
+
constraint = values[1] ? string_from_value(values[1]) : "*"
|
|
98
|
+
PackageUpstream.new(name: name, constraint: constraint)
|
|
99
|
+
end
|
|
100
|
+
|
|
93
101
|
def parse_exports(value)
|
|
94
102
|
map = Literal.parse_literal_map(value)
|
|
95
103
|
exports = {}
|
|
@@ -208,6 +216,10 @@ module Pray
|
|
|
208
216
|
spec.dependencies << parse_dependency(Regexp.last_match(1), false)
|
|
209
217
|
when /\Aspec\.add_optional_dependency (.+)\z/
|
|
210
218
|
spec.dependencies << parse_dependency(Regexp.last_match(1), true)
|
|
219
|
+
when /\Aspec\.upstream (.+)\z/
|
|
220
|
+
raise Error.parse("prayspec", "upstream may only be declared once") if spec.upstream
|
|
221
|
+
|
|
222
|
+
spec.upstream = parse_upstream(Regexp.last_match(1))
|
|
211
223
|
when /\Aspec\.(.+) = (.+)\z/
|
|
212
224
|
apply_assignment(spec, Regexp.last_match(1).strip, Regexp.last_match(2).strip)
|
|
213
225
|
else
|
data/lib/pray/resolve.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Pray
|
|
|
13
13
|
ResolvedPackage = Struct.new(
|
|
14
14
|
:declaration, :root, :spec, :tree_hash, :artifact_hash, :artifact,
|
|
15
15
|
:selected_exports, :source_checksum, :export_bodies, :skill_files,
|
|
16
|
-
:signer_fingerprint, :registry_latest_version
|
|
16
|
+
:signer_fingerprint, :registry_latest_version, :upstream
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
ResolvedLocalFile = Struct.new(
|
|
@@ -75,7 +75,7 @@ module Pray
|
|
|
75
75
|
user_config,
|
|
76
76
|
declaration,
|
|
77
77
|
lockfile_hints,
|
|
78
|
-
|
|
78
|
+
options: options
|
|
79
79
|
)
|
|
80
80
|
if seen[package.declaration.name]
|
|
81
81
|
raise Error.resolution("duplicate package declaration: #{package.declaration.name}")
|
|
@@ -149,9 +149,10 @@ module Pray
|
|
|
149
149
|
"Create the file or remove the entry from Prayfile, then run `pray install`."
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
-
def resolve_package(project_root, sources, git_sources, user_config, declaration, lockfile, offline: false)
|
|
152
|
+
def resolve_package(project_root, sources, git_sources, user_config, declaration, lockfile, offline: false, options: nil)
|
|
153
|
+
options ||= ResolveOptions.new(offline: offline)
|
|
153
154
|
root, registry_latest_version = resolve_package_root_with_metadata(
|
|
154
|
-
project_root, sources, git_sources, user_config, declaration, lockfile, offline: offline
|
|
155
|
+
project_root, sources, git_sources, user_config, declaration, lockfile, offline: options.offline
|
|
155
156
|
)
|
|
156
157
|
spec_path = find_prayspec_file(root)
|
|
157
158
|
spec_text = File.read(spec_path)
|
|
@@ -185,7 +186,10 @@ module Pray
|
|
|
185
186
|
export_bodies: export_bodies,
|
|
186
187
|
skill_files: skill_files,
|
|
187
188
|
signer_fingerprint: nil,
|
|
188
|
-
registry_latest_version: registry_latest_version
|
|
189
|
+
registry_latest_version: registry_latest_version,
|
|
190
|
+
upstream: Upstream.lock_path(
|
|
191
|
+
project_root, sources, git_sources, user_config, declaration, spec, lockfile, options
|
|
192
|
+
)
|
|
189
193
|
)
|
|
190
194
|
end
|
|
191
195
|
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module Upstream
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def ensure_update_supported!(packages, selected = nil)
|
|
8
|
+
unsupported = packages.find do |package|
|
|
9
|
+
package.declaration.path && package.spec.upstream &&
|
|
10
|
+
(selected.nil? || package.declaration.name == selected)
|
|
11
|
+
end
|
|
12
|
+
return unless unsupported
|
|
13
|
+
|
|
14
|
+
raise Error.unsupported(
|
|
15
|
+
"this installation cannot refresh upstream package #{unsupported.declaration.name}; " \
|
|
16
|
+
"install pray with Cargo and retry"
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_lock_hash(entry)
|
|
21
|
+
hash = {
|
|
22
|
+
"name" => entry.name,
|
|
23
|
+
"version" => entry.version,
|
|
24
|
+
"tree_hash" => entry.tree_hash,
|
|
25
|
+
"artifact_hash" => entry.artifact_hash
|
|
26
|
+
}
|
|
27
|
+
hash["source"] = entry.source unless entry.source.nil?
|
|
28
|
+
hash
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def from_lock_hash(entry)
|
|
32
|
+
return nil if entry.nil?
|
|
33
|
+
|
|
34
|
+
LockedUpstream.new(
|
|
35
|
+
name: entry["name"],
|
|
36
|
+
version: entry["version"],
|
|
37
|
+
source: entry["source"],
|
|
38
|
+
tree_hash: entry["tree_hash"],
|
|
39
|
+
artifact_hash: entry["artifact_hash"]
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def lock_path(project_root, sources, git_sources, user_config, declaration, spec, lockfile, options)
|
|
44
|
+
return nil unless spec.upstream
|
|
45
|
+
if spec.name == spec.upstream.name
|
|
46
|
+
raise Error.resolution("package #{spec.name} cannot use itself as upstream")
|
|
47
|
+
end
|
|
48
|
+
return nil unless declaration.path
|
|
49
|
+
|
|
50
|
+
refresh = options.ignore_locked_versions || options.unlocked_packages.include?(declaration.name)
|
|
51
|
+
locked = lockfile&.package&.find { |entry| entry.name == declaration.name }&.upstream
|
|
52
|
+
name, constraint, source = resolution_input(declaration, spec, sources, locked, refresh)
|
|
53
|
+
resolved = Resolve.resolve_package(
|
|
54
|
+
project_root,
|
|
55
|
+
sources,
|
|
56
|
+
git_sources,
|
|
57
|
+
user_config,
|
|
58
|
+
ManifestPackage.new(
|
|
59
|
+
name: name,
|
|
60
|
+
constraint: constraint,
|
|
61
|
+
source: source
|
|
62
|
+
),
|
|
63
|
+
lockfile,
|
|
64
|
+
options: options
|
|
65
|
+
)
|
|
66
|
+
resolved_upstream = LockedUpstream.new(
|
|
67
|
+
name: name,
|
|
68
|
+
version: resolved.spec.version,
|
|
69
|
+
source: source,
|
|
70
|
+
tree_hash: resolved.tree_hash,
|
|
71
|
+
artifact_hash: resolved.artifact_hash
|
|
72
|
+
)
|
|
73
|
+
ensure_locked_match!(locked, resolved_upstream) if !refresh && locked
|
|
74
|
+
resolved_upstream
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def resolution_input(declaration, spec, sources, locked, refresh)
|
|
78
|
+
if locked && !refresh
|
|
79
|
+
if locked.name != spec.upstream.name
|
|
80
|
+
raise Error.integrity(
|
|
81
|
+
"locked upstream name mismatch for #{declaration.name}: " \
|
|
82
|
+
"expected #{locked.name}, found #{spec.upstream.name}"
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
return [locked.name, "= #{locked.version}", locked.source]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
name = spec.upstream.name
|
|
89
|
+
source = ResolveSource.implied_source_name(ManifestPackage.new(name: name), sources)
|
|
90
|
+
[name, spec.upstream.constraint, source]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def ensure_locked_match!(locked, resolved)
|
|
94
|
+
if locked.name != resolved.name || locked.version != resolved.version
|
|
95
|
+
raise Error.integrity("locked upstream identity mismatch")
|
|
96
|
+
end
|
|
97
|
+
raise Error.integrity("locked upstream source mismatch") if locked.source != resolved.source
|
|
98
|
+
raise Error.integrity("locked upstream tree hash mismatch") if locked.tree_hash != resolved.tree_hash
|
|
99
|
+
if locked.artifact_hash != resolved.artifact_hash
|
|
100
|
+
raise Error.integrity("locked upstream artifact hash mismatch")
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
data/lib/pray/version.rb
CHANGED
data/lib/pray.rb
CHANGED
|
@@ -24,6 +24,7 @@ require_relative "pray/resolve_exports"
|
|
|
24
24
|
require_relative "pray/invocation"
|
|
25
25
|
require_relative "pray/git_refresh"
|
|
26
26
|
require_relative "pray/resolve"
|
|
27
|
+
require_relative "pray/upstream"
|
|
27
28
|
require_relative "pray/compose_dest"
|
|
28
29
|
require_relative "pray/render_patch"
|
|
29
30
|
require_relative "pray/render"
|
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.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrei Makarov
|
|
@@ -180,6 +180,7 @@ files:
|
|
|
180
180
|
- lib/pray/trust.rb
|
|
181
181
|
- lib/pray/trust_feed.rb
|
|
182
182
|
- lib/pray/trust_ops.rb
|
|
183
|
+
- lib/pray/upstream.rb
|
|
183
184
|
- lib/pray/verify.rb
|
|
184
185
|
- lib/pray/verify_position.rb
|
|
185
186
|
- lib/pray/verify_provisioned.rb
|