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 clap::{Parser, Subcommand, ValueHint};

use super::cmds;
use super::model;
use super::path;

#[derive(Clone, Debug, Default, Parser)]
#[command(name = "garden")]
#[command(author, version, about, long_about = None)]
pub struct MainOptions {
    /// Set the color mode
    #[arg(
        long,
        require_equals = true,
        num_args = 0..=1,
        default_value_t = model::ColorMode::Auto,
        default_missing_value = "on",
        value_enum,
    )]
    color: model::ColorMode,

    /// Set the Garden file to use
    #[arg(long, short, value_hint = ValueHint::FilePath)]
    pub config: Option<std::path::PathBuf>,

    /// Change directories before searching for Garden files
    #[arg(long, short = 'C', value_hint = ValueHint::DirPath)]
    chdir: Option<std::path::PathBuf>,

    /// Increase verbosity for a debug category
    #[arg(long, short, action = clap::ArgAction::Append)]
    pub debug: Vec<String>,

    /// Set variables using 'name=value' expressions
    #[arg(long, short = 'D')]
    pub define: Vec<String>,

    /// Set the Garden tree root
    #[arg(long, short, value_hint = ValueHint::DirPath)]
    pub root: Option<std::path::PathBuf>,

    /// Be quiet
    #[arg(short, long)]
    pub quiet: bool,

    /// Increase verbosity level (default: 0)
    #[arg(short, long, action = clap::ArgAction::Count)]
    pub verbose: u8,

    /// Command to run
    #[command(subcommand)]
    pub command: Command,
}

impl MainOptions {
    /// Construct a default set of options
    pub fn new() -> Self {
        Self::default()
    }

    /// Update the initial state to handle chdir() and making arguments absolute.
    pub fn update(&mut self) {
        self.color.update();

        if let Some(config) = &self.config {
            if config.exists() {
                self.config = Some(path::abspath(config));
            }
        }

        if let Some(root) = &self.root {
            self.root = Some(path::abspath(root));
        }

        if let Some(chdir) = &self.chdir {
            if let Err(err) = std::env::set_current_dir(chdir) {
                error!("could not chdir to {:?}: {}", chdir, err);
            }
        }
    }

    /// Return the debug level for the given name.
    pub fn debug_level(&self, name: &str) -> u8 {
        debug_level(&self.debug, name)
    }
}

/// Parse a vector of debug level arguments to count how many have been set
pub fn debug_level(debug: &[String], name: &str) -> u8 {
    debug.iter().filter(|&x| x == name).count() as u8
}

#[derive(Clone, Debug, Subcommand)]
pub enum Command {
    /// Run custom commands over gardens
    Cmd(cmds::cmd::CmdOptions),
    /// Generate shell completions
    Completion(cmds::completion::CompletionOptions),
    /// Custom commands
    #[command(external_subcommand)]
    Custom(Vec<String>),
    /// Evaluate garden expressions
    Eval(cmds::eval::EvalOptions),
    /// Run commands inside garden environments
    Exec(cmds::exec::ExecOptions),
    /// Grow garden worktrees into existence
    Grow(cmds::grow::GrowOptions),
    /// Initialize a "garden.yaml" garden configuration file
    Init(cmds::init::InitOptions),
    /// Query tree status
    Inspect(cmds::inspect::InspectOptions),
    /// List available gardens, groups, trees and commands
    #[command(alias = "ls")]
    List(cmds::list::ListOptions),
    /// Add pre-existing worktrees to a garden configuration file
    Plant(cmds::plant::PlantOptions),
    /// Remove unreferenced Git repositories
    Prune(cmds::prune::PruneOptions),
    /// Open a shell in a garden environment
    #[command(alias = "sh")]
    Shell(cmds::shell::ShellOptions),
}

impl std::default::Default for Command {
    fn default() -> Self {
        Command::Custom(vec![])
    }
}