Skip to content

Commit fa94050

Browse files
authored
Merge pull request #921 from antheas/main
feat(upgrade): Add total progress bar and JSON output
2 parents 39559aa + 518435f commit fa94050

File tree

7 files changed

+568
-24
lines changed

7 files changed

+568
-24
lines changed

lib/src/cli.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
use std::ffi::{CString, OsStr, OsString};
66
use std::io::Seek;
7+
use std::os::fd::RawFd;
78
use std::os::unix::process::CommandExt;
89
use std::process::Command;
910

@@ -25,6 +26,8 @@ use serde::{Deserialize, Serialize};
2526

2627
use crate::deploy::RequiredHostSpec;
2728
use crate::lints;
29+
use crate::progress_jsonl;
30+
use crate::progress_jsonl::ProgressWriter;
2831
use crate::spec::Host;
2932
use crate::spec::ImageReference;
3033
use crate::utils::sigpolicy_from_opts;
@@ -52,6 +55,10 @@ pub(crate) struct UpgradeOpts {
5255
/// a userspace-only restart.
5356
#[clap(long, conflicts_with = "check")]
5457
pub(crate) apply: bool,
58+
59+
/// Pipe download progress to this fd in a jsonl format.
60+
#[clap(long)]
61+
pub(crate) json_fd: Option<RawFd>,
5562
}
5663

5764
/// Perform an switch operation
@@ -101,6 +108,10 @@ pub(crate) struct SwitchOpts {
101108

102109
/// Target image to use for the next boot.
103110
pub(crate) target: String,
111+
112+
/// Pipe download progress to this fd in a jsonl format.
113+
#[clap(long)]
114+
pub(crate) json_fd: Option<RawFd>,
104115
}
105116

106117
/// Options controlling rollback
@@ -644,6 +655,12 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
644655
let (booted_deployment, _deployments, host) =
645656
crate::status::get_status_require_booted(sysroot)?;
646657
let imgref = host.spec.image.as_ref();
658+
let prog = opts
659+
.json_fd
660+
.map(progress_jsonl::ProgressWriter::from_raw_fd)
661+
.transpose()?
662+
.unwrap_or_default();
663+
647664
// If there's no specified image, let's be nice and check if the booted system is using rpm-ostree
648665
if imgref.is_none() {
649666
let booted_incompatible = host
@@ -700,7 +717,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
700717
}
701718
}
702719
} else {
703-
let fetched = crate::deploy::pull(repo, imgref, None, opts.quiet).await?;
720+
let fetched = crate::deploy::pull(repo, imgref, None, opts.quiet, prog.clone()).await?;
704721
let staged_digest = staged_image.map(|s| s.digest().expect("valid digest in status"));
705722
let fetched_digest = &fetched.manifest_digest;
706723
tracing::debug!("staged: {staged_digest:?}");
@@ -723,7 +740,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
723740
println!("No update available.")
724741
} else {
725742
let osname = booted_deployment.osname();
726-
crate::deploy::stage(sysroot, &osname, &fetched, &spec).await?;
743+
crate::deploy::stage(sysroot, &osname, &fetched, &spec, prog.clone()).await?;
727744
changed = true;
728745
if let Some(prev) = booted_image.as_ref() {
729746
if let Some(fetched_manifest) = fetched.get_manifest(repo)? {
@@ -759,6 +776,11 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
759776
);
760777
let target = ostree_container::OstreeImageReference { sigverify, imgref };
761778
let target = ImageReference::from(target);
779+
let prog = opts
780+
.json_fd
781+
.map(progress_jsonl::ProgressWriter::from_raw_fd)
782+
.transpose()?
783+
.unwrap_or_default();
762784

763785
// If we're doing an in-place mutation, we shortcut most of the rest of the work here
764786
if opts.mutate_in_place {
@@ -794,7 +816,7 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
794816
}
795817
let new_spec = RequiredHostSpec::from_spec(&new_spec)?;
796818

797-
let fetched = crate::deploy::pull(repo, &target, None, opts.quiet).await?;
819+
let fetched = crate::deploy::pull(repo, &target, None, opts.quiet, prog.clone()).await?;
798820

799821
if !opts.retain {
800822
// By default, we prune the previous ostree ref so it will go away after later upgrades
@@ -808,7 +830,7 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
808830
}
809831

810832
let stateroot = booted_deployment.osname();
811-
crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec).await?;
833+
crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec, prog.clone()).await?;
812834

813835
if opts.apply {
814836
crate::reboot::reboot()?;
@@ -850,18 +872,20 @@ async fn edit(opts: EditOpts) -> Result<()> {
850872
host.spec.verify_transition(&new_host.spec)?;
851873
let new_spec = RequiredHostSpec::from_spec(&new_host.spec)?;
852874

875+
let prog = ProgressWriter::default();
876+
853877
// We only support two state transitions right now; switching the image,
854878
// or flipping the bootloader ordering.
855879
if host.spec.boot_order != new_host.spec.boot_order {
856880
return crate::deploy::rollback(sysroot).await;
857881
}
858882

859-
let fetched = crate::deploy::pull(repo, new_spec.image, None, opts.quiet).await?;
883+
let fetched = crate::deploy::pull(repo, new_spec.image, None, opts.quiet, prog.clone()).await?;
860884

861885
// TODO gc old layers here
862886

863887
let stateroot = booted_deployment.osname();
864-
crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec).await?;
888+
crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec, prog.clone()).await?;
865889

866890
Ok(())
867891
}

0 commit comments

Comments
 (0)