1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use std::fs;
use clap::{ArgMatches, Command};
use serde_json::json;
use crate::{
cli::CliCommand, config::RawConfig, context::Ctx, error::Result, fs::conf_dirs,
ops::state_version::CURRENT_STATE_VERSION,
};
static LONG_FORCE: &str =
"Force create the files and directories (DANGER: will overwrite existing files)
Using --force is the same as using --overwrite=all";
static LONG_OVERWRITE: &str =
"Overwrite select files or directories (DANGER: will overwrite existing data)
Using --overwrite=all is the same as using --force
Multiple items can be passed as a comma separated list, or by using the argument
multiple times.";
#[derive(Copy, Clone, Debug)]
pub struct SeaplaneInit;
impl SeaplaneInit {
pub fn command() -> Command {
Command::new("init")
.about("Create the Seaplane directory structure at the appropriate locations")
.arg(arg!(--force)
.help("Force create the files and directories (DANGER: will overwrite existing files)")
.long_help(LONG_FORCE))
.arg(arg!(--overwrite =["ITEM"]...)
.help("Overwrite select files or directories (DANGER: will overwrite existing data) (supports comma separated list, or multiple uses)")
.long_help(LONG_OVERWRITE)
.value_parser(["all", "formations", "config"]))
}
}
impl CliCommand for SeaplaneInit {
fn run(&self, ctx: &mut Ctx) -> Result<()> {
cli_debugln!("Creating or using data directory {:?}", ctx.data_dir());
fs::create_dir_all(ctx.data_dir())?;
let conf_dir = &conf_dirs()[0];
cli_debugln!("Creating or using config directory {conf_dir:?}");
fs::create_dir_all(conf_dir)?;
let to_create = &[
(
conf_dir.join("seaplane.toml"),
toml::to_string_pretty(&RawConfig::default()).unwrap(),
"config",
),
(
ctx.state_file(),
json!({ "state_version": CURRENT_STATE_VERSION }).to_string(),
"formations",
),
];
let mut did_create = false;
for (file, empty_bytes, opt) in to_create {
if file.exists() && !(ctx.did_init || ctx.internal_run) {
if ctx.args.force
|| ctx
.args
.overwrite
.iter()
.any(|item| item == opt || item == "all")
{
cli_debugln!(
"overwriting existing file {file:?} due to {}",
if ctx.args.force {
"--force".into()
} else {
format!(
"--overwrite={}",
if ctx.args.overwrite.iter().any(|item| item == "all") {
"all"
} else {
opt
}
)
}
);
} else if ctx.args.overwrite.is_empty() {
cli_debugln!("found existing file {file:?}");
cli_debugln!(
"(hint: use 'seaplane init --overwrite={opt}' to erase and overwrite it)"
);
continue;
}
}
did_create = true;
cli_debugln!("creating file {file:?}");
fs::write(file, empty_bytes)?;
}
if !ctx.internal_run {
if did_create {
cli_println!("Successfully created Seaplane files and directories");
} else {
cli_println!("All Seaplane files and directories already exist");
}
}
Ok(())
}
fn update_ctx(&self, matches: &ArgMatches, ctx: &mut Ctx) -> Result<()> {
ctx.args.force = matches.get_flag("force");
ctx.args.overwrite = matches
.get_many::<String>("overwrite")
.unwrap_or_default()
.map(ToOwned::to_owned)
.collect();
Ok(())
}
}