pray-cli 1.16.0 → 1.17.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 +10 -0
- data/lib/pray/apply_report.rb +49 -0
- data/lib/pray/cli/commands/init.rb +1 -20
- data/lib/pray/cli/commands/init_prayer.rb +76 -0
- data/lib/pray/cli/commands/init_prayer_manifest.rb +102 -0
- data/lib/pray/cli/commands/packages.rb +13 -2
- data/lib/pray/cli/commands/workflow.rb +5 -0
- data/lib/pray/cli/help.rb +52 -15
- data/lib/pray/cli/helpers.rb +13 -5
- data/lib/pray/cli/parse.rb +21 -1
- data/lib/pray/cli.rb +3 -1
- data/lib/pray/destination.rb +32 -2
- data/lib/pray/distribution.rb +94 -0
- data/lib/pray/format_serialize.rb +1 -4
- data/lib/pray/local_prayer.rb +38 -0
- data/lib/pray/lockfile.rb +8 -2
- data/lib/pray/manifest.rb +6 -3
- data/lib/pray/manifest_json.rb +1 -0
- data/lib/pray/manifest_parser_blocks.rb +15 -15
- data/lib/pray/materialize.rb +7 -1
- data/lib/pray/package_spec.rb +25 -13
- data/lib/pray/package_spec_render.rb +4 -3
- data/lib/pray/package_spec_version.rb +33 -0
- data/lib/pray/plan.rb +2 -1
- data/lib/pray/publish.rb +27 -2
- data/lib/pray/render.rb +6 -36
- data/lib/pray/render_managed.rb +64 -0
- data/lib/pray/render_patch.rb +63 -12
- data/lib/pray/resolve.rb +5 -36
- data/lib/pray/resolve_local.rb +39 -0
- data/lib/pray/resolve_source.rb +5 -0
- data/lib/pray/serve.rb +15 -4
- data/lib/pray/serve_range.rb +36 -0
- data/lib/pray/torrent_manifest.rb +78 -0
- data/lib/pray/upstream_drift.rb +42 -0
- data/lib/pray/upstream_merge.rb +25 -0
- data/lib/pray/upstream_refresh.rb +28 -2
- data/lib/pray/verify.rb +2 -2
- data/lib/pray/version.rb +2 -2
- data/lib/pray.rb +10 -0
- metadata +12 -1
data/lib/pray/render_patch.rb
CHANGED
|
@@ -7,28 +7,74 @@ module Pray
|
|
|
7
7
|
def patch_rendered_content(existing, fresh)
|
|
8
8
|
existing_segments = split_segments(existing)
|
|
9
9
|
fresh_segments = split_segments(fresh)
|
|
10
|
-
fresh_managed = fresh_segments
|
|
11
|
-
|
|
12
|
-
end.to_h
|
|
13
|
-
overlap = existing_segments.any? do |segment|
|
|
14
|
-
segment[:kind] == :managed && fresh_managed.key?(segment[:id])
|
|
15
|
-
end
|
|
16
|
-
return fresh unless overlap
|
|
10
|
+
fresh_managed = managed_bodies(fresh_segments)
|
|
11
|
+
return fresh unless overlapping_managed?(existing_segments, fresh_managed)
|
|
17
12
|
|
|
18
13
|
used = {}
|
|
19
|
-
output =
|
|
20
|
-
|
|
14
|
+
output = +""
|
|
15
|
+
remaining = prepend_new_leading_spans(
|
|
16
|
+
existing_segments,
|
|
17
|
+
fresh_segments,
|
|
18
|
+
managed_id_set(existing_segments),
|
|
19
|
+
used,
|
|
20
|
+
output
|
|
21
|
+
)
|
|
22
|
+
splice_existing_managed(remaining, fresh_managed, used, output)
|
|
23
|
+
append_unused_fresh_managed(fresh_segments, used, output)
|
|
24
|
+
output.end_with?("\n") ? output : "#{output}\n"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def managed_bodies(segments)
|
|
28
|
+
segments.filter_map { |segment| [segment[:id], segment[:body]] if segment[:kind] == :managed }.to_h
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def overlapping_managed?(existing_segments, fresh_managed)
|
|
32
|
+
existing_segments.any? { |segment| segment[:kind] == :managed && fresh_managed.key?(segment[:id]) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def managed_id_set(segments)
|
|
36
|
+
segments.filter_map { |segment| segment[:id] if segment[:kind] == :managed }.to_h { |id| [id, true] }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def splice_existing_managed(remaining, fresh_managed, used, output)
|
|
40
|
+
remaining.each do |segment|
|
|
41
|
+
if segment[:kind] == :text
|
|
42
|
+
output << segment[:text]
|
|
43
|
+
next
|
|
44
|
+
end
|
|
21
45
|
|
|
22
46
|
used[segment[:id]] = true
|
|
23
|
-
managed_segment(segment[:id], fresh_managed.fetch(segment[:id], segment[:body]))
|
|
24
|
-
end
|
|
47
|
+
output << managed_segment(segment[:id], fresh_managed.fetch(segment[:id], segment[:body]))
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def append_unused_fresh_managed(fresh_segments, used, output)
|
|
25
52
|
fresh_segments.each do |segment|
|
|
26
53
|
next unless segment[:kind] == :managed
|
|
27
54
|
next if used[segment[:id]]
|
|
28
55
|
|
|
29
56
|
output << managed_segment(segment[:id], segment[:body])
|
|
30
57
|
end
|
|
31
|
-
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def prepend_new_leading_spans(existing_segments, fresh_segments, existing_ids, used, output)
|
|
61
|
+
missing = fresh_segments.any? { |segment| segment[:kind] == :managed && !existing_ids[segment[:id]] }
|
|
62
|
+
return existing_segments unless missing
|
|
63
|
+
|
|
64
|
+
shared_id = fresh_segments.find { |segment| segment[:kind] == :managed && existing_ids[segment[:id]] }&.[](:id)
|
|
65
|
+
return existing_segments unless shared_id
|
|
66
|
+
|
|
67
|
+
fresh_segments.each do |segment|
|
|
68
|
+
break if segment[:kind] == :managed && segment[:id] == shared_id
|
|
69
|
+
|
|
70
|
+
if segment[:kind] == :text
|
|
71
|
+
output << segment[:text]
|
|
72
|
+
else
|
|
73
|
+
used[segment[:id]] = true
|
|
74
|
+
output << managed_segment(segment[:id], segment[:body])
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
skip_until_managed(existing_segments, shared_id)
|
|
32
78
|
end
|
|
33
79
|
|
|
34
80
|
def relocate_managed_spans(content, spans)
|
|
@@ -68,6 +114,11 @@ module Pray
|
|
|
68
114
|
segments
|
|
69
115
|
end
|
|
70
116
|
|
|
117
|
+
def skip_until_managed(segments, identifier)
|
|
118
|
+
index = segments.index { |segment| segment[:kind] == :managed && segment[:id] == identifier }
|
|
119
|
+
index ? segments[index..] : segments
|
|
120
|
+
end
|
|
121
|
+
|
|
71
122
|
def lines_of(content)
|
|
72
123
|
content.lines(chomp: true)
|
|
73
124
|
end
|
data/lib/pray/resolve.rb
CHANGED
|
@@ -17,7 +17,7 @@ module Pray
|
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
ResolvedLocalFile = Struct.new(
|
|
20
|
-
:path, :manifest_path, :content, :position, :optional
|
|
20
|
+
:path, :manifest_path, :content, :source_checksum, :position, :optional
|
|
21
21
|
)
|
|
22
22
|
|
|
23
23
|
module Resolve
|
|
@@ -92,6 +92,7 @@ module Pray
|
|
|
92
92
|
local_files = []
|
|
93
93
|
local_errors = []
|
|
94
94
|
manifest.local.each do |local|
|
|
95
|
+
next unless Destination.local_compose_embed?(manifest, local)
|
|
95
96
|
local_files << resolve_local_file(project_root, local)
|
|
96
97
|
rescue Error => error
|
|
97
98
|
local_errors << "local #{local.path}: #{error.message}"
|
|
@@ -146,11 +147,6 @@ module Pray
|
|
|
146
147
|
GitRefresh.resolution_may_benefit_from_git_source_refresh?(error)
|
|
147
148
|
end
|
|
148
149
|
|
|
149
|
-
def missing_local_embed_guidance(path)
|
|
150
|
-
"Prayfile lists `local \"#{path}\"` but the file does not exist. " \
|
|
151
|
-
"Create the file or remove the entry from Prayfile, then run `pray install`."
|
|
152
|
-
end
|
|
153
|
-
|
|
154
150
|
def resolve_package(project_root, sources, git_sources, user_config, declaration, lockfile, offline: false, options: nil)
|
|
155
151
|
options ||= ResolveOptions.new(offline: offline)
|
|
156
152
|
root, registry_latest_version = resolve_package_root_with_metadata(
|
|
@@ -164,11 +160,7 @@ module Pray
|
|
|
164
160
|
"package path #{root.inspect} declares #{spec.name.inspect}, expected #{declaration.name.inspect}"
|
|
165
161
|
)
|
|
166
162
|
end
|
|
167
|
-
|
|
168
|
-
raise Error.resolution(
|
|
169
|
-
"package #{declaration.name} version #{spec.version} does not satisfy constraint #{declaration.constraint}"
|
|
170
|
-
)
|
|
171
|
-
end
|
|
163
|
+
spec.satisfy_constraint!(declaration.constraint)
|
|
172
164
|
|
|
173
165
|
selected_exports = select_exports(declaration, spec)
|
|
174
166
|
file_bytes = load_package_file_bytes(root, spec)
|
|
@@ -226,7 +218,8 @@ module Pray
|
|
|
226
218
|
|
|
227
219
|
case source.kind
|
|
228
220
|
when "path"
|
|
229
|
-
|
|
221
|
+
directory = LocalPrayer.path_source_package_directory(source_name, declaration.name)
|
|
222
|
+
return [File.join(project_root, source.url, directory), nil]
|
|
230
223
|
when "registry", "static index"
|
|
231
224
|
resolved = Registry.resolve_registry_package_root(
|
|
232
225
|
project_root,
|
|
@@ -277,30 +270,6 @@ module Pray
|
|
|
277
270
|
resolve_package_root_with_metadata(project_root, sources, git_sources, user_config, declaration, lockfile).first
|
|
278
271
|
end
|
|
279
272
|
|
|
280
|
-
def resolve_local_file(project_root, declaration)
|
|
281
|
-
path = File.join(project_root, declaration.path)
|
|
282
|
-
unless File.exist?(path)
|
|
283
|
-
if declaration.optional
|
|
284
|
-
return ResolvedLocalFile.new(
|
|
285
|
-
path: path,
|
|
286
|
-
manifest_path: declaration.path,
|
|
287
|
-
content: "",
|
|
288
|
-
position: declaration.position,
|
|
289
|
-
optional: true
|
|
290
|
-
)
|
|
291
|
-
end
|
|
292
|
-
raise Error.resolution(missing_local_embed_guidance(declaration.path))
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
ResolvedLocalFile.new(
|
|
296
|
-
path: path,
|
|
297
|
-
manifest_path: declaration.path,
|
|
298
|
-
content: Hashing.normalize_line_endings(File.read(path)),
|
|
299
|
-
position: declaration.position,
|
|
300
|
-
optional: declaration.optional
|
|
301
|
-
)
|
|
302
|
-
end
|
|
303
|
-
|
|
304
273
|
def find_prayspec_file(root)
|
|
305
274
|
files = Dir.children(root).filter_map do |entry|
|
|
306
275
|
path = File.join(root, entry)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module Resolve
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def missing_local_embed_guidance(path)
|
|
8
|
+
"Prayfile lists `local \"#{path}\"` but the file does not exist. " \
|
|
9
|
+
"Create the file or remove the entry from Prayfile, then run `pray install`."
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def resolve_local_file(project_root, declaration)
|
|
13
|
+
path = File.join(project_root, declaration.path)
|
|
14
|
+
unless File.exist?(path)
|
|
15
|
+
if declaration.optional
|
|
16
|
+
return ResolvedLocalFile.new(
|
|
17
|
+
path: path,
|
|
18
|
+
manifest_path: declaration.path,
|
|
19
|
+
content: "",
|
|
20
|
+
source_checksum: Hashing.sha256_prefixed(""),
|
|
21
|
+
position: declaration.position,
|
|
22
|
+
optional: true
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
raise Error.resolution(missing_local_embed_guidance(declaration.path))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
content = Hashing.normalize_line_endings(File.read(path))
|
|
29
|
+
ResolvedLocalFile.new(
|
|
30
|
+
path: path,
|
|
31
|
+
manifest_path: declaration.path,
|
|
32
|
+
content: content,
|
|
33
|
+
source_checksum: Hashing.sha256_prefixed(content),
|
|
34
|
+
position: declaration.position,
|
|
35
|
+
optional: declaration.optional
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/pray/resolve_source.rb
CHANGED
|
@@ -10,6 +10,11 @@ module Pray
|
|
|
10
10
|
namespace = package_namespace(declaration.name)
|
|
11
11
|
return namespace if namespace && sources.key?(namespace)
|
|
12
12
|
|
|
13
|
+
unless declaration.name.include?("/")
|
|
14
|
+
path_sources = sources.select { |_name, source| source.kind == "path" }
|
|
15
|
+
return path_sources.keys.first if path_sources.length == 1
|
|
16
|
+
end
|
|
17
|
+
|
|
13
18
|
case sources.length
|
|
14
19
|
when 0 then nil
|
|
15
20
|
when 1 then sources.keys.first
|
data/lib/pray/serve.rb
CHANGED
|
@@ -65,7 +65,7 @@ module Pray
|
|
|
65
65
|
validate_body_length!(body_length)
|
|
66
66
|
body = body_length.positive? ? socket.read(body_length) : ""
|
|
67
67
|
|
|
68
|
-
response = dispatch_request(root, method, path, body)
|
|
68
|
+
response = dispatch_request(root, method, path, body, headers)
|
|
69
69
|
socket.print(response)
|
|
70
70
|
end
|
|
71
71
|
|
|
@@ -94,7 +94,7 @@ module Pray
|
|
|
94
94
|
)
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
-
def dispatch_request(root, method, path, body = "")
|
|
97
|
+
def dispatch_request(root, method, path, body = "", headers = {})
|
|
98
98
|
path = path.split("?", 2).first
|
|
99
99
|
|
|
100
100
|
case [method, path]
|
|
@@ -125,7 +125,8 @@ module Pray
|
|
|
125
125
|
|
|
126
126
|
content_type = content_type_for(file_path)
|
|
127
127
|
file_body = File.binread(file_path)
|
|
128
|
-
|
|
128
|
+
status, ranged_body, content_range = ServeRange.apply(200, file_body, headers["range"])
|
|
129
|
+
ranged_response(status, content_type, ranged_body, content_range)
|
|
129
130
|
end
|
|
130
131
|
|
|
131
132
|
def content_type_for(path)
|
|
@@ -137,7 +138,17 @@ module Pray
|
|
|
137
138
|
end
|
|
138
139
|
|
|
139
140
|
def ok_response(content_type, body)
|
|
140
|
-
|
|
141
|
+
ranged_response(200, content_type, body, nil)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def ranged_response(status, content_type, body, content_range)
|
|
145
|
+
reason = {
|
|
146
|
+
200 => "OK",
|
|
147
|
+
206 => "Partial Content",
|
|
148
|
+
416 => "Range Not Satisfiable"
|
|
149
|
+
}.fetch(status, "OK")
|
|
150
|
+
range_header = content_range ? "Content-Range: #{content_range}\r\n" : ""
|
|
151
|
+
"HTTP/1.1 #{status} #{reason}\r\nContent-Type: #{content_type}\r\n#{range_header}Content-Length: #{body.bytesize}\r\nConnection: close\r\n\r\n#{body}"
|
|
141
152
|
end
|
|
142
153
|
|
|
143
154
|
def html_response(body)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module ServeRange
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def apply(status, body, range_header)
|
|
8
|
+
return [status, body, nil] if range_header.nil? || range_header.empty?
|
|
9
|
+
return [status, body, nil] unless status == 200 && !body.empty?
|
|
10
|
+
|
|
11
|
+
start_offset, end_offset = parse_byte_range(range_header, body.bytesize)
|
|
12
|
+
unless start_offset
|
|
13
|
+
return [416, "".b, "bytes */#{body.bytesize}"]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
[
|
|
17
|
+
206,
|
|
18
|
+
body.b[start_offset..end_offset],
|
|
19
|
+
"bytes #{start_offset}-#{end_offset}/#{body.bytesize}"
|
|
20
|
+
]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def parse_byte_range(header, total)
|
|
24
|
+
range = header.delete_prefix("bytes=")
|
|
25
|
+
start_text, end_text = range.split("-", 2)
|
|
26
|
+
return unless start_text && end_text
|
|
27
|
+
|
|
28
|
+
start_offset = Integer(start_text, exception: false)
|
|
29
|
+
end_offset = Integer(end_text, exception: false)
|
|
30
|
+
return if start_offset.nil? || end_offset.nil?
|
|
31
|
+
return unless start_offset <= end_offset && end_offset < total
|
|
32
|
+
|
|
33
|
+
[start_offset, end_offset]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
|
|
6
|
+
module Pray
|
|
7
|
+
TORRENT_MANIFEST_SPEC = "pray-torrent-v1"
|
|
8
|
+
DEFAULT_TORRENT_PIECE_SIZE = 16 * 1024
|
|
9
|
+
|
|
10
|
+
module TorrentManifest
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def path_for(artifact_path)
|
|
14
|
+
"#{artifact_path}.praytorrent.json"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def payload(name:, version:, artifact_path:, archive_bytes:, trackers: [])
|
|
18
|
+
{
|
|
19
|
+
"spec" => TORRENT_MANIFEST_SPEC,
|
|
20
|
+
"name" => name,
|
|
21
|
+
"version" => version,
|
|
22
|
+
"artifact_url" => artifact_path,
|
|
23
|
+
"artifact_hash" => Hashing.sha256_prefixed(archive_bytes),
|
|
24
|
+
"piece_size" => DEFAULT_TORRENT_PIECE_SIZE,
|
|
25
|
+
"length" => archive_bytes.bytesize,
|
|
26
|
+
"pieces" => piece_hashes(archive_bytes),
|
|
27
|
+
"sources" => [artifact_path],
|
|
28
|
+
"trackers" => Array(trackers)
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def bytes(name:, version:, artifact_path:, archive_bytes:, trackers: [])
|
|
33
|
+
JSON.pretty_generate(
|
|
34
|
+
payload(
|
|
35
|
+
name: name,
|
|
36
|
+
version: version,
|
|
37
|
+
artifact_path: artifact_path,
|
|
38
|
+
archive_bytes: archive_bytes,
|
|
39
|
+
trackers: trackers
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def write(root, name:, version:, artifact_path:, archive_bytes:, settings:)
|
|
45
|
+
return unless settings.allows_torrent?
|
|
46
|
+
|
|
47
|
+
path = File.join(root, path_for(artifact_path))
|
|
48
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
49
|
+
File.write(
|
|
50
|
+
path,
|
|
51
|
+
bytes(
|
|
52
|
+
name: name,
|
|
53
|
+
version: version,
|
|
54
|
+
artifact_path: artifact_path,
|
|
55
|
+
archive_bytes: archive_bytes,
|
|
56
|
+
trackers: settings.bootstrap_trackers
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def piece_hashes(archive_bytes)
|
|
62
|
+
length = archive_bytes.bytesize
|
|
63
|
+
return [] if length.zero?
|
|
64
|
+
|
|
65
|
+
hashes = []
|
|
66
|
+
start = 0
|
|
67
|
+
while start < length
|
|
68
|
+
hashes << Hashing.sha256_prefixed(archive_bytes.byteslice(start, DEFAULT_TORRENT_PIECE_SIZE))
|
|
69
|
+
start += DEFAULT_TORRENT_PIECE_SIZE
|
|
70
|
+
end
|
|
71
|
+
hashes
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def descriptor_present?(root, artifact_path, settings)
|
|
75
|
+
!settings.allows_torrent? || File.file?(File.join(root, path_for(artifact_path)))
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pray
|
|
4
|
+
module Upstream
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def path_fork_drift_lines(project, previous, 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
|
+
lines = []
|
|
17
|
+
project.packages.each do |package|
|
|
18
|
+
next unless package.declaration.path
|
|
19
|
+
next unless package.upstream
|
|
20
|
+
|
|
21
|
+
upstream = package.upstream
|
|
22
|
+
resolved = resolve_named(
|
|
23
|
+
project.project_root, sources, git_sources, user_config, previous, options,
|
|
24
|
+
upstream.name, "= #{upstream.version}", upstream.source
|
|
25
|
+
)
|
|
26
|
+
upstream_content = content_file_bytes(resolved.root, resolved.spec)
|
|
27
|
+
local_content = local_content_for_refresh(package.root, package.spec)
|
|
28
|
+
if local_content.empty?
|
|
29
|
+
lines << "#{package.declaration.name} has no content files; run pray install to copy #{upstream.name} #{upstream.version}"
|
|
30
|
+
next
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
overlay_file_changes(local_content, upstream_content).each do |path, change|
|
|
34
|
+
lines << overlay_drift_line(
|
|
35
|
+
package.declaration.name, upstream.name, upstream.version, path, change
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
lines
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/pray/upstream_merge.rb
CHANGED
|
@@ -76,6 +76,31 @@ module Pray
|
|
|
76
76
|
|
|
77
77
|
"= #{new_version}"
|
|
78
78
|
end
|
|
79
|
+
|
|
80
|
+
def overlay_file_changes(local_content, upstream_content)
|
|
81
|
+
(local_content.keys + upstream_content.keys).uniq.sort.filter_map do |path|
|
|
82
|
+
local = local_content[path]
|
|
83
|
+
upstream = upstream_content[path]
|
|
84
|
+
if local && upstream && local != upstream
|
|
85
|
+
[path, :changed]
|
|
86
|
+
elsif local && upstream.nil?
|
|
87
|
+
[path, :local_only]
|
|
88
|
+
elsif local.nil? && upstream
|
|
89
|
+
[path, :missing]
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def overlay_drift_line(fork, upstream_name, upstream_version, path, change)
|
|
95
|
+
case change
|
|
96
|
+
when :changed
|
|
97
|
+
"#{fork} #{path} differs from #{upstream_name} #{upstream_version}"
|
|
98
|
+
when :local_only
|
|
99
|
+
"#{fork} #{path} local"
|
|
100
|
+
else
|
|
101
|
+
"#{fork} #{path} missing from fork"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
79
104
|
private_class_method :merge_one_content_path, :merge_all_present
|
|
80
105
|
end
|
|
81
106
|
end
|
|
@@ -27,6 +27,11 @@ module Pray
|
|
|
27
27
|
new_upstream = package.upstream
|
|
28
28
|
return false unless new_upstream && package.declaration.path
|
|
29
29
|
|
|
30
|
+
local_content = local_content_for_refresh(package.root, package.spec)
|
|
31
|
+
if local_content.empty?
|
|
32
|
+
return materialize_empty_path_fork(project, package, previous, sources, git_sources, user_config, options, new_upstream)
|
|
33
|
+
end
|
|
34
|
+
|
|
30
35
|
old_upstream = previous&.package&.find { |entry| entry.name == package.declaration.name }&.upstream
|
|
31
36
|
return false unless old_upstream
|
|
32
37
|
return false if old_upstream.version == new_upstream.version && old_upstream.tree_hash == new_upstream.tree_hash
|
|
@@ -40,6 +45,27 @@ module Pray
|
|
|
40
45
|
true
|
|
41
46
|
end
|
|
42
47
|
|
|
48
|
+
def materialize_empty_path_fork(project, package, previous, sources, git_sources, user_config, options, new_upstream)
|
|
49
|
+
new_package = resolve_named(
|
|
50
|
+
project.project_root, sources, git_sources, user_config, previous, options,
|
|
51
|
+
new_upstream.name, "= #{new_upstream.version}", new_upstream.source
|
|
52
|
+
)
|
|
53
|
+
new_content = content_file_bytes(new_package.root, new_package.spec)
|
|
54
|
+
write_content_files(package.root, {}, new_content)
|
|
55
|
+
write_refreshed_spec(package, new_package, {}, {}, new_content)
|
|
56
|
+
true
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def local_content_for_refresh(root, spec)
|
|
60
|
+
paths = content_paths(spec.files)
|
|
61
|
+
return {} if paths.empty?
|
|
62
|
+
|
|
63
|
+
missing = paths.count { |relative| !File.file?(File.join(root, relative)) }
|
|
64
|
+
return {} if missing == paths.length
|
|
65
|
+
|
|
66
|
+
content_file_bytes(root, spec)
|
|
67
|
+
end
|
|
68
|
+
|
|
43
69
|
def resolve_upstream_pair(project, previous, sources, git_sources, user_config, options, old_upstream, new_upstream)
|
|
44
70
|
old_package = resolve_named(
|
|
45
71
|
project.project_root, sources, git_sources, user_config, previous, options,
|
|
@@ -80,7 +106,6 @@ module Pray
|
|
|
80
106
|
updated = PackageSpecRender.fork_spec_after_refresh(
|
|
81
107
|
package.spec,
|
|
82
108
|
new_package.spec,
|
|
83
|
-
File.basename(spec_path),
|
|
84
109
|
clean_replica?(old_content, local_content),
|
|
85
110
|
merged.keys
|
|
86
111
|
)
|
|
@@ -138,7 +163,8 @@ module Pray
|
|
|
138
163
|
Transaction.write_file(File.join(root, relative), bytes)
|
|
139
164
|
end
|
|
140
165
|
end
|
|
141
|
-
private_class_method :apply_one_path_upstream, :
|
|
166
|
+
private_class_method :apply_one_path_upstream, :materialize_empty_path_fork, :local_content_for_refresh,
|
|
167
|
+
:resolve_upstream_pair, :merge_fork_content,
|
|
142
168
|
:write_refreshed_spec, :resolve_named
|
|
143
169
|
end
|
|
144
170
|
end
|
data/lib/pray/verify.rb
CHANGED
|
@@ -83,10 +83,10 @@ module Pray
|
|
|
83
83
|
message: "Package `#{package.declaration.name}` no longer matches the locked tree hash. Run `pray install` to re-resolve packages."
|
|
84
84
|
)
|
|
85
85
|
end
|
|
86
|
-
if locked.version != package.spec.
|
|
86
|
+
if locked.version != package.spec.recorded_version
|
|
87
87
|
report.findings << VerificationFinding.new(
|
|
88
88
|
kind: "verify_error",
|
|
89
|
-
message: "Package `#{package.declaration.name}` resolved to version #{package.spec.
|
|
89
|
+
message: "Package `#{package.declaration.name}` resolved to version #{package.spec.recorded_version} but `Prayfile.lock` has #{locked.version}. Run `pray install` to refresh the lockfile."
|
|
90
90
|
)
|
|
91
91
|
end
|
|
92
92
|
else
|
data/lib/pray/version.rb
CHANGED
data/lib/pray.rb
CHANGED
|
@@ -13,7 +13,13 @@ require_relative "pray/manifest"
|
|
|
13
13
|
require_relative "pray/format_serialize"
|
|
14
14
|
require_relative "pray/format_manifest"
|
|
15
15
|
require_relative "pray/package_spec"
|
|
16
|
+
require_relative "pray/package_spec_version"
|
|
17
|
+
require_relative "pray/local_prayer"
|
|
16
18
|
require_relative "pray/lockfile"
|
|
19
|
+
require_relative "pray/distribution"
|
|
20
|
+
require_relative "pray/torrent_manifest"
|
|
21
|
+
require_relative "pray/serve_range"
|
|
22
|
+
require_relative "pray/apply_report"
|
|
17
23
|
require_relative "pray/config"
|
|
18
24
|
require_relative "pray/dotenv"
|
|
19
25
|
require_relative "pray/project_context"
|
|
@@ -27,13 +33,17 @@ require_relative "pray/resolve_tarball"
|
|
|
27
33
|
require_relative "pray/invocation"
|
|
28
34
|
require_relative "pray/git_refresh"
|
|
29
35
|
require_relative "pray/resolve"
|
|
36
|
+
require_relative "pray/resolve_local"
|
|
30
37
|
require_relative "pray/upstream"
|
|
31
38
|
require_relative "pray/upstream_merge"
|
|
32
39
|
require_relative "pray/package_spec_render"
|
|
33
40
|
require_relative "pray/upstream_refresh"
|
|
41
|
+
require_relative "pray/upstream_drift"
|
|
34
42
|
require_relative "pray/upstream_latest"
|
|
35
43
|
require_relative "pray/compose_dest"
|
|
36
44
|
require_relative "pray/render_patch"
|
|
45
|
+
require_relative "pray/render_content"
|
|
46
|
+
require_relative "pray/render_managed"
|
|
37
47
|
require_relative "pray/render"
|
|
38
48
|
require_relative "pray/render_dest"
|
|
39
49
|
require_relative "pray/transaction"
|
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.17.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrei Makarov
|
|
@@ -102,6 +102,7 @@ files:
|
|
|
102
102
|
- bin/pray
|
|
103
103
|
- lib/pray-cli.rb
|
|
104
104
|
- lib/pray.rb
|
|
105
|
+
- lib/pray/apply_report.rb
|
|
105
106
|
- lib/pray/archive.rb
|
|
106
107
|
- lib/pray/archive_unpack.rb
|
|
107
108
|
- lib/pray/auth_client.rb
|
|
@@ -110,6 +111,8 @@ files:
|
|
|
110
111
|
- lib/pray/cli/commands/auth.rb
|
|
111
112
|
- lib/pray/cli/commands/distribution.rb
|
|
112
113
|
- lib/pray/cli/commands/init.rb
|
|
114
|
+
- lib/pray/cli/commands/init_prayer.rb
|
|
115
|
+
- lib/pray/cli/commands/init_prayer_manifest.rb
|
|
113
116
|
- lib/pray/cli/commands/meta.rb
|
|
114
117
|
- lib/pray/cli/commands/packages.rb
|
|
115
118
|
- lib/pray/cli/commands/trust.rb
|
|
@@ -127,6 +130,7 @@ files:
|
|
|
127
130
|
- lib/pray/constraint.rb
|
|
128
131
|
- lib/pray/dependency_graph.rb
|
|
129
132
|
- lib/pray/destination.rb
|
|
133
|
+
- lib/pray/distribution.rb
|
|
130
134
|
- lib/pray/dotenv.rb
|
|
131
135
|
- lib/pray/environment.rb
|
|
132
136
|
- lib/pray/error.rb
|
|
@@ -138,6 +142,7 @@ files:
|
|
|
138
142
|
- lib/pray/http_body.rb
|
|
139
143
|
- lib/pray/invocation.rb
|
|
140
144
|
- lib/pray/literal.rb
|
|
145
|
+
- lib/pray/local_prayer.rb
|
|
141
146
|
- lib/pray/lockfile.rb
|
|
142
147
|
- lib/pray/lockfile_serialize.rb
|
|
143
148
|
- lib/pray/manifest.rb
|
|
@@ -150,6 +155,7 @@ files:
|
|
|
150
155
|
- lib/pray/materialize.rb
|
|
151
156
|
- lib/pray/package_spec.rb
|
|
152
157
|
- lib/pray/package_spec_render.rb
|
|
158
|
+
- lib/pray/package_spec_version.rb
|
|
153
159
|
- lib/pray/path_safety.rb
|
|
154
160
|
- lib/pray/plan.rb
|
|
155
161
|
- lib/pray/project_context.rb
|
|
@@ -162,16 +168,19 @@ files:
|
|
|
162
168
|
- lib/pray/render_content.rb
|
|
163
169
|
- lib/pray/render_dest.rb
|
|
164
170
|
- lib/pray/render_layout.rb
|
|
171
|
+
- lib/pray/render_managed.rb
|
|
165
172
|
- lib/pray/render_patch.rb
|
|
166
173
|
- lib/pray/resolve.rb
|
|
167
174
|
- lib/pray/resolve_context.rb
|
|
168
175
|
- lib/pray/resolve_deps.rb
|
|
169
176
|
- lib/pray/resolve_exports.rb
|
|
177
|
+
- lib/pray/resolve_local.rb
|
|
170
178
|
- lib/pray/resolve_source.rb
|
|
171
179
|
- lib/pray/resolve_tarball.rb
|
|
172
180
|
- lib/pray/resource_limits.rb
|
|
173
181
|
- lib/pray/serve.rb
|
|
174
182
|
- lib/pray/serve_federation.rb
|
|
183
|
+
- lib/pray/serve_range.rb
|
|
175
184
|
- lib/pray/session.rb
|
|
176
185
|
- lib/pray/ssh_agent.rb
|
|
177
186
|
- lib/pray/statement_surface.rb
|
|
@@ -179,6 +188,7 @@ files:
|
|
|
179
188
|
- lib/pray/sync.rb
|
|
180
189
|
- lib/pray/tar_validation.rb
|
|
181
190
|
- lib/pray/terminal.rb
|
|
191
|
+
- lib/pray/torrent_manifest.rb
|
|
182
192
|
- lib/pray/transaction.rb
|
|
183
193
|
- lib/pray/transaction/journal.rb
|
|
184
194
|
- lib/pray/transaction/owner.rb
|
|
@@ -187,6 +197,7 @@ files:
|
|
|
187
197
|
- lib/pray/trust_feed.rb
|
|
188
198
|
- lib/pray/trust_ops.rb
|
|
189
199
|
- lib/pray/upstream.rb
|
|
200
|
+
- lib/pray/upstream_drift.rb
|
|
190
201
|
- lib/pray/upstream_latest.rb
|
|
191
202
|
- lib/pray/upstream_merge.rb
|
|
192
203
|
- lib/pray/upstream_refresh.rb
|