pray-cli 1.18.1 → 1.20.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.
@@ -7,10 +7,11 @@ module Pray
7
7
  GitSourceCheckout = Struct.new(:cache_directory, :revision, :subdir)
8
8
 
9
9
  class GitSourceSet
10
- def initialize(project_root, sources, lockfile, refresh:)
10
+ def initialize(project_root, sources, lockfile, refresh:, offline: false)
11
11
  @project_root = project_root
12
12
  @lockfile = lockfile
13
13
  @refresh = refresh
14
+ @offline = offline
14
15
  @sources = sources.select { |source| source.kind == "git" }.to_h { |source| [source.name, source] }
15
16
  @checkouts = {}
16
17
  end
@@ -21,7 +22,7 @@ module Pray
21
22
  source = @sources[name]
22
23
  return nil unless source
23
24
 
24
- checkout = GitSources.prepare_one_git_source(@project_root, source, @lockfile, refresh: @refresh)
25
+ checkout = GitSources.prepare_one_git_source(@project_root, source, @lockfile, refresh: @refresh, offline: @offline)
25
26
  @checkouts[name] = checkout if checkout
26
27
  checkout
27
28
  end
@@ -38,21 +39,21 @@ module Pray
38
39
  module GitSources
39
40
  module_function
40
41
 
41
- def prepare_git_sources(project_root, sources, lockfile, refresh: false)
42
- GitSourceSet.new(project_root, sources, lockfile, refresh: refresh)
42
+ def prepare_git_sources(project_root, sources, lockfile, refresh: false, offline: false)
43
+ GitSourceSet.new(project_root, sources, lockfile, refresh: refresh, offline: offline)
43
44
  end
44
45
 
45
- def prepare_one_git_source(project_root, source, lockfile, refresh:)
46
+ def prepare_one_git_source(project_root, source, lockfile, refresh:, offline: false)
46
47
  clone_url = source.url.delete_prefix("git+")
47
48
  if local_filesystem_source?(clone_url) && !local_git_repo_path(project_root, clone_url)
48
49
  source_root = local_git_source_root(project_root, clone_url)
49
- return unless source_root
50
-
51
- return GitSourceCheckout.new(
52
- cache_directory: source_root,
53
- revision: "",
54
- subdir: source.subdir
55
- )
50
+ if source_root
51
+ return GitSourceCheckout.new(
52
+ cache_directory: source_root,
53
+ revision: "",
54
+ subdir: source.subdir
55
+ )
56
+ end
56
57
  end
57
58
 
58
59
  pinned_revision = refresh ? nil : pinned_revision_for_source(lockfile, source)
@@ -61,7 +62,8 @@ module Pray
61
62
  clone_url,
62
63
  refresh: refresh,
63
64
  pinned_revision: pinned_revision,
64
- sparse_subdir: source.subdir
65
+ sparse_subdir: source.subdir,
66
+ offline: offline
65
67
  )
66
68
  GitSourceCheckout.new(
67
69
  cache_directory: cache_directory,
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require_relative "error"
5
+ require_relative "hashing"
6
+ require_relative "git_run"
7
+ require_relative "git_clone"
8
+
9
+ module Pray
10
+ module GitStore
11
+ module_function
12
+
13
+ def ensure_global_git_db(clone_url, pinned_revision:, refresh:, offline:, working_directory:)
14
+ db = global_git_cache_directory(clone_url)
15
+ raise Error.resolution("git object cache is not configured") unless db
16
+
17
+ unless global_git_cache_ready?(db)
18
+ raise Error.resolution(offline_git_source_uncached(clone_url)) if offline
19
+
20
+ FileUtils.rm_rf(db) if File.exist?(db)
21
+ FileUtils.mkdir_p(File.dirname(db))
22
+ GitClone.clone_bare_git_db(working_directory, clone_url, db, quiet: false)
23
+ ensure_git_remote_origin(db, clone_url)
24
+ end
25
+ fetch_origin_tip(db, clone_url) if refresh && !offline
26
+ if pinned_revision
27
+ ensure_revision_in_db(db, clone_url, pinned_revision, !offline)
28
+ return [db, pinned_revision]
29
+ end
30
+
31
+ [db, git_head_revision(db)]
32
+ end
33
+
34
+ def global_cache_root
35
+ return ENV["PRAY_CACHE"] if ENV["PRAY_CACHE"]
36
+ return File.join(ENV["PRAY_HOME"], "cache") if ENV["PRAY_HOME"]
37
+
38
+ home = ENV["HOME"]
39
+ home ? File.join(home, ".cache", "pray") : nil
40
+ end
41
+
42
+ def global_git_cache_directory(clone_url)
43
+ root = global_cache_root
44
+ root ? File.join(root, "git", Hashing.sha256_prefixed(clone_url)[7, 16]) : nil
45
+ end
46
+
47
+ def global_git_cache_ready?(global_cache)
48
+ File.file?(File.join(global_cache, "HEAD")) || File.directory?(File.join(global_cache, ".git"))
49
+ end
50
+
51
+ def offline_git_source_uncached(clone_url)
52
+ "git source #{clone_url} is not cached locally and offline mode is enabled"
53
+ end
54
+
55
+ def ensure_revision_in_db(db, clone_url, revision, allow_fetch)
56
+ return if GitRun.try_run_git(db, "cat-file", "-e", revision)
57
+ unless allow_fetch
58
+ raise Error.resolution(
59
+ "git source #{db.inspect} is locked to revision #{revision}, but that commit is not available locally and offline mode is enabled"
60
+ )
61
+ end
62
+
63
+ ensure_git_remote_origin(db, clone_url)
64
+ fetch_unshallow(db) if File.file?(File.join(db, "shallow"))
65
+ return if GitRun.try_run_git(db, "cat-file", "-e", revision)
66
+
67
+ fetch_revision(db, revision)
68
+ return if GitRun.try_run_git(db, "cat-file", "-e", revision)
69
+
70
+ raise Error.resolution(
71
+ "git source #{db.inspect} is locked to revision #{revision}, but that commit could not be fetched"
72
+ )
73
+ end
74
+
75
+ def ensure_git_remote_origin(repository, clone_url)
76
+ if GitRun.try_run_git(repository, "remote", "get-url", "origin")
77
+ GitRun.run_git(repository, "remote", "set-url", "origin", clone_url)
78
+ else
79
+ GitRun.run_git(repository, "remote", "add", "origin", clone_url)
80
+ end
81
+ end
82
+
83
+ def fetch_origin_tip(db, clone_url)
84
+ ensure_git_remote_origin(db, clone_url)
85
+ unless GitRun.try_run_git(db, "fetch", "--depth", "1", "--filter=blob:none", "origin")
86
+ GitRun.run_git(db, "fetch", "--depth", "1", "origin")
87
+ end
88
+ GitRun.run_git(db, "update-ref", "HEAD", "FETCH_HEAD")
89
+ end
90
+
91
+ def fetch_unshallow(db)
92
+ return if GitRun.try_run_git(db, "fetch", "--unshallow", "--filter=blob:none", "origin")
93
+
94
+ GitRun.run_git(db, "fetch", "--unshallow", "origin")
95
+ end
96
+
97
+ def fetch_revision(db, revision)
98
+ return if GitRun.try_run_git(db, "fetch", "--filter=blob:none", "origin", revision)
99
+
100
+ GitRun.run_git(db, "fetch", "origin", revision)
101
+ end
102
+
103
+ def git_head_revision(repository)
104
+ output, status = GitRun.capture_git(repository, "rev-parse", "HEAD")
105
+ raise Error.resolution(GitRun.command_error("git rev-parse HEAD", output)) unless status.success?
106
+
107
+ revision = output.strip
108
+ raise Error.resolution("git repository has no HEAD revision") if revision.empty?
109
+
110
+ revision
111
+ end
112
+ end
113
+ end
data/lib/pray/manifest.rb CHANGED
@@ -4,8 +4,11 @@ require_relative "manifest_json"
4
4
  require_relative "manifest_formatter"
5
5
  require_relative "manifest_parser_helpers"
6
6
  require_relative "manifest_parser_blocks"
7
+ require_relative "manifest_parser_publish"
7
8
  require_relative "manifest_parser"
8
9
  require_relative "path_safety"
10
+ require_relative "publish_remote"
11
+ require_relative "publish_select"
9
12
 
10
13
  module Pray
11
14
  RenderPolicy = Struct.new(
@@ -53,7 +56,7 @@ module Pray
53
56
  end
54
57
 
55
58
  Manifest = Struct.new(
56
- :prayfile_version, :sources, :targets, :packages, :local, :symbols, :render,
59
+ :prayfile_version, :sources, :targets, :packages, :local, :publish_remotes, :symbols, :render,
57
60
  :deprecated_keywords,
58
61
  keyword_init: true
59
62
  ) do
@@ -63,6 +66,7 @@ module Pray
63
66
  targets: [],
64
67
  packages: [],
65
68
  local: [],
69
+ publish_remotes: [],
66
70
  symbols: {},
67
71
  render: RenderPolicy.default,
68
72
  deprecated_keywords: []
@@ -99,6 +103,7 @@ module Pray
99
103
  copy.targets = targets.sort_by(&:name)
100
104
  copy.packages = packages.sort_by { |package| [package.name, package.source.to_s, package.constraint] }
101
105
  copy.local = local.sort_by(&:path)
106
+ copy.publish_remotes = (publish_remotes || []).sort_by(&:name)
102
107
  copy.deprecated_keywords = []
103
108
  end
104
109
  end
@@ -139,6 +144,7 @@ module Pray
139
144
  PathSafety.validate_project_relative_path!(local.path)
140
145
  PathSafety.validate_destination_path!(local.file) if local.file
141
146
  end
147
+ PublishRemote.validate_publish_remotes!(manifest)
142
148
  end
143
149
  end
144
150
 
@@ -17,10 +17,20 @@ module Pray
17
17
  "local" => manifest.local.map { |entry| local_fields(entry) }
18
18
  }
19
19
  fields["symbols"] = manifest.symbols.sort.to_h unless manifest.symbols.empty?
20
+ unless (manifest.publish_remotes || []).empty?
21
+ fields["publish_remotes"] = manifest.publish_remotes.map { |remote| publish_remote_fields(remote) }
22
+ end
20
23
  fields["render"] = render_fields(manifest.render)
21
24
  fields
22
25
  end
23
26
 
27
+ def publish_remote_fields(remote)
28
+ fields = {"name" => remote.name, "packages" => remote.packages}
29
+ fields["path"] = remote.path if remote.path
30
+ fields["url"] = remote.url if remote.url
31
+ fields
32
+ end
33
+
24
34
  def source_fields(source)
25
35
  fields = {
26
36
  "name" => source.name,
@@ -5,6 +5,7 @@ module Pray
5
5
  class BlockParser
6
6
  include ParserHelpers
7
7
  include ParserBlocks
8
+ include ParserPublish
8
9
 
9
10
  def initialize(lines)
10
11
  @lines = lines
@@ -41,6 +42,8 @@ module Pray
41
42
  manifest.prayfile_version = string_from_literal(Regexp.last_match(1))
42
43
  when /\Asource (.+)\z/
43
44
  manifest.sources << parse_source(Regexp.last_match(1))
45
+ when /\Apublish (.+)\z/
46
+ apply_publish(manifest, Regexp.last_match(1))
44
47
  when /\Atarget (.+)\z/
45
48
  apply_legacy_target(manifest, statement, Regexp.last_match(1), allow_target)
46
49
  when /\Agroup (.+)\z/
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pray
4
+ module ManifestMethods
5
+ module ParserPublish
6
+ def apply_publish(manifest, rest)
7
+ is_block = rest.rstrip.end_with?(" do")
8
+ header = rest.sub(/\s+do\z/, "").strip
9
+ remote = parse_publish_header(header)
10
+ parse_publish_block(remote) if is_block
11
+ manifest.publish_remotes << remote
12
+ end
13
+
14
+ def parse_publish_header(rest)
15
+ values, keywords = parse_call(rest)
16
+ raise Error.parse("manifest", "publish requires a name") if values.empty?
17
+
18
+ name = string_from_value(values.first)
19
+ if %w[git source signing_key token].any? { |key| keywords.key?(key) }
20
+ raise Error.parse(
21
+ "manifest",
22
+ "publish \"#{name}\" does not take git:, source:, signing_key:, or token:"
23
+ )
24
+ end
25
+ ManifestPublishRemote.new(
26
+ name: name,
27
+ path: keyword_string(keywords, "path"),
28
+ url: values[1] && string_from_value(values[1]),
29
+ packages: []
30
+ )
31
+ end
32
+
33
+ def parse_publish_block(remote)
34
+ while (statement = next_statement)
35
+ return if statement == "end"
36
+
37
+ pray_rest = statement[/\A(?:pray|use|include|agent|package) (.+)\z/, 1]
38
+ unless pray_rest
39
+ raise Error.parse("manifest", "publish blocks only support pray package names: #{statement}")
40
+ end
41
+
42
+ package = parse_package_decl(pray_rest)
43
+ if remote.packages.include?(package.name)
44
+ raise Error.parse("manifest", "duplicate package #{package.name} in publish \"#{remote.name}\"")
45
+ end
46
+ remote.packages << package.name
47
+ end
48
+ raise Error.parse("manifest", "missing 'end' for publish block")
49
+ end
50
+ end
51
+ end
52
+ end
data/lib/pray/publish.rb CHANGED
@@ -28,9 +28,7 @@ module Pray
28
28
  metadata = load_registry_package_metadata(metadata_path, package.declaration.name)
29
29
  existing = metadata.versions.find { |entry| entry.version == package.spec.version }
30
30
  stored_artifact = stored_package_artifact(root, artifact_path, package, existing, distribution)
31
- if stored_artifact && stored_publish_matches?(
32
- stored_artifact, package, signer, signer_fingerprint, existing
33
- )
31
+ if stored_artifact && stored_publish_matches?(stored_artifact, package, existing)
34
32
  package_names << package.declaration.name
35
33
  write_registry_package_metadata(metadata_path, metadata)
36
34
  next
@@ -134,10 +132,17 @@ module Pray
134
132
  artifact_bytes
135
133
  end
136
134
 
137
- def stored_publish_matches?(artifact_bytes, package, signer, signer_fingerprint, existing)
138
- existing.signer == signer &&
139
- existing.signer_fingerprint == signer_fingerprint &&
140
- existing.signature == Registry.registry_artifact_signature(artifact_bytes, package.tree_hash, signer)
135
+ # A stored row is current when its own recorded signature still authenticates the
136
+ # stored artifact. The check deliberately ignores who is publishing now: a row signed
137
+ # by another publisher is still a valid attestation of identical bytes, and rewriting
138
+ # it would restate authorship without republishing anything. A row carrying no
139
+ # signature is not current, so publish repairs it.
140
+ def stored_publish_matches?(artifact_bytes, package, existing)
141
+ return false if existing.signer.nil? || existing.signature.nil?
142
+
143
+ existing.signature == Registry.registry_artifact_signature(
144
+ artifact_bytes, package.tree_hash, existing.signer
145
+ )
141
146
  end
142
147
 
143
148
  def stored_prayspec_matches?(artifact_bytes, package_root)
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pray
4
+ ManifestPublishRemote = Struct.new(:name, :path, :url, :packages) do
5
+ def initialize(name:, path: nil, url: nil, packages: [])
6
+ super
7
+ end
8
+ end
9
+
10
+ module PublishRemote
11
+ module_function
12
+
13
+ def validate_publish_remotes!(manifest)
14
+ seen = {}
15
+ (manifest.publish_remotes || []).each do |remote|
16
+ raise Error.parse("manifest", "publish requires a name") if remote.name.to_s.strip.empty?
17
+ if seen[remote.name]
18
+ raise Error.manifest("duplicate publish remote: #{remote.name}")
19
+ end
20
+ seen[remote.name] = true
21
+ if remote.path && remote.url
22
+ raise Error.parse("manifest", "publish \"#{remote.name}\" must set path: or a URL, not both")
23
+ end
24
+ if remote.path.nil? && remote.url.nil?
25
+ raise Error.parse("manifest", "publish \"#{remote.name}\" requires path: or a URL")
26
+ end
27
+ PathSafety.validate_project_relative_path!(remote.path) if remote.path
28
+ if remote.url && !publish_url?(remote.url)
29
+ raise Error.parse(
30
+ "manifest",
31
+ "publish \"#{remote.name}\" URL must be https://, http://, pray+ssh://, or ssh+pray://"
32
+ )
33
+ end
34
+ validate_remote_packages!(manifest, remote)
35
+ end
36
+ end
37
+
38
+ def validate_remote_packages!(manifest, remote)
39
+ remote.packages.each do |package_name|
40
+ package = manifest.packages.find { |entry| entry.name == package_name }
41
+ unless package
42
+ raise Error.manifest("publish \"#{remote.name}\" lists unknown package #{package_name}")
43
+ end
44
+ next if package_is_path_owned?(package, manifest.sources)
45
+
46
+ raise Error.manifest(
47
+ "publish \"#{remote.name}\" lists #{package_name}, which is not a path package"
48
+ )
49
+ end
50
+ end
51
+
52
+ def package_is_path_owned?(package, sources)
53
+ return true if package.path
54
+ return false if package.git || package.tarball || package.oci
55
+
56
+ map = sources.to_h { |source| [source.name, source] }
57
+ name = ResolveSource.implied_source_name(package, map)
58
+ name && map[name]&.kind == "path"
59
+ rescue Error
60
+ false
61
+ end
62
+
63
+ def path_owned_package_names(manifest)
64
+ manifest.packages.select { |package| package_is_path_owned?(package, manifest.sources) }
65
+ .map(&:name)
66
+ end
67
+
68
+ def allowed_publish_names(manifest, listed)
69
+ listed.empty? ? path_owned_package_names(manifest) : listed
70
+ end
71
+
72
+ def publish_url?(url)
73
+ url.start_with?("https://", "http://", "pray+ssh://", "ssh+pray://")
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pray
4
+ module PublishSelect
5
+ module_function
6
+
7
+ PublishDestination = Struct.new(:name, :root, :server, :packages) do
8
+ def initialize(name:, root: nil, server: nil, packages: [])
9
+ super
10
+ end
11
+ end
12
+ PublishCliDest = Struct.new(:to, :roots, :servers) do
13
+ def initialize(to: [], roots: [], servers: [])
14
+ super
15
+ end
16
+ end
17
+
18
+ def resolve_publish_destinations(remotes, cli, project_root)
19
+ if !cli.to.empty? && (!cli.roots.empty? || !cli.servers.empty?)
20
+ raise Error.usage("publish --to cannot be combined with --root or --server")
21
+ end
22
+ return resolve_undeclared_destinations(cli) if remotes.empty?
23
+
24
+ select_remotes(remotes, cli, project_root).map do |remote|
25
+ PublishDestination.new(
26
+ name: remote.name,
27
+ root: remote.path && File.join(project_root, remote.path),
28
+ server: remote.url,
29
+ packages: remote.packages
30
+ )
31
+ end
32
+ end
33
+
34
+ def resolve_path_remote(remotes, to, root, project_root)
35
+ path_remotes = remotes.select(&:path)
36
+ if to
37
+ remote = remotes.find { |entry| entry.name == to }
38
+ raise Error.usage("unknown publish remote: #{to}") unless remote
39
+ unless remote.path
40
+ raise Error.usage("publish remote #{to} is a URL; yank, serve, and token need a path remote")
41
+ end
42
+ return File.join(project_root, remote.path)
43
+ end
44
+ if remotes.empty?
45
+ raise Error.usage("requires --root PATH") unless root
46
+
47
+ return root
48
+ end
49
+ if root
50
+ matched = remotes.find { |remote| remote.path && root_matches?(root, remote.path, project_root) }
51
+ raise Error.usage("path #{root} is not a declared publish remote") unless matched
52
+
53
+ return root
54
+ end
55
+ if path_remotes.length == 1 && path_remotes.first.path
56
+ return File.join(project_root, path_remotes.first.path)
57
+ end
58
+
59
+ raise Error.usage("say which path remote with --to NAME or --root PATH")
60
+ end
61
+
62
+ def resolve_undeclared_destinations(cli)
63
+ if !cli.to.empty?
64
+ raise Error.usage("Prayfile has no publish remotes; pass --root PATH or --server URL")
65
+ end
66
+ if cli.roots.empty? && cli.servers.empty?
67
+ raise Error.unsupported("publish requires at least one --root PATH or --server URL")
68
+ end
69
+
70
+ dests = cli.roots.map { |root| PublishDestination.new(name: root, root: root, packages: []) }
71
+ dests + cli.servers.map { |server| PublishDestination.new(name: server, server: server, packages: []) }
72
+ end
73
+
74
+ def select_remotes(remotes, cli, project_root)
75
+ unless cli.to.empty?
76
+ return cli.to.map do |name|
77
+ remote = remotes.find { |entry| entry.name == name }
78
+ raise Error.usage("unknown publish remote: #{name}") unless remote
79
+
80
+ remote
81
+ end
82
+ end
83
+ return remotes if cli.roots.empty? && cli.servers.empty?
84
+
85
+ selected = cli.roots.map do |root|
86
+ remote = remotes.find { |entry| entry.path && root_matches?(root, entry.path, project_root) }
87
+ raise Error.usage("path #{root} is not a declared publish remote") unless remote
88
+
89
+ remote
90
+ end
91
+ selected + cli.servers.map do |server|
92
+ remote = remotes.find { |entry| entry.url == server }
93
+ raise Error.usage("server #{server} is not a declared publish remote") unless remote
94
+
95
+ remote
96
+ end
97
+ end
98
+
99
+ def root_matches?(cli_root, remote_path, project_root)
100
+ declared = File.join(project_root, remote_path)
101
+ return true if cli_root == declared || cli_root == remote_path
102
+
103
+ strip_dot_slash(cli_root) == strip_dot_slash(remote_path)
104
+ end
105
+
106
+ def strip_dot_slash(value)
107
+ value.to_s.strip.delete_prefix("./").delete_suffix("/").tr("\\", "/")
108
+ end
109
+ end
110
+ end
@@ -19,7 +19,7 @@ module Pray
19
19
  used,
20
20
  output
21
21
  )
22
- splice_existing_managed(remaining, fresh_managed, used, output)
22
+ splice_existing_managed(remaining, fresh_segments, fresh_managed, used, output)
23
23
  append_unused_fresh_managed(fresh_segments, used, output)
24
24
  output.end_with?("\n") ? output : "#{output}\n"
25
25
  end
@@ -36,8 +36,8 @@ module Pray
36
36
  segments.filter_map { |segment| segment[:id] if segment[:kind] == :managed }.to_h { |id| [id, true] }
37
37
  end
38
38
 
39
- def splice_existing_managed(remaining, fresh_managed, used, output)
40
- remaining.each do |segment|
39
+ def splice_existing_managed(remaining, fresh_segments, fresh_managed, used, output)
40
+ remaining.each_with_index do |segment, index|
41
41
  if segment[:kind] == :text
42
42
  output << segment[:text]
43
43
  next
@@ -45,15 +45,47 @@ module Pray
45
45
 
46
46
  used[segment[:id]] = true
47
47
  output << managed_segment(segment[:id], fresh_managed.fetch(segment[:id], segment[:body]))
48
+ next_segment = remaining[index + 1]
49
+ next unless next_segment && next_segment[:kind] == :managed
50
+
51
+ output << text_between(fresh_segments, segment[:id], next_segment[:id])
48
52
  end
49
53
  end
50
54
 
55
+ def text_between(segments, left, right)
56
+ copying = false
57
+ text = +""
58
+ segments.each do |segment|
59
+ if segment[:kind] == :managed
60
+ if segment[:id] == left
61
+ copying = true
62
+ text = +""
63
+ elsif copying
64
+ return (segment[:id] == right) ? text : ""
65
+ end
66
+ elsif copying
67
+ text << segment[:text]
68
+ end
69
+ end
70
+ ""
71
+ end
72
+
51
73
  def append_unused_fresh_managed(fresh_segments, used, output)
74
+ pending = +""
75
+ seen_used = false
52
76
  fresh_segments.each do |segment|
53
- next unless segment[:kind] == :managed
54
- next if used[segment[:id]]
55
-
56
- output << managed_segment(segment[:id], segment[:body])
77
+ if segment[:kind] == :managed
78
+ if used[segment[:id]]
79
+ seen_used = true
80
+ pending = +""
81
+ next
82
+ end
83
+ output << pending
84
+ pending = +""
85
+ output << managed_segment(segment[:id], segment[:body])
86
+ elsif seen_used
87
+ pending << segment[:text]
88
+ end
57
89
  end
58
90
  end
59
91
 
data/lib/pray/resolve.rb CHANGED
@@ -59,7 +59,8 @@ module Pray
59
59
  project_root,
60
60
  manifest.sources,
61
61
  lockfile_hints,
62
- refresh: options.refresh || options.refresh_source_revisions
62
+ refresh: options.refresh || options.refresh_source_revisions,
63
+ offline: options.offline
63
64
  )
64
65
  source_host_keys = Trust.prepare_source_host_keys(manifest.sources)
65
66
 
@@ -10,7 +10,8 @@ module Pray
10
10
  project.project_root,
11
11
  project.manifest.sources,
12
12
  previous,
13
- refresh: options.refresh || options.refresh_source_revisions
13
+ refresh: options.refresh || options.refresh_source_revisions,
14
+ offline: options.offline
14
15
  )
15
16
  sources = Resolve.source_map(project.manifest.sources)
16
17
  lines = []
@@ -15,7 +15,8 @@ module Pray
15
15
  project.project_root,
16
16
  project.manifest.sources,
17
17
  previous,
18
- refresh: options.refresh || options.refresh_source_revisions
18
+ refresh: options.refresh || options.refresh_source_revisions,
19
+ offline: options.offline
19
20
  )
20
21
  sources = Resolve.source_map(project.manifest.sources)
21
22
  plans = []
@@ -10,7 +10,8 @@ module Pray
10
10
  project.project_root,
11
11
  project.manifest.sources,
12
12
  previous,
13
- refresh: options.refresh || options.refresh_source_revisions
13
+ refresh: options.refresh || options.refresh_source_revisions,
14
+ offline: options.offline
14
15
  )
15
16
  sources = Resolve.source_map(project.manifest.sources)
16
17
  changed = false
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.18.1"
5
- GENERATED_BY = "pray 1.18.1"
4
+ VERSION = "1.20.0"
5
+ GENERATED_BY = "pray 1.20.0"
6
6
  end