cli_engine/
config_commands.rs1use clap::Arg;
14use serde_json::{Value, json};
15
16use crate::config::{ConfigFile, config_file_path};
17use crate::{CommandResult, CommandSpec, GroupSpec, RuntimeCommandSpec, RuntimeGroupSpec, Tier};
18
19#[must_use]
21pub fn config_command_group() -> RuntimeGroupSpec {
22 RuntimeGroupSpec::new(GroupSpec::new(
23 "config",
24 "Read and write the CLI config file",
25 ))
26 .with_command(RuntimeCommandSpec::new_with_context(
27 CommandSpec::new("path", "Print the config file path")
28 .with_system("config")
29 .no_auth(true),
30 async |context| {
31 let path =
32 config_file_path(&context.middleware.app_id).map(|p| p.display().to_string());
33 Ok(CommandResult::new(json!({ "path": path })))
34 },
35 ))
36 .with_command(RuntimeCommandSpec::new_with_context(
37 CommandSpec::new("get", "Print a config value by dotted key")
38 .with_system("config")
39 .no_auth(true)
40 .with_arg(
41 Arg::new("key")
42 .value_name("KEY")
43 .required(true)
44 .help("Dotted key, e.g. credentials.store or deploy.region"),
45 ),
46 async |context| {
47 let key = string_arg(&context.args, "key");
48 let value = context.config().get(&key);
49 Ok(CommandResult::new(json!({ "key": key, "value": value })))
50 },
51 ))
52 .with_command(RuntimeCommandSpec::new_with_context(
53 CommandSpec::new("set", "Set a config value and save")
54 .with_system("config")
55 .with_tier(Tier::Mutate)
56 .mutates(true)
57 .no_auth(true)
58 .with_arg(
59 Arg::new("key")
60 .value_name("KEY")
61 .required(true)
62 .help("Dotted key, e.g. credentials.store or deploy.region"),
63 )
64 .with_arg(Arg::new("value").value_name("VALUE").required(true).help(
65 "Value to set. Type is inferred: \"true\"/\"false\" → bool, \
66 digits → int, float syntax (\"1.5\", \"1e5\") → float, \
67 everything else → string.",
68 )),
69 async |context| {
70 let key = string_arg(&context.args, "key");
71 let value = string_arg(&context.args, "value");
72 let mut config = ConfigFile::load(&context.middleware.app_id);
78 config.set(&key, &value)?;
79 config.save()?;
80 let path = config.path().map(|p| p.display().to_string());
81 Ok(CommandResult::new(
82 json!({ "key": key, "value": value, "path": path }),
83 ))
84 },
85 ))
86 .with_command(RuntimeCommandSpec::new_with_context(
87 CommandSpec::new("list", "Print the full config file contents")
88 .with_system("config")
89 .no_auth(true),
90 async |context| {
91 let path = context.config().path().map(|p| p.display().to_string());
92 Ok(CommandResult::new(json!({
93 "path": path,
94 "contents": context.config().to_toml_string(),
95 })))
96 },
97 ))
98}
99
100fn string_arg(args: &serde_json::Map<String, Value>, name: &str) -> String {
102 args.get(name)
103 .and_then(Value::as_str)
104 .unwrap_or_default()
105 .to_owned()
106}