evobench_migrate/
evobench-migrate.rs

1use std::path::PathBuf;
2
3use anyhow::{Result, bail};
4use clap::Parser;
5
6use evobench_tools::{
7    info,
8    run::{
9        config::RunConfigBundle,
10        global_app_state_dir::GlobalAppStateDir,
11        insert_jobs::open_already_inserted,
12        migrate::{migrate_already_inserted, migrate_queue},
13        open_run_queues::open_run_queues,
14    },
15    utillib::get_terminal_width::get_terminal_width,
16    utillib::logging::{LogLevelOpts, set_log_level},
17};
18
19#[derive(clap::Parser, Debug)]
20#[clap(next_line_help = true)]
21#[clap(term_width = get_terminal_width(4))]
22/// Database migration for evobench: update storage format for jobs in
23/// queues. Run this when you're getting deserialisation errors from
24/// `evobench`, or when you know that the data structures have
25/// changed and will cause errors.
26struct Opts {
27    #[clap(flatten)]
28    log_level: LogLevelOpts,
29
30    /// Override the path to the config file (default: the paths
31    /// `~/.evobench.*` where a single one exists where the `*` is
32    /// the suffix for one of the supported config file formats (run
33    /// `config-formats` to get the list), and if those are missing,
34    /// use compiled-in default config values)
35    #[clap(long)]
36    config: Option<PathBuf>,
37
38    /// The subcommand to run. Use `--help` after the sub-command to
39    /// get a list of the allowed options there.
40    #[clap(subcommand)]
41    subcommand: SubCommand,
42}
43
44#[derive(clap::Subcommand, Debug)]
45enum SubCommand {
46    /// Run the migration
47    Run,
48}
49
50fn main() -> Result<()> {
51    let Opts {
52        log_level,
53        config,
54        subcommand,
55    } = Opts::parse();
56
57    set_log_level(log_level.try_into()?);
58
59    let config = config.map(Into::into);
60
61    match subcommand {
62        SubCommand::Run => {
63            let run_config_bundle = RunConfigBundle::load(
64                config,
65                |msg| bail!("can't load config: {msg}"),
66                GlobalAppStateDir::new()?,
67            )?;
68
69            info!("migrating the queues");
70            {
71                let (queues, regenerate_index_files) =
72                    open_run_queues(&run_config_bundle.shareable)?;
73                for queue in queues.all_queues() {
74                    info!("migrating queue {:?}", queue.file_name.as_str());
75                    let n = migrate_queue(queue)?;
76                    info!("migrated {n} items in queue {:?}", queue.file_name.as_str());
77                }
78                regenerate_index_files.run_one();
79            }
80
81            info!("migrating the already_inserted table");
82            let already_inserted =
83                open_already_inserted(&run_config_bundle.shareable.global_app_state_dir)?;
84            let n = migrate_already_inserted(&already_inserted)?;
85            info!("migrated {n} items in the already_inserted table");
86        }
87    }
88
89    Ok(())
90}