pray-cli 1.14.0 → 1.16.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 +14 -0
- data/lib/pray/archive.rb +21 -2
- data/lib/pray/cli/commands/update_latest.rb +94 -0
- data/lib/pray/cli/commands/workflow.rb +28 -6
- data/lib/pray/cli/help.rb +5 -1
- data/lib/pray/cli.rb +4 -0
- data/lib/pray/constraint.rb +17 -4
- data/lib/pray/dependency_graph.rb +43 -0
- data/lib/pray/git_sources.rb +11 -10
- data/lib/pray/materialize.rb +7 -1
- data/lib/pray/package_spec_render.rb +143 -0
- data/lib/pray/path_safety.rb +8 -4
- data/lib/pray/registry.rb +12 -0
- data/lib/pray/registry_paths.rb +14 -0
- data/lib/pray/resolve.rb +12 -14
- data/lib/pray/resolve_context.rb +7 -0
- data/lib/pray/resolve_deps.rb +18 -0
- data/lib/pray/resolve_tarball.rb +66 -0
- data/lib/pray/transaction.rb +7 -0
- data/lib/pray/upstream.rb +0 -13
- data/lib/pray/upstream_latest.rb +88 -0
- data/lib/pray/upstream_merge.rb +81 -0
- data/lib/pray/upstream_refresh.rb +144 -0
- data/lib/pray/verify_locked_dest.rb +47 -0
- data/lib/pray/version.rb +2 -2
- data/lib/pray.rb +9 -1
- metadata +11 -1
data/lib/pray/resolve.rb
CHANGED
|
@@ -98,6 +98,8 @@ module Pray
|
|
|
98
98
|
end
|
|
99
99
|
raise Error.resolution(local_errors.join("\n")) unless local_errors.empty?
|
|
100
100
|
|
|
101
|
+
ResolveDeps.reject_dependency_cycles(packages)
|
|
102
|
+
|
|
101
103
|
ResolvedProject.new(
|
|
102
104
|
manifest_path: manifest_path,
|
|
103
105
|
project_root: project_root,
|
|
@@ -152,7 +154,7 @@ module Pray
|
|
|
152
154
|
def resolve_package(project_root, sources, git_sources, user_config, declaration, lockfile, offline: false, options: nil)
|
|
153
155
|
options ||= ResolveOptions.new(offline: offline)
|
|
154
156
|
root, registry_latest_version = resolve_package_root_with_metadata(
|
|
155
|
-
project_root, sources, git_sources, user_config, declaration, lockfile,
|
|
157
|
+
project_root, sources, git_sources, user_config, declaration, lockfile, options
|
|
156
158
|
)
|
|
157
159
|
spec_path = find_prayspec_file(root)
|
|
158
160
|
spec_text = File.read(spec_path)
|
|
@@ -194,12 +196,16 @@ module Pray
|
|
|
194
196
|
end
|
|
195
197
|
|
|
196
198
|
def resolve_package_root_with_metadata(
|
|
197
|
-
project_root, sources, git_sources, user_config, declaration, lockfile,
|
|
199
|
+
project_root, sources, git_sources, user_config, declaration, lockfile, options = nil
|
|
198
200
|
)
|
|
201
|
+
options ||= ResolveOptions.new
|
|
202
|
+
offline = options.offline
|
|
203
|
+
preferred_version = options.preferred_lock_version(lockfile, declaration.name)
|
|
199
204
|
if (local_path = user_config.local.package[declaration.name])
|
|
200
205
|
return [File.expand_path(local_path, project_root), nil]
|
|
201
206
|
end
|
|
202
207
|
return [File.expand_path(declaration.path, project_root), nil] if declaration.path
|
|
208
|
+
return [ResolveTarball.package_root(project_root, declaration.tarball, offline: offline), nil] if declaration.tarball
|
|
203
209
|
source_name = ResolveSource.implied_source_name(declaration, sources)
|
|
204
210
|
if source_name
|
|
205
211
|
source = sources[source_name]
|
|
@@ -212,7 +218,7 @@ module Pray
|
|
|
212
218
|
"local:#{source_name}",
|
|
213
219
|
source_root,
|
|
214
220
|
declaration,
|
|
215
|
-
preferred_version:
|
|
221
|
+
preferred_version: preferred_version,
|
|
216
222
|
offline: offline
|
|
217
223
|
)
|
|
218
224
|
return [resolved.root, resolved.registry_latest_version]
|
|
@@ -226,7 +232,7 @@ module Pray
|
|
|
226
232
|
project_root,
|
|
227
233
|
source.url,
|
|
228
234
|
declaration,
|
|
229
|
-
preferred_version:
|
|
235
|
+
preferred_version: preferred_version,
|
|
230
236
|
offline: offline
|
|
231
237
|
)
|
|
232
238
|
return [resolved.root, resolved.registry_latest_version]
|
|
@@ -245,7 +251,7 @@ module Pray
|
|
|
245
251
|
source_key,
|
|
246
252
|
distribution_root,
|
|
247
253
|
declaration,
|
|
248
|
-
preferred_version:
|
|
254
|
+
preferred_version: preferred_version,
|
|
249
255
|
offline: offline
|
|
250
256
|
)
|
|
251
257
|
rescue Error => error
|
|
@@ -262,9 +268,7 @@ module Pray
|
|
|
262
268
|
end
|
|
263
269
|
end
|
|
264
270
|
|
|
265
|
-
|
|
266
|
-
raise Error.unsupported("remote sources are not implemented yet")
|
|
267
|
-
end
|
|
271
|
+
raise Error.unsupported("remote sources are not implemented yet") if declaration.git || declaration.oci
|
|
268
272
|
|
|
269
273
|
[File.join(project_root, declaration.name.tr("/", "-")), nil]
|
|
270
274
|
end
|
|
@@ -273,12 +277,6 @@ module Pray
|
|
|
273
277
|
resolve_package_root_with_metadata(project_root, sources, git_sources, user_config, declaration, lockfile).first
|
|
274
278
|
end
|
|
275
279
|
|
|
276
|
-
def lockfile_preferred_version(lockfile, package_name)
|
|
277
|
-
return nil unless lockfile
|
|
278
|
-
|
|
279
|
-
lockfile.package.find { |entry| entry.name == package_name }&.version
|
|
280
|
-
end
|
|
281
|
-
|
|
282
280
|
def resolve_local_file(project_root, declaration)
|
|
283
281
|
path = File.join(project_root, declaration.path)
|
|
284
282
|
unless File.exist?(path)
|
data/lib/pray/resolve_context.rb
CHANGED
|
@@ -15,5 +15,12 @@ module Pray
|
|
|
15
15
|
)
|
|
16
16
|
super
|
|
17
17
|
end
|
|
18
|
+
|
|
19
|
+
def preferred_lock_version(lockfile, package_name)
|
|
20
|
+
return nil unless lockfile
|
|
21
|
+
return nil if ignore_locked_versions || unlocked_packages.include?(package_name)
|
|
22
|
+
|
|
23
|
+
lockfile.package.find { |entry| entry.name == package_name }&.version
|
|
24
|
+
end
|
|
18
25
|
end
|
|
19
26
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module ResolveDeps
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def reject_dependency_cycles(packages)
|
|
8
|
+
edges = {}
|
|
9
|
+
packages.each do |package|
|
|
10
|
+
edges[package.declaration.name] = package.spec.dependencies.map(&:name)
|
|
11
|
+
end
|
|
12
|
+
cycle = DependencyGraph.find_dependency_cycle(edges)
|
|
13
|
+
return unless cycle
|
|
14
|
+
|
|
15
|
+
raise Error.resolution("dependency cycle detected: #{cycle.join(" -> ")}")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "pathname"
|
|
5
|
+
require_relative "archive_unpack"
|
|
6
|
+
require_relative "hashing"
|
|
7
|
+
require_relative "resource_limits"
|
|
8
|
+
|
|
9
|
+
module Pray
|
|
10
|
+
module ResolveTarball
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def package_root(project_root, tarball, offline:)
|
|
14
|
+
artifact_bytes = read_tarball_bytes(project_root, tarball, offline: offline)
|
|
15
|
+
if artifact_bytes.bytesize > ResourceLimits::MAX_ARCHIVE_TOTAL_BYTES
|
|
16
|
+
raise Error.integrity(
|
|
17
|
+
"package archive exceeds #{ResourceLimits::MAX_ARCHIVE_TOTAL_BYTES} bytes"
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
cache_key = Hashing.sha256_prefixed(artifact_bytes).delete_prefix("sha256:")[0, 16]
|
|
22
|
+
cache_directory = File.join(project_root, ".pray", "cache", "tarball", cache_key)
|
|
23
|
+
if File.directory?(cache_directory)
|
|
24
|
+
begin
|
|
25
|
+
Resolve.find_prayspec_file(cache_directory)
|
|
26
|
+
return cache_directory
|
|
27
|
+
rescue Error
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
staging_directory = "#{cache_directory}.staging"
|
|
33
|
+
FileUtils.rm_rf(staging_directory)
|
|
34
|
+
FileUtils.mkdir_p(staging_directory)
|
|
35
|
+
ArchiveUnpack.unpack_praypkg(artifact_bytes, staging_directory)
|
|
36
|
+
Resolve.find_prayspec_file(staging_directory)
|
|
37
|
+
FileUtils.mkdir_p(File.dirname(cache_directory))
|
|
38
|
+
FileUtils.rm_rf(cache_directory)
|
|
39
|
+
FileUtils.mv(staging_directory, cache_directory)
|
|
40
|
+
cache_directory
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def read_tarball_bytes(project_root, tarball, offline:)
|
|
44
|
+
if tarball.start_with?("http://", "https://")
|
|
45
|
+
if offline
|
|
46
|
+
raise Error.resolution(
|
|
47
|
+
"tarball #{tarball} is not cached locally and offline mode is enabled"
|
|
48
|
+
)
|
|
49
|
+
end
|
|
50
|
+
return Registry.http_get(tarball)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
path = local_tarball_path(project_root, tarball)
|
|
54
|
+
unless File.file?(path)
|
|
55
|
+
raise Error.resolution("tarball missing at #{path}")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
File.binread(path)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def local_tarball_path(project_root, tarball)
|
|
62
|
+
path = tarball.delete_prefix("file://")
|
|
63
|
+
Pathname.new(path).absolute? ? path : File.expand_path(path, project_root)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
data/lib/pray/transaction.rb
CHANGED
|
@@ -57,5 +57,12 @@ module Pray
|
|
|
57
57
|
|
|
58
58
|
journal.replace(path, TransactionJournal.snapshot(path), bytes.b)
|
|
59
59
|
end
|
|
60
|
+
|
|
61
|
+
def remove_file(path)
|
|
62
|
+
journal = Thread.current[:pray_write_transaction]
|
|
63
|
+
return File.delete(path) unless journal
|
|
64
|
+
|
|
65
|
+
journal.replace(path, TransactionJournal.snapshot(path), nil)
|
|
66
|
+
end
|
|
60
67
|
end
|
|
61
68
|
end
|
data/lib/pray/upstream.rb
CHANGED
|
@@ -4,19 +4,6 @@ module Pray
|
|
|
4
4
|
module Upstream
|
|
5
5
|
module_function
|
|
6
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
7
|
def to_lock_hash(entry)
|
|
21
8
|
hash = {
|
|
22
9
|
"name" => entry.name,
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module Upstream
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
PathUpstreamLatestConstraint = Struct.new(
|
|
8
|
+
:package_name, :upstream_name, :current_constraint, :latest_version, :new_constraint, :package_root,
|
|
9
|
+
keyword_init: true
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
def plan_path_upstream_latest_constraints(project, previous, selected, options)
|
|
13
|
+
user_config = Config.load_user_config
|
|
14
|
+
git_sources = GitSources.prepare_git_sources(
|
|
15
|
+
project.project_root,
|
|
16
|
+
project.manifest.sources,
|
|
17
|
+
previous,
|
|
18
|
+
refresh: options.refresh || options.refresh_source_revisions
|
|
19
|
+
)
|
|
20
|
+
sources = Resolve.source_map(project.manifest.sources)
|
|
21
|
+
plans = []
|
|
22
|
+
project.packages.each do |package|
|
|
23
|
+
next if selected && package.declaration.name != selected
|
|
24
|
+
|
|
25
|
+
plan = plan_one_path_upstream(project, package, sources, git_sources, user_config, previous, options)
|
|
26
|
+
plans << plan if plan
|
|
27
|
+
end
|
|
28
|
+
plans
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def apply_path_upstream_latest_constraints(plans)
|
|
32
|
+
plans.each do |plan|
|
|
33
|
+
spec_path = Resolve.find_prayspec_file(plan.package_root)
|
|
34
|
+
spec = Pray.parse_package_spec(File.read(spec_path))
|
|
35
|
+
unless spec.upstream
|
|
36
|
+
raise Error.resolution("package #{plan.package_name} has no upstream pin")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
spec.upstream = PackageUpstream.new(
|
|
40
|
+
name: spec.upstream.name,
|
|
41
|
+
constraint: plan.new_constraint
|
|
42
|
+
)
|
|
43
|
+
Transaction.write_file(spec_path, PackageSpecRender.render_package_spec(spec))
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def latest_spec_upstream_constraint(current, latest_version)
|
|
48
|
+
derived = Constraint.latest_constraint_for_package(current, latest_version)
|
|
49
|
+
return "= #{latest_version}" if derived.start_with?("=")
|
|
50
|
+
|
|
51
|
+
derived
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def plan_one_path_upstream(project, package, sources, git_sources, user_config, lockfile, options)
|
|
55
|
+
upstream = package.spec.upstream
|
|
56
|
+
return unless upstream && package.declaration.path
|
|
57
|
+
|
|
58
|
+
source = ResolveSource.implied_source_name(ManifestPackage.new(name: upstream.name), sources)
|
|
59
|
+
resolved = Resolve.resolve_package(
|
|
60
|
+
project.project_root,
|
|
61
|
+
sources,
|
|
62
|
+
git_sources,
|
|
63
|
+
user_config,
|
|
64
|
+
ManifestPackage.new(name: upstream.name, constraint: "*", source: source),
|
|
65
|
+
lockfile,
|
|
66
|
+
options: options
|
|
67
|
+
)
|
|
68
|
+
return if Constraint.version_satisfies(resolved.spec.version, upstream.constraint)
|
|
69
|
+
|
|
70
|
+
new_constraint = latest_spec_upstream_constraint(upstream.constraint, resolved.spec.version)
|
|
71
|
+
unless Constraint.version_satisfies(resolved.spec.version, new_constraint)
|
|
72
|
+
raise Error.resolution(
|
|
73
|
+
"derived constraint #{new_constraint} does not admit latest #{resolved.spec.version} for #{package.declaration.name}"
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
PathUpstreamLatestConstraint.new(
|
|
78
|
+
package_name: package.declaration.name,
|
|
79
|
+
upstream_name: upstream.name,
|
|
80
|
+
current_constraint: upstream.constraint,
|
|
81
|
+
latest_version: resolved.spec.version,
|
|
82
|
+
new_constraint: new_constraint,
|
|
83
|
+
package_root: package.root
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
private_class_method :plan_one_path_upstream
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module Upstream
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def identity_path?(path)
|
|
8
|
+
File.extname(path.to_s) == ".prayspec"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def content_paths(files)
|
|
12
|
+
files.reject { |path| identity_path?(path) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def clean_replica?(old_content, local_content)
|
|
16
|
+
local_content == old_content
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def try_merge_content_files(old_content, new_content, local_content)
|
|
20
|
+
return [new_content.dup, []] if clean_replica?(old_content, local_content)
|
|
21
|
+
|
|
22
|
+
merged = {}
|
|
23
|
+
conflicts = []
|
|
24
|
+
(old_content.keys + new_content.keys + local_content.keys).uniq.sort.each do |path|
|
|
25
|
+
result = merge_one_content_path(old_content[path], new_content[path], local_content[path])
|
|
26
|
+
if result == :conflict
|
|
27
|
+
conflicts << path
|
|
28
|
+
elsif result != :omit
|
|
29
|
+
merged[path] = result
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
[merged, conflicts]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def merge_one_content_path(old, new, local)
|
|
36
|
+
case [old.nil?, new.nil?, local.nil?]
|
|
37
|
+
when [false, false, false]
|
|
38
|
+
merge_all_present(old, new, local)
|
|
39
|
+
when [false, true, false]
|
|
40
|
+
(local == old) ? :omit : :conflict
|
|
41
|
+
when [false, false, true]
|
|
42
|
+
(old == new) ? :omit : new
|
|
43
|
+
when [true, false, true]
|
|
44
|
+
new
|
|
45
|
+
when [true, true, false]
|
|
46
|
+
local
|
|
47
|
+
when [true, false, false]
|
|
48
|
+
(local == new) ? new : :conflict
|
|
49
|
+
else
|
|
50
|
+
:conflict
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def merge_all_present(old, new, local)
|
|
55
|
+
return new if local == new || local == old
|
|
56
|
+
return local if old == new
|
|
57
|
+
|
|
58
|
+
:conflict
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def merge_content_files(old_content, new_content, local_content)
|
|
62
|
+
merged, conflicts = try_merge_content_files(old_content, new_content, local_content)
|
|
63
|
+
return merged if conflicts.empty?
|
|
64
|
+
|
|
65
|
+
raise Error.resolution("upstream merge conflict in #{conflicts.join(", ")}")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def merge_conflict_message(fork, upstream_name, old_version, new_version, paths)
|
|
69
|
+
"upstream merge conflict in #{fork} while refreshing #{upstream_name} " \
|
|
70
|
+
"#{old_version} to #{new_version}: #{paths.join(", ")}"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def next_upstream_constraint(current, new_version)
|
|
74
|
+
trimmed = current.to_s.strip
|
|
75
|
+
return current if trimmed == "*" || trimmed.start_with?("~>", "^", ">=", ">", "<=", "<")
|
|
76
|
+
|
|
77
|
+
"= #{new_version}"
|
|
78
|
+
end
|
|
79
|
+
private_class_method :merge_one_content_path, :merge_all_present
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module Upstream
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def apply_path_upstream_refreshes(project, previous, selected, options)
|
|
8
|
+
user_config = Config.load_user_config
|
|
9
|
+
git_sources = GitSources.prepare_git_sources(
|
|
10
|
+
project.project_root,
|
|
11
|
+
project.manifest.sources,
|
|
12
|
+
previous,
|
|
13
|
+
refresh: options.refresh || options.refresh_source_revisions
|
|
14
|
+
)
|
|
15
|
+
sources = Resolve.source_map(project.manifest.sources)
|
|
16
|
+
changed = false
|
|
17
|
+
project.packages.each do |package|
|
|
18
|
+
next if selected && package.declaration.name != selected
|
|
19
|
+
next unless apply_one_path_upstream(project, package, previous, sources, git_sources, user_config, options)
|
|
20
|
+
|
|
21
|
+
changed = true
|
|
22
|
+
end
|
|
23
|
+
changed
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def apply_one_path_upstream(project, package, previous, sources, git_sources, user_config, options)
|
|
27
|
+
new_upstream = package.upstream
|
|
28
|
+
return false unless new_upstream && package.declaration.path
|
|
29
|
+
|
|
30
|
+
old_upstream = previous&.package&.find { |entry| entry.name == package.declaration.name }&.upstream
|
|
31
|
+
return false unless old_upstream
|
|
32
|
+
return false if old_upstream.version == new_upstream.version && old_upstream.tree_hash == new_upstream.tree_hash
|
|
33
|
+
|
|
34
|
+
old_package, new_package = resolve_upstream_pair(
|
|
35
|
+
project, previous, sources, git_sources, user_config, options, old_upstream, new_upstream
|
|
36
|
+
)
|
|
37
|
+
old_content, local_content, merged = merge_fork_content(package, old_upstream, new_upstream, old_package, new_package)
|
|
38
|
+
write_content_files(package.root, old_content, merged)
|
|
39
|
+
write_refreshed_spec(package, new_package, old_content, local_content, merged)
|
|
40
|
+
true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def resolve_upstream_pair(project, previous, sources, git_sources, user_config, options, old_upstream, new_upstream)
|
|
44
|
+
old_package = resolve_named(
|
|
45
|
+
project.project_root, sources, git_sources, user_config, previous, options,
|
|
46
|
+
old_upstream.name, "= #{old_upstream.version}", old_upstream.source
|
|
47
|
+
)
|
|
48
|
+
resolved_old = LockedUpstream.new(
|
|
49
|
+
name: old_upstream.name,
|
|
50
|
+
version: old_package.spec.version,
|
|
51
|
+
source: old_upstream.source,
|
|
52
|
+
tree_hash: old_package.tree_hash,
|
|
53
|
+
artifact_hash: old_package.artifact_hash
|
|
54
|
+
)
|
|
55
|
+
ensure_locked_match!(old_upstream, resolved_old)
|
|
56
|
+
new_package = resolve_named(
|
|
57
|
+
project.project_root, sources, git_sources, user_config, previous, options,
|
|
58
|
+
new_upstream.name, "= #{new_upstream.version}", new_upstream.source
|
|
59
|
+
)
|
|
60
|
+
[old_package, new_package]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def merge_fork_content(package, old_upstream, new_upstream, old_package, new_package)
|
|
64
|
+
old_content = content_file_bytes(old_package.root, old_package.spec)
|
|
65
|
+
new_content = content_file_bytes(new_package.root, new_package.spec)
|
|
66
|
+
local_content = content_file_bytes(package.root, package.spec)
|
|
67
|
+
merged, conflicts = try_merge_content_files(old_content, new_content, local_content)
|
|
68
|
+
unless conflicts.empty?
|
|
69
|
+
raise Error.resolution(
|
|
70
|
+
merge_conflict_message(
|
|
71
|
+
package.declaration.name, old_upstream.name, old_upstream.version, new_upstream.version, conflicts
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
[old_content, local_content, merged]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def write_refreshed_spec(package, new_package, old_content, local_content, merged)
|
|
79
|
+
spec_path = Resolve.find_prayspec_file(package.root)
|
|
80
|
+
updated = PackageSpecRender.fork_spec_after_refresh(
|
|
81
|
+
package.spec,
|
|
82
|
+
new_package.spec,
|
|
83
|
+
File.basename(spec_path),
|
|
84
|
+
clean_replica?(old_content, local_content),
|
|
85
|
+
merged.keys
|
|
86
|
+
)
|
|
87
|
+
Transaction.write_file(spec_path, PackageSpecRender.render_package_spec(updated))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def resolve_named(project_root, sources, git_sources, user_config, lockfile, options, name, constraint, source)
|
|
91
|
+
Resolve.resolve_package(
|
|
92
|
+
project_root,
|
|
93
|
+
sources,
|
|
94
|
+
git_sources,
|
|
95
|
+
user_config,
|
|
96
|
+
ManifestPackage.new(name: name, constraint: constraint, source: source),
|
|
97
|
+
lockfile,
|
|
98
|
+
options: options
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def content_file_bytes(root, spec)
|
|
103
|
+
paths = content_paths(spec.files)
|
|
104
|
+
if paths.length > ResourceLimits::MAX_ARCHIVE_ENTRIES
|
|
105
|
+
raise Error.integrity("package content exceeds #{ResourceLimits::MAX_ARCHIVE_ENTRIES} files")
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
files = {}
|
|
109
|
+
total_bytes = 0
|
|
110
|
+
paths.each do |relative|
|
|
111
|
+
PathSafety.validate_archive_member_path!(relative)
|
|
112
|
+
path = File.join(root, relative)
|
|
113
|
+
raise Error.integrity("package file missing: #{relative}") unless File.file?(path)
|
|
114
|
+
|
|
115
|
+
size = File.size(path)
|
|
116
|
+
if size > ResourceLimits::MAX_ARCHIVE_ENTRY_BYTES
|
|
117
|
+
raise Error.integrity("package file exceeds #{ResourceLimits::MAX_ARCHIVE_ENTRY_BYTES} bytes: #{relative}")
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
total_bytes += size
|
|
121
|
+
if total_bytes > ResourceLimits::MAX_ARCHIVE_TOTAL_BYTES
|
|
122
|
+
raise Error.integrity("package content exceeds #{ResourceLimits::MAX_ARCHIVE_TOTAL_BYTES} bytes")
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
files[relative] = File.binread(path)
|
|
126
|
+
end
|
|
127
|
+
files
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def write_content_files(root, old_content, merged)
|
|
131
|
+
(old_content.keys + merged.keys).each { |path| PathSafety.validate_archive_member_path!(path) }
|
|
132
|
+
old_content.each_key do |path|
|
|
133
|
+
next if merged.key?(path)
|
|
134
|
+
|
|
135
|
+
Transaction.remove_file(File.join(root, path))
|
|
136
|
+
end
|
|
137
|
+
merged.each do |relative, bytes|
|
|
138
|
+
Transaction.write_file(File.join(root, relative), bytes)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
private_class_method :apply_one_path_upstream, :resolve_upstream_pair, :merge_fork_content,
|
|
142
|
+
:write_refreshed_spec, :resolve_named
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module Verify
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def inspect_locked_destinations(project_root, lockfile)
|
|
8
|
+
report = VerificationReport.new
|
|
9
|
+
lockfile.managed_span.group_by(&:target).each do |target_path, spans|
|
|
10
|
+
absolute_path = File.join(project_root, target_path)
|
|
11
|
+
unless File.exist?(absolute_path)
|
|
12
|
+
report.findings << VerificationFinding.new(
|
|
13
|
+
kind: "verify_error",
|
|
14
|
+
message: "Rendered file `#{target_path}` is missing. Run `pray install` to generate it."
|
|
15
|
+
)
|
|
16
|
+
next
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
text = RenderDest.decode_utf8(
|
|
20
|
+
RenderDest.read_regular_bytes(absolute_path, target_path),
|
|
21
|
+
target_path
|
|
22
|
+
)
|
|
23
|
+
markers = marker_positions(text.lines(chomp: true))
|
|
24
|
+
spans.each do |span|
|
|
25
|
+
marker = markers[span.id]
|
|
26
|
+
unless marker
|
|
27
|
+
report.findings << VerificationFinding.new(
|
|
28
|
+
kind: "removed_prayer",
|
|
29
|
+
message: "`#{target_path}` is missing managed marker `#{span.id}` for `#{span.package}::#{span.export}`. Run `pray install` to restore the managed span."
|
|
30
|
+
)
|
|
31
|
+
next
|
|
32
|
+
end
|
|
33
|
+
next if marker[2] == span.ideal_checksum
|
|
34
|
+
|
|
35
|
+
report.findings << VerificationFinding.new(
|
|
36
|
+
kind: "custom_implementation",
|
|
37
|
+
message: "`#{target_path}` marker `#{span.id}` (`#{span.package}::#{span.export}`) was edited. Restore the managed block or run `pray install` to regenerate it."
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
find_orphan_marker_findings(spans, markers, target_path).each do |finding|
|
|
41
|
+
report.findings << finding
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
report
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/pray/version.rb
CHANGED
data/lib/pray.rb
CHANGED
|
@@ -21,10 +21,17 @@ require_relative "pray/environment"
|
|
|
21
21
|
require_relative "pray/resolve_context"
|
|
22
22
|
require_relative "pray/resolve_source"
|
|
23
23
|
require_relative "pray/resolve_exports"
|
|
24
|
+
require_relative "pray/dependency_graph"
|
|
25
|
+
require_relative "pray/resolve_deps"
|
|
26
|
+
require_relative "pray/resolve_tarball"
|
|
24
27
|
require_relative "pray/invocation"
|
|
25
28
|
require_relative "pray/git_refresh"
|
|
26
29
|
require_relative "pray/resolve"
|
|
27
30
|
require_relative "pray/upstream"
|
|
31
|
+
require_relative "pray/upstream_merge"
|
|
32
|
+
require_relative "pray/package_spec_render"
|
|
33
|
+
require_relative "pray/upstream_refresh"
|
|
34
|
+
require_relative "pray/upstream_latest"
|
|
28
35
|
require_relative "pray/compose_dest"
|
|
29
36
|
require_relative "pray/render_patch"
|
|
30
37
|
require_relative "pray/render"
|
|
@@ -34,6 +41,7 @@ require_relative "pray/render_layout"
|
|
|
34
41
|
require_relative "pray/verify_position"
|
|
35
42
|
require_relative "pray/verify_provisioned"
|
|
36
43
|
require_relative "pray/verify"
|
|
44
|
+
require_relative "pray/verify_locked_dest"
|
|
37
45
|
require_relative "pray/resource_limits"
|
|
38
46
|
require_relative "pray/http_body"
|
|
39
47
|
require_relative "pray/registry_install"
|
|
@@ -57,6 +65,6 @@ class << Pray
|
|
|
57
65
|
:parse_package_spec, :parse_lockfile, :read_lockfile, :serialize_lockfile, :lockfile_hash,
|
|
58
66
|
:write_lockfile, :write_lockfile_if_changed, :lockfiles_equivalent?, :build_lockfile,
|
|
59
67
|
:resolve_project, :render_project, :materialize_project,
|
|
60
|
-
:inspect_project, :verify_project, :drift_project,
|
|
68
|
+
:inspect_project, :inspect_locked_destinations, :verify_project, :drift_project,
|
|
61
69
|
:default_manifest_path, :default_lockfile_path, :project_root_from_manifest
|
|
62
70
|
end
|
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.16.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrei Makarov
|
|
@@ -113,6 +113,7 @@ files:
|
|
|
113
113
|
- lib/pray/cli/commands/meta.rb
|
|
114
114
|
- lib/pray/cli/commands/packages.rb
|
|
115
115
|
- lib/pray/cli/commands/trust.rb
|
|
116
|
+
- lib/pray/cli/commands/update_latest.rb
|
|
116
117
|
- lib/pray/cli/commands/workflow.rb
|
|
117
118
|
- lib/pray/cli/help.rb
|
|
118
119
|
- lib/pray/cli/helpers.rb
|
|
@@ -124,6 +125,7 @@ files:
|
|
|
124
125
|
- lib/pray/confess.rb
|
|
125
126
|
- lib/pray/config.rb
|
|
126
127
|
- lib/pray/constraint.rb
|
|
128
|
+
- lib/pray/dependency_graph.rb
|
|
127
129
|
- lib/pray/destination.rb
|
|
128
130
|
- lib/pray/dotenv.rb
|
|
129
131
|
- lib/pray/environment.rb
|
|
@@ -147,6 +149,7 @@ files:
|
|
|
147
149
|
- lib/pray/manifest_parser_helpers.rb
|
|
148
150
|
- lib/pray/materialize.rb
|
|
149
151
|
- lib/pray/package_spec.rb
|
|
152
|
+
- lib/pray/package_spec_render.rb
|
|
150
153
|
- lib/pray/path_safety.rb
|
|
151
154
|
- lib/pray/plan.rb
|
|
152
155
|
- lib/pray/project_context.rb
|
|
@@ -154,6 +157,7 @@ files:
|
|
|
154
157
|
- lib/pray/registry.rb
|
|
155
158
|
- lib/pray/registry_install.rb
|
|
156
159
|
- lib/pray/registry_integrity.rb
|
|
160
|
+
- lib/pray/registry_paths.rb
|
|
157
161
|
- lib/pray/render.rb
|
|
158
162
|
- lib/pray/render_content.rb
|
|
159
163
|
- lib/pray/render_dest.rb
|
|
@@ -161,8 +165,10 @@ files:
|
|
|
161
165
|
- lib/pray/render_patch.rb
|
|
162
166
|
- lib/pray/resolve.rb
|
|
163
167
|
- lib/pray/resolve_context.rb
|
|
168
|
+
- lib/pray/resolve_deps.rb
|
|
164
169
|
- lib/pray/resolve_exports.rb
|
|
165
170
|
- lib/pray/resolve_source.rb
|
|
171
|
+
- lib/pray/resolve_tarball.rb
|
|
166
172
|
- lib/pray/resource_limits.rb
|
|
167
173
|
- lib/pray/serve.rb
|
|
168
174
|
- lib/pray/serve_federation.rb
|
|
@@ -181,7 +187,11 @@ files:
|
|
|
181
187
|
- lib/pray/trust_feed.rb
|
|
182
188
|
- lib/pray/trust_ops.rb
|
|
183
189
|
- lib/pray/upstream.rb
|
|
190
|
+
- lib/pray/upstream_latest.rb
|
|
191
|
+
- lib/pray/upstream_merge.rb
|
|
192
|
+
- lib/pray/upstream_refresh.rb
|
|
184
193
|
- lib/pray/verify.rb
|
|
194
|
+
- lib/pray/verify_locked_dest.rb
|
|
185
195
|
- lib/pray/verify_position.rb
|
|
186
196
|
- lib/pray/verify_provisioned.rb
|
|
187
197
|
- lib/pray/version.rb
|