grex_cli/cli/verbs/
migrate_lockfile.rs1use crate::cli::args::{GlobalFlags, MigrateLockfileArgs};
28use anyhow::Result;
29use grex_core::lockfile::migrate_v1_1_1::migrate_v1_1_1_lockfile;
30use grex_core::lockfile::{detect_legacy_lockfile, meta_lockfile_path};
31use std::path::Path;
32use tokio_util::sync::CancellationToken;
33
34pub fn run(
35 args: MigrateLockfileArgs,
36 global: &GlobalFlags,
37 _cancel: &CancellationToken,
38) -> Result<()> {
39 crate::cli::deprecation::warn_workspace_alias_used();
40 let workspace = match args.pack.clone() {
41 Some(p) => p,
42 None => std::env::current_dir()?,
43 };
44 let dry_run = args.dry_run || global.dry_run;
45
46 if dry_run {
47 run_dry_run(&workspace, global.json)
48 } else {
49 run_migrate(&workspace, global.json)
50 }
51}
52
53fn run_dry_run(workspace: &std::path::Path, json: bool) -> Result<()> {
58 let lockfile = meta_lockfile_path(workspace);
59 if !lockfile.exists() {
60 emit_outcome(json, &lockfile, Outcome::NoLockfile, true);
61 return Ok(());
62 }
63 let legacy = detect_legacy_lockfile(workspace)?;
64 let outcome = if legacy { Outcome::WouldMigrate } else { Outcome::AlreadyMigrated };
65 emit_outcome(json, &lockfile, outcome, true);
66 Ok(())
67}
68
69fn run_migrate(workspace: &std::path::Path, json: bool) -> Result<()> {
72 let report = migrate_v1_1_1_lockfile(workspace)?;
73 let outcome = if report.no_lockfile {
74 Outcome::NoLockfile
75 } else if report.already_migrated {
76 Outcome::AlreadyMigrated
77 } else {
78 Outcome::Migrated { entries: report.migrated_entries }
79 };
80 emit_outcome(json, &report.lockfile, outcome, false);
81 Ok(())
82}
83
84#[derive(Debug, Clone, Copy)]
85enum Outcome {
86 NoLockfile,
88 AlreadyMigrated,
90 WouldMigrate,
92 Migrated { entries: usize },
94}
95
96fn emit_outcome(json: bool, lockfile: &Path, outcome: Outcome, dry_run: bool) {
97 if json {
98 let (status, entries) = match outcome {
99 Outcome::NoLockfile => ("no_lockfile", None),
100 Outcome::AlreadyMigrated => ("already_migrated", None),
101 Outcome::WouldMigrate => ("would_migrate", None),
102 Outcome::Migrated { entries } => ("migrated", Some(entries)),
103 };
104 let doc = serde_json::json!({
105 "verb": "migrate-lockfile",
106 "lockfile": lockfile.display().to_string(),
107 "status": status,
108 "entries": entries,
109 "dry_run": dry_run,
110 });
111 if let Ok(s) = serde_json::to_string(&doc) {
112 println!("{s}");
113 }
114 } else {
115 let path = lockfile.display();
116 match outcome {
117 Outcome::NoLockfile => {
118 println!("no lockfile at {path}; nothing to migrate");
119 }
120 Outcome::AlreadyMigrated => {
121 println!("{path}: already on v1.2.0 schema; no-op");
122 }
123 Outcome::WouldMigrate => {
124 println!("{path}: v1.1.x → v1.2.0 (would migrate; --dry-run, no write)");
125 }
126 Outcome::Migrated { entries } => {
127 println!("{path}: migrated {entries} entries v1.1.x → v1.2.0");
128 }
129 }
130 }
131}