pray-cli 1.20.0 → 1.22.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.
data/lib/pray/publish.rb CHANGED
@@ -4,6 +4,7 @@ require "json"
4
4
  require "fileutils"
5
5
  require "time"
6
6
  require "tmpdir"
7
+ require_relative "terminal"
7
8
 
8
9
  module Pray
9
10
  RegistryIndex = Struct.new(:spec, :packages) do
@@ -15,11 +16,14 @@ module Pray
15
16
  module Publish
16
17
  module_function
17
18
 
18
- def publish_to_root(project, root, signer: "local", signer_fingerprint: nil)
19
+ def publish_to_root(project, root, signer: "local", signer_fingerprint: nil, dest_name: nil, target: nil)
19
20
  root = File.expand_path(root)
21
+ dest_name ||= root
22
+ target ||= root
20
23
  index = load_registry_index(root)
21
24
  distribution = Distribution.read_settings(root)
22
25
  package_names = index.packages.to_set
26
+ stats = {published: 0, unchanged: 0}
23
27
 
24
28
  project.packages.each do |package|
25
29
  package.spec.require_release_version!
@@ -31,6 +35,8 @@ module Pray
31
35
  if stored_artifact && stored_publish_matches?(stored_artifact, package, existing)
32
36
  package_names << package.declaration.name
33
37
  write_registry_package_metadata(metadata_path, metadata)
38
+ report_unchanged(package, dest_name, target)
39
+ stats[:unchanged] += 1
34
40
  next
35
41
  end
36
42
 
@@ -56,14 +62,20 @@ module Pray
56
62
  metadata.versions << version_entry
57
63
  write_registry_package_metadata(metadata_path, metadata)
58
64
  package_names << package.declaration.name
65
+ report_published(package, dest_name, target, artifact_path)
66
+ stats[:published] += 1
59
67
  end
60
68
 
61
69
  index.packages = package_names.sort
62
70
  write_registry_index(root, index)
71
+ stats
63
72
  end
64
73
 
65
- def publish_to_server(project, server_url, signer: "local", signer_fingerprint: nil)
74
+ def publish_to_server(project, server_url, signer: "local", signer_fingerprint: nil, dest_name: nil, target: nil)
75
+ dest_name ||= server_url
76
+ target ||= server_url
66
77
  distribution = Distribution.fetch_settings(server_url)
78
+ stats = {published: 0, unchanged: 0}
67
79
  project.packages.each do |package|
68
80
  archive_bytes = Archive.build_package_archive_bytes(package)
69
81
  artifact_path = registry_artifact_path(package.declaration.name, package.spec.version)
@@ -99,9 +111,38 @@ module Pray
99
111
  "application/json",
100
112
  JSON.pretty_generate(metadata_to_hash(metadata))
101
113
  )
114
+ report_published(package, dest_name, target, artifact_path)
115
+ stats[:published] += 1
102
116
  end
117
+ stats
103
118
  end
104
119
 
120
+ def report_published(package, dest_name, target, artifact_path)
121
+ Terminal.println_stdout(
122
+ "published #{package.declaration.name} #{package.spec.version} -> #{redact_publish_target(dest_name)} (#{redact_publish_target(target)})"
123
+ )
124
+ Terminal.println_verbose(" artifact #{artifact_path}")
125
+ end
126
+
127
+ def report_unchanged(package, dest_name, target)
128
+ Terminal.println_stdout(
129
+ "unchanged #{package.declaration.name} #{package.spec.version} -> #{redact_publish_target(dest_name)} (#{redact_publish_target(target)})"
130
+ )
131
+ Terminal.println_verbose(" skip reason: stored publish matches")
132
+ end
133
+
134
+ def redact_publish_target(target)
135
+ text = target.to_s
136
+ return text unless text.include?("://")
137
+
138
+ scheme, remainder = text.split("://", 2)
139
+ return text unless remainder&.include?("@")
140
+
141
+ _userinfo, host_and_path = remainder.split("@", 2)
142
+ "#{scheme}://***@#{host_and_path}"
143
+ end
144
+ private_class_method :report_published, :report_unchanged
145
+
105
146
  def published_registry_package_version(package, signer, signer_fingerprint, archive_bytes, artifact_path)
106
147
  RegistryPackageVersion.new(
107
148
  version: package.spec.version,
@@ -114,7 +155,8 @@ module Pray
114
155
  signer: signer,
115
156
  signer_fingerprint: signer_fingerprint,
116
157
  published_at: Time.now.to_i,
117
- signature: Registry.registry_artifact_signature(archive_bytes, package.tree_hash, signer)
158
+ signature: Registry.registry_artifact_signature(archive_bytes, package.tree_hash, signer),
159
+ derived_metadata: DerivedMetadata.from_package_root(package.root, package.spec)
118
160
  )
119
161
  end
120
162
 
@@ -163,6 +205,7 @@ module Pray
163
205
 
164
206
  version_entry.yanked = existing.yanked
165
207
  version_entry.published_at = existing.published_at if stored_artifact
208
+ version_entry.derived_metadata ||= existing.derived_metadata
166
209
  end
167
210
 
168
211
  def load_registry_index(root)
@@ -181,7 +224,7 @@ module Pray
181
224
 
182
225
  def load_registry_package_metadata(path, package_name)
183
226
  if File.exist?(path)
184
- data = JSON.parse(File.read(path))
227
+ data = JSON.parse(File.read(path, encoding: "UTF-8"))
185
228
  RegistryPackageMetadata.new(
186
229
  name: data["name"],
187
230
  versions: Array(data["versions"]).map { |entry| Registry.version_from_hash(entry) }
@@ -193,7 +236,7 @@ module Pray
193
236
 
194
237
  def write_registry_package_metadata(path, metadata)
195
238
  FileUtils.mkdir_p(File.dirname(path))
196
- File.write(path, JSON.pretty_generate(metadata_to_hash(metadata)))
239
+ File.write(path, JSON.pretty_generate(metadata_to_hash(metadata)), encoding: "UTF-8")
197
240
  end
198
241
 
199
242
  def metadata_to_hash(metadata)
@@ -217,6 +260,7 @@ module Pray
217
260
  hash["signer_fingerprint"] = entry.signer_fingerprint if entry.signer_fingerprint
218
261
  hash["published_at"] = entry.published_at if entry.published_at
219
262
  hash["signature"] = entry.signature if entry.signature
263
+ hash["derived_metadata"] = entry.derived_metadata if entry.derived_metadata
220
264
  hash
221
265
  end
222
266
 
data/lib/pray/registry.rb CHANGED
@@ -15,15 +15,17 @@ require_relative "git_materialize"
15
15
  module Pray
16
16
  RegistryPackageVersion = Struct.new(
17
17
  :version, :artifact, :artifact_hash, :tree_hash, :yanked, :targets, :exports,
18
- :signer, :signer_fingerprint, :published_at, :signature
18
+ :signer, :signer_fingerprint, :published_at, :signature, :derived_metadata
19
19
  ) do
20
20
  def initialize(
21
21
  artifact_hash: nil, tree_hash: nil, yanked: false, targets: [], exports: [],
22
- signer: nil, signer_fingerprint: nil, published_at: nil, signature: nil, **kwargs
22
+ signer: nil, signer_fingerprint: nil, published_at: nil, signature: nil,
23
+ derived_metadata: nil, **kwargs
23
24
  )
24
25
  super(**kwargs, artifact_hash: artifact_hash, tree_hash: tree_hash, yanked: yanked,
25
26
  targets: targets, exports: exports, signer: signer,
26
- signer_fingerprint: signer_fingerprint, published_at: published_at, signature: signature)
27
+ signer_fingerprint: signer_fingerprint, published_at: published_at,
28
+ signature: signature, derived_metadata: derived_metadata)
27
29
  end
28
30
  end
29
31
 
@@ -118,7 +120,7 @@ module Pray
118
120
 
119
121
  raise Error.resolution(offline_package_error(declaration.name, selected.version)) if offline
120
122
 
121
- artifact_bytes = read_local_artifact_bytes(source_root, selected.artifact)
123
+ artifact_bytes = read_local_artifact_bytes(source_root, selected.artifact, offline: offline)
122
124
  RegistryInstall.install_artifact_to_cache(
123
125
  cache_directory, declaration, selected, artifact_bytes, source_url: source_root
124
126
  )
@@ -159,15 +161,16 @@ module Pray
159
161
  signer: entry["signer"],
160
162
  signer_fingerprint: entry["signer_fingerprint"],
161
163
  published_at: entry.key?("published_at") ? publish_timestamp_from_value(entry["published_at"]) : nil,
162
- signature: entry["signature"]
164
+ signature: entry["signature"],
165
+ derived_metadata: entry["derived_metadata"]
163
166
  )
164
167
  end
165
168
 
166
169
  def publish_timestamp_from_value(value)
167
170
  timestamp = case value
171
+ when nil then return nil
168
172
  when Integer then value
169
- when String
170
- value.match?(/\A\d+\z/) ? value.to_i : Time.iso8601(value).to_i
173
+ when String then value.match?(/\A\d+\z/) ? value.to_i : Time.iso8601(value).to_i
171
174
  end
172
175
  unless timestamp&.between?(0, 253_402_300_799)
173
176
  raise Error.integrity("registry published_at must be whole UTC Unix seconds")
@@ -206,8 +209,8 @@ module Pray
206
209
  Gem::Version.new(left) <=> Gem::Version.new(right)
207
210
  end
208
211
 
209
- def read_local_artifact_bytes(source_root, artifact)
210
- GitMaterialize.read_local_artifact_bytes(source_root, artifact)
212
+ def read_local_artifact_bytes(source_root, artifact, offline: false)
213
+ GitMaterialize.read_local_artifact_bytes(source_root, artifact, offline: offline)
211
214
  end
212
215
 
213
216
  def read_artifact_bytes(source_url, artifact)
data/lib/pray/sync.rb CHANGED
@@ -205,10 +205,7 @@ module Pray
205
205
  end
206
206
 
207
207
  def fetch_bytes(peer_source, artifact)
208
- if artifact.start_with?("http://", "https://")
209
- return Registry.http_get(artifact).b
210
- end
211
-
208
+ Registry.reject_absolute_artifact!(artifact)
212
209
  Registry.http_get("#{trim_slash(peer_source)}/#{artifact.delete_prefix("/")}").b
213
210
  end
214
211
 
@@ -38,6 +38,8 @@ module Pray
38
38
 
39
39
  def process_entry(header, data, size, state, output_directory)
40
40
  type = header.byteslice(156, 1)
41
+ # git archive emits a pax global header (`g`); ignore without applying path.
42
+ return if type == "g"
41
43
  if type == "x"
42
44
  state.pending_path = pax_path(data)
43
45
  return
data/lib/pray/terminal.rb CHANGED
@@ -20,6 +20,34 @@ module Pray
20
20
  env_truthy?("PRAY_NO_INPUT")
21
21
  end
22
22
 
23
+ def quiet?
24
+ env_truthy?("PRAY_QUIET")
25
+ end
26
+
27
+ def verbose?
28
+ level = ENV.fetch("PRAY_VERBOSE", "0").to_i
29
+ level > 0
30
+ end
31
+
32
+ def configure_output!(quiet:, verbose:)
33
+ ENV["PRAY_QUIET"] = "1" if quiet
34
+ if verbose > 0
35
+ ENV["PRAY_VERBOSE"] = verbose.to_s
36
+ end
37
+ end
38
+
39
+ def println_stdout(message)
40
+ return if quiet?
41
+
42
+ puts message
43
+ end
44
+
45
+ def println_verbose(message)
46
+ return if quiet? || !verbose?
47
+
48
+ puts message
49
+ end
50
+
23
51
  def env_truthy?(name)
24
52
  value = ENV.fetch(name, nil)
25
53
  return false if value.nil?
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "json"
4
+ require_relative "git_run"
4
5
 
5
6
  module Pray
6
7
  module Trust
@@ -189,7 +190,7 @@ module Pray
189
190
 
190
191
  def git_format(repository, format)
191
192
  output = IO.popen(
192
- ["git", "-C", repository, "log", "-1", "--format=#{format}"],
193
+ [GitRun.git_env, "git", "-C", repository, "log", "-1", "--format=#{format}"],
193
194
  err: File::NULL, &:read
194
195
  )
195
196
  return "" unless $?.success?
@@ -39,13 +39,15 @@ module Pray
39
39
  when [false, true, false]
40
40
  (local == old) ? :omit : :conflict
41
41
  when [false, false, true]
42
- (old == new) ? :omit : new
42
+ (old == new) ? :omit : :conflict
43
43
  when [true, false, true]
44
44
  new
45
45
  when [true, true, false]
46
46
  local
47
47
  when [true, false, false]
48
48
  (local == new) ? new : :conflict
49
+ when [false, true, true]
50
+ :omit
49
51
  else
50
52
  :conflict
51
53
  end
@@ -67,7 +69,9 @@ module Pray
67
69
 
68
70
  def merge_conflict_message(fork, upstream_name, old_version, new_version, paths)
69
71
  "upstream merge conflict in #{fork} while refreshing #{upstream_name} " \
70
- "#{old_version} to #{new_version}: #{paths.join(", ")}"
72
+ "#{old_version} to #{new_version}: #{paths.join(", ")}. " \
73
+ "Reset those content files to the locked upstream tree, run `pray update --latest`, " \
74
+ "re-apply intentional overlays, then bump the fork version (upstream_merge_conflict)."
71
75
  end
72
76
 
73
77
  def next_upstream_constraint(current, new_version)
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pray
4
+ module Upstream
5
+ PathUpstreamConflict = Struct.new(
6
+ :package_name,
7
+ :upstream_name,
8
+ :old_version,
9
+ :new_version,
10
+ :paths,
11
+ keyword_init: true
12
+ )
13
+
14
+ module_function
15
+
16
+ def plan_path_upstream_conflicts(project, previous, selected, options)
17
+ user_config = Config.load_user_config
18
+ git_sources = GitSources.prepare_git_sources(
19
+ project.project_root,
20
+ project.manifest.sources,
21
+ previous,
22
+ refresh: options.refresh || options.refresh_source_revisions,
23
+ offline: options.offline
24
+ )
25
+ sources = Resolve.source_map(project.manifest.sources)
26
+ conflicts = []
27
+ project.packages.each do |package|
28
+ next if selected && package.declaration.name != selected
29
+
30
+ conflict = plan_one_path_upstream_conflict(
31
+ project, package, previous, sources, git_sources, user_config, options
32
+ )
33
+ conflicts << conflict if conflict
34
+ end
35
+ conflicts
36
+ end
37
+
38
+ def report_path_upstream_would_conflicts(project, previous, selected, options)
39
+ conflicts = plan_path_upstream_conflicts(project, previous, selected, options)
40
+ return if conflicts.empty?
41
+
42
+ messages = conflicts.map do |conflict|
43
+ puts "would-conflict #{conflict.package_name}: #{conflict.paths.join(", ")}"
44
+ merge_conflict_message(
45
+ conflict.package_name,
46
+ conflict.upstream_name,
47
+ conflict.old_version,
48
+ conflict.new_version,
49
+ conflict.paths
50
+ )
51
+ end
52
+ raise Error.resolution(messages.join("\n"))
53
+ end
54
+
55
+ def plan_one_path_upstream_conflict(project, package, previous, sources, git_sources, user_config, options)
56
+ new_upstream = package.upstream
57
+ return nil unless new_upstream && package.declaration.path
58
+
59
+ local_content = local_content_for_refresh(package.root, package.spec)
60
+ return nil if local_content.empty?
61
+
62
+ old_upstream = previous&.package&.find { |entry| entry.name == package.declaration.name }&.upstream
63
+ return nil unless old_upstream
64
+ return nil if old_upstream.version == new_upstream.version && old_upstream.tree_hash == new_upstream.tree_hash
65
+
66
+ old_package, new_package = resolve_upstream_pair(
67
+ project, previous, sources, git_sources, user_config, options, old_upstream, new_upstream
68
+ )
69
+ old_content = content_file_bytes(old_package.root, old_package.spec)
70
+ new_content = content_file_bytes(new_package.root, new_package.spec)
71
+ _merged, conflict_paths = try_merge_content_files(old_content, new_content, local_content)
72
+ return nil if conflict_paths.empty?
73
+
74
+ PathUpstreamConflict.new(
75
+ package_name: package.declaration.name,
76
+ upstream_name: old_upstream.name,
77
+ old_version: old_upstream.version,
78
+ new_version: new_upstream.version,
79
+ paths: conflict_paths
80
+ )
81
+ end
82
+ private_class_method :plan_one_path_upstream_conflict
83
+ end
84
+ end
data/lib/pray/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pray
4
- VERSION = "1.20.0"
5
- GENERATED_BY = "pray 1.20.0"
4
+ VERSION = "1.22.0"
5
+ GENERATED_BY = "pray 1.22.0"
6
6
  end
data/lib/pray.rb CHANGED
@@ -13,6 +13,7 @@ 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_paths"
16
17
  require_relative "pray/package_spec_version"
17
18
  require_relative "pray/local_prayer"
18
19
  require_relative "pray/lockfile"
@@ -38,6 +39,7 @@ require_relative "pray/upstream"
38
39
  require_relative "pray/upstream_merge"
39
40
  require_relative "pray/package_spec_render"
40
41
  require_relative "pray/upstream_refresh"
42
+ require_relative "pray/upstream_plan"
41
43
  require_relative "pray/upstream_drift"
42
44
  require_relative "pray/upstream_latest"
43
45
  require_relative "pray/compose_dest"
@@ -57,6 +59,7 @@ require_relative "pray/http_body"
57
59
  require_relative "pray/registry_install"
58
60
  require_relative "pray/registry_integrity"
59
61
  require_relative "pray/registry"
62
+ require_relative "pray/derived_metadata"
60
63
  require_relative "pray/archive_unpack"
61
64
  require_relative "pray/archive"
62
65
  require_relative "pray/plan"
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.20.0
4
+ version: 1.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Makarov
@@ -129,6 +129,7 @@ files:
129
129
  - lib/pray/config.rb
130
130
  - lib/pray/constraint.rb
131
131
  - lib/pray/dependency_graph.rb
132
+ - lib/pray/derived_metadata.rb
132
133
  - lib/pray/destination.rb
133
134
  - lib/pray/distribution.rb
134
135
  - lib/pray/dotenv.rb
@@ -138,6 +139,7 @@ files:
138
139
  - lib/pray/format_serialize.rb
139
140
  - lib/pray/git_cache.rb
140
141
  - lib/pray/git_clone.rb
142
+ - lib/pray/git_legacy.rb
141
143
  - lib/pray/git_materialize.rb
142
144
  - lib/pray/git_refresh.rb
143
145
  - lib/pray/git_run.rb
@@ -160,6 +162,7 @@ files:
160
162
  - lib/pray/manifest_parser_publish.rb
161
163
  - lib/pray/materialize.rb
162
164
  - lib/pray/package_spec.rb
165
+ - lib/pray/package_spec_paths.rb
163
166
  - lib/pray/package_spec_render.rb
164
167
  - lib/pray/package_spec_version.rb
165
168
  - lib/pray/path_safety.rb
@@ -209,6 +212,7 @@ files:
209
212
  - lib/pray/upstream_drift.rb
210
213
  - lib/pray/upstream_latest.rb
211
214
  - lib/pray/upstream_merge.rb
215
+ - lib/pray/upstream_plan.rb
212
216
  - lib/pray/upstream_refresh.rb
213
217
  - lib/pray/verify.rb
214
218
  - lib/pray/verify_locked_dest.rb
@@ -240,7 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
240
244
  - !ruby/object:Gem::Version
241
245
  version: '0'
242
246
  requirements: []
243
- rubygems_version: 4.0.3
247
+ rubygems_version: 4.0.20
244
248
  specification_version: 4
245
249
  summary: Package manager for the language placed before inference (Prayfile)
246
250
  test_files: []