Skip to main content

dotsec/
cli.rs

1use crate::storage::{SledStorage, Storage};
2use anyhow::Result;
3use clap::{Args, Parser, Subcommand};
4
5#[derive(Debug, Parser)]
6#[command(author, version, about)]
7pub struct Cli {
8    #[command(subcommand)]
9    pub command: Option<Command>,
10}
11
12#[derive(Debug, Subcommand)]
13pub enum Command {
14    /// Store a new secret
15    Put(PutArgs),
16
17    /// Retrieve a secret
18    Get(GetArgs),
19
20    /// List all secrets
21    List,
22
23    /// Delete a secret
24    Delete(DeleteArgs),
25}
26
27#[derive(Debug, Args)]
28pub struct PutArgs {
29    /// Name of the secret to store
30    key: String,
31
32    /// Value of the secret to store
33    value: String, // TODO: should this be a string?
34}
35
36#[derive(Debug, Args)]
37pub struct GetArgs {
38    /// Name of the secret to get
39    key: String,
40}
41
42#[derive(Debug, Args)]
43pub struct DeleteArgs {
44    /// Name of the secret to delete
45    key: String,
46
47    /// Delete must be run with either --dry-run or --force
48    #[command(flatten)]
49    delete_flags: DeleteFlags,
50}
51
52#[derive(Debug, Args)]
53#[group(required = true, multiple = false)]
54struct DeleteFlags {
55    /// Display the secret that would be deleted, without removing
56    #[arg(long, short('n'), default_value_t = true)]
57    dry_run: bool,
58
59    /// Force actual deletion (required in order to delete)
60    #[arg(long, short('f'))]
61    force: bool,
62}
63
64impl Command {
65    pub fn run(&self) -> Result<()> {
66        match self {
67            Command::Put(args) => put(args),
68            Command::Get(args) => get(args),
69            Command::List => list(),
70            Command::Delete(args) => delete(args),
71        }
72    }
73}
74
75const DEV_PATH: &str = "/tmp/sled-dev"; // TODO: replace this with a real path
76
77fn put(args: &PutArgs) -> Result<()> {
78    let storage = SledStorage::new(DEV_PATH)?;
79    storage.put(&args.key, &args.value)
80}
81
82fn get(args: &GetArgs) -> Result<()> {
83    let storage = SledStorage::new(DEV_PATH)?;
84    let result = storage.get(&args.key)?;
85    let output = match result {
86        Some(value) => format!("{value}"),
87        None => String::from("No value found"), // TODO: shouldn't this go to stderr somehow??
88    };
89
90    println!("{output}");
91    Ok(())
92}
93
94fn list() -> Result<()> {
95    let storage = SledStorage::new(DEV_PATH)?;
96    for key in storage.list()? {
97        println!("{key}");
98    }
99    Ok(())
100}
101
102fn delete(args: &DeleteArgs) -> Result<()> {
103    if args.delete_flags.force {
104        let storage = SledStorage::new(DEV_PATH)?;
105        storage.delete(&args.key)?;
106    } else {
107        println!("would delete secret with name {}", args.key);
108    }
109    Ok(())
110}