Skip to main content

rustic_rs/commands/
rewrite.rs

1//! `rewrite` subcommand
2
3use crate::{
4    Application, RUSTIC_APP,
5    commands::snapshots::print_snapshots,
6    repository::{IndexedRepo, OpenRepo, get_snapots_from_ids},
7    status_err,
8};
9
10use abscissa_core::{Command, Runnable, Shutdown};
11use anyhow::Result;
12use log::info;
13
14use rustic_core::{
15    Excludes, NodeModification, RewriteOptions, RewriteTreesOptions, StringList,
16    repofile::{SnapshotFile, SnapshotModification},
17};
18
19/// `rewrite` subcommand
20#[derive(clap::Parser, Command, Debug, Default)]
21pub(crate) struct RewriteCmd {
22    /// Snapshots to rewrite. If none is given, use filter to filter from all snapshots.
23    ///
24    /// Snapshot can be identified the following ways: "01a2b3c4" or "latest" or "latest~N" (N >= 0)
25    #[clap(value_name = "ID")]
26    pub ids: Vec<String>,
27
28    /// remove original snapshots
29    #[clap(long)]
30    pub forget: bool,
31
32    /// Tags to add to rewritten snapshots [default: "rewrite" if original snapshots are not removed]
33    #[clap(long, value_name = "TAG[,TAG,..]")]
34    pub tags_rewritten: Option<StringList>,
35
36    #[clap(flatten, next_help_heading = "Snapshot options")]
37    pub modification: SnapshotModification,
38
39    /// treat all trees as changed (i.e. serialize all and rebuild summary)
40    #[clap(long, help_heading = "Tree rewrite options")]
41    pub all_trees: bool,
42
43    #[clap(flatten, next_help_heading = "Exclude options")]
44    pub excludes: Excludes,
45
46    #[clap(flatten, next_help_heading = "Node modification options")]
47    pub node_modification: NodeModification,
48}
49
50impl Runnable for RewriteCmd {
51    fn run(&self) {
52        let repo = &RUSTIC_APP.config().repository;
53
54        if let Err(err) =
55            if self.excludes.is_empty() && self.node_modification.is_empty() && !self.all_trees {
56                repo.run_open(|repo| self.inner_run_open(repo))
57            } else {
58                repo.run_indexed(|repo| self.inner_run_indexed(repo))
59            }
60        {
61            status_err!("{}", err);
62            RUSTIC_APP.shutdown(Shutdown::Crash);
63        }
64    }
65}
66
67impl RewriteCmd {
68    fn opts(&self) -> RewriteOptions {
69        let config = RUSTIC_APP.config();
70        RewriteOptions::default()
71            .forget(self.forget)
72            .tags_rewritten(self.tags_rewritten.clone())
73            .modification(self.modification.clone())
74            .dry_run(config.global.dry_run)
75    }
76
77    fn inner_run_open(&self, repo: OpenRepo) -> Result<()> {
78        let snapshots = get_snapots_from_ids(&repo, &self.ids)?;
79
80        let snaps = repo.rewrite_snapshots(snapshots, &self.opts())?;
81
82        self.output(snaps);
83
84        Ok(())
85    }
86
87    fn inner_run_indexed(&self, repo: IndexedRepo) -> Result<()> {
88        let snapshots = get_snapots_from_ids(&repo, &self.ids)?;
89        let tree_opts = RewriteTreesOptions::default()
90            .all_trees(self.all_trees)
91            .excludes(self.excludes.clone())
92            .node_modification(self.node_modification.clone());
93
94        let snaps = repo.rewrite_snapshots_and_trees(snapshots, &self.opts(), &tree_opts)?;
95
96        self.output(snaps);
97
98        Ok(())
99    }
100
101    fn output(&self, snaps: Vec<SnapshotFile>) {
102        let config = RUSTIC_APP.config();
103        if config.global.dry_run {
104            println!("Would have rewritten the following snapshots:");
105            print_snapshots(snaps, false, true);
106        } else {
107            info!("{} snapshots have been rewritten", snaps.len());
108        }
109    }
110}