rustic_rs/commands/
merge.rs1use crate::{
4 Application, RUSTIC_APP,
5 repository::{OpenRepo, get_snapots_from_ids},
6 status_err,
7};
8use abscissa_core::{Command, Runnable, Shutdown};
9use anyhow::Result;
10use jiff::Zoned;
11use log::info;
12
13use rustic_core::{SnapshotOptions, last_modified_node, repofile::SnapshotFile};
14
15#[derive(clap::Parser, Default, Command, Debug)]
17pub(super) struct MergeCmd {
18 #[clap(value_name = "ID")]
20 ids: Vec<String>,
21
22 #[clap(long)]
24 json: bool,
25
26 #[clap(long)]
28 delete: bool,
29
30 #[clap(flatten, next_help_heading = "Snapshot options")]
32 snap_opts: SnapshotOptions,
33}
34
35impl Runnable for MergeCmd {
36 fn run(&self) {
37 if let Err(err) = RUSTIC_APP
38 .config()
39 .repository
40 .run_open(|repo| self.inner_run(repo))
41 {
42 status_err!("{}", err);
43 RUSTIC_APP.shutdown(Shutdown::Crash);
44 };
45 }
46}
47
48impl MergeCmd {
49 fn inner_run(&self, repo: OpenRepo) -> Result<()> {
50 let config = RUSTIC_APP.config();
51 let repo = repo.to_indexed_ids()?;
52
53 let snapshots = get_snapots_from_ids(&repo, &self.ids)?;
54
55 if config.global.dry_run {
57 println!("would have modified the following snapshots:\n {snapshots:?}");
58 return Ok(());
59 }
60
61 let snap = SnapshotFile::from_options(&self.snap_opts)?;
62 let snap = repo.merge_snapshots(&snapshots, &last_modified_node, snap)?;
63
64 if self.json {
65 let mut stdout = std::io::stdout();
66 serde_json::to_writer_pretty(&mut stdout, &snap)?;
67 }
68 info!("saved new snapshot as {}.", snap.id);
69
70 if self.delete {
71 let now = Zoned::now();
72 let snap_ids: Vec<_> = snapshots
74 .iter()
75 .filter(|sn| !sn.must_keep(&now))
76 .map(|sn| sn.id)
77 .collect();
78 repo.delete_snapshots(&snap_ids)?;
79 }
80
81 Ok(())
82 }
83}