Skip to main content

spec_driven_docs/commands/
upgrade.rs

1//! `upgrade` subcommand: runtime-shape.
2//!
3//! Resolves the target, runs the upgrader, prints its report, and turns
4//! conflicts or unfinished removals into the red exit. Upgrade semantics
5//! live in `services::upgrader`.
6
7use crate::cli::upgrade::UpgradeArgs;
8use crate::context::AppContext;
9use crate::error::AppError;
10use crate::output;
11use crate::services::upgrader::{UpgradeOptions, upgrade};
12
13/// Upgrade an installed instance to this binary's version.
14///
15/// # Errors
16///
17/// [`AppError::Violations`] on conflicts or unfinished removals; whatever
18/// the upgrader refuses otherwise.
19pub fn run(ctx: &AppContext, args: UpgradeArgs) -> Result<(), AppError> {
20    let target = if args.target.is_absolute() {
21        args.target
22    } else if args.target == "." {
23        ctx.cwd.clone()
24    } else {
25        return Err(AppError::Usage("target must be absolute or .".to_string()));
26    };
27    crate::commands::front::serves(crate::plan::classify::Intent::Upgrade, &target)?;
28    let selections = crate::plan::decision::parse(&args.set)
29        .map_err(|error| AppError::Usage(error.to_string()))?;
30    let outcome = upgrade(
31        &UpgradeOptions {
32            target,
33            dry_run: args.dry_run,
34            selections,
35        },
36        &crate::release::embedded::EmbeddedReleaseBundle::new(),
37    )?;
38    for line in &outcome.lines {
39        output::line(line);
40    }
41    if outcome.failures > 0 {
42        return Err(AppError::Violations {
43            count: outcome.failures,
44        });
45    }
46    Ok(())
47}