Skip to main content

dot/
cli.rs

1use std::path::PathBuf;
2
3use clap::{Parser, Subcommand};
4
5use crate::commands::{AddCommand, Command, InitCommand, RemoveCommand, SyncCommand};
6use crate::error::Result;
7
8#[derive(Parser)]
9#[command(version, about = "A simple dotfiles manager")]
10pub struct Cli {
11    #[command(subcommand)]
12    command: CliCommand,
13}
14
15#[derive(Subcommand)]
16enum CliCommand {
17    /// Initialize a new dot repository
18    Init,
19    /// Track a file by moving it here and creating a symlink
20    Add { path: PathBuf },
21    /// Stop tracking a file and restore it
22    Remove { path: PathBuf },
23    /// Create symlinks for all tracked files
24    Sync,
25}
26
27pub fn run() -> Result<()> {
28    let cli = Cli::parse();
29
30    match cli.command {
31        CliCommand::Init => InitCommand::new().execute(),
32        CliCommand::Add { path } => AddCommand::new(path).execute(),
33        CliCommand::Remove { path } => RemoveCommand::new(path).execute(),
34        CliCommand::Sync => SyncCommand::new().execute(),
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use clap::CommandFactory;
42
43    #[test]
44    fn verify_cli() {
45        Cli::command().debug_assert();
46    }
47
48    #[test]
49    fn parse_init() {
50        let cli = Cli::try_parse_from(["dot", "init"]).unwrap();
51        assert!(matches!(cli.command, CliCommand::Init));
52    }
53
54    #[test]
55    fn parse_add() {
56        let cli = Cli::try_parse_from(["dot", "add", "/path/file"]).unwrap();
57        assert!(
58            matches!(cli.command, CliCommand::Add { path } if path == PathBuf::from("/path/file"))
59        );
60    }
61
62    #[test]
63    fn parse_remove() {
64        let cli = Cli::try_parse_from(["dot", "remove", "myfile"]).unwrap();
65        assert!(
66            matches!(cli.command, CliCommand::Remove { path } if path == PathBuf::from("myfile"))
67        );
68    }
69
70    #[test]
71    fn parse_sync() {
72        let cli = Cli::try_parse_from(["dot", "sync"]).unwrap();
73        assert!(matches!(cli.command, CliCommand::Sync));
74    }
75
76    #[test]
77    fn add_requires_path() {
78        assert!(Cli::try_parse_from(["dot", "add"]).is_err());
79    }
80}