Skip to main content

zoi_cli/cmd/install/
args.rs

1use clap::Args;
2use zoi_common::Runnable;
3
4use crate::cli::InstallScope;
5use crate::pkg::plugin::PluginManager;
6
7/// Arguments for the `install` command.
8#[derive(Args, Debug, Clone)]
9pub struct InstallArgs {
10    /// The package source identifier(s).
11    #[arg(
12        value_name = "ALL_SOURCES",
13        help = "Package identifier (e.g. @repo/name, #git@repo/name, path, or \
14                URL)"
15    )]
16    pub sources: Vec<String>,
17
18    /// Install from a git repository (e.g. 'Zillowe/Hello',
19    /// 'gl:Zillowe/Hello')
20    #[arg(long, value_name = "REPO", conflicts_with = "sources")]
21    pub repo: Option<String>,
22
23    /// Force re-installation even if the package is already installed
24    #[arg(long)]
25    pub force: bool,
26
27    /// Accept all optional dependencies
28    #[arg(long)]
29    pub all_optional: bool,
30
31    /// The scope to install the package to
32    #[arg(long, value_enum, conflicts_with_all = &["local", "global"])]
33    pub scope: Option<InstallScope>,
34
35    /// Install packages to the current project (alias for --scope=project)
36    #[arg(long, conflicts_with = "global")]
37    pub local: bool,
38
39    /// Install packages globally for the current user (alias for --scope=user)
40    #[arg(long)]
41    pub global: bool,
42
43    /// Save the package to the project's zoi.yaml
44    #[arg(long)]
45    pub save: bool,
46
47    /// The type of package to build if building from source (e.g. 'source',
48    /// 'pre-compiled').
49    #[arg(long)]
50    pub r#type: Option<String>,
51
52    /// Do not actually perform the installation, just show what would be done
53    #[arg(long)]
54    pub dry_run: bool,
55
56    /// Force building from source even if a pre-compiled archive is available
57    /// in the registry
58    #[arg(long, short = 'b')]
59    pub build: bool,
60
61    /// Enforce zoi.lock exactly (project install only, no lockfile updates)
62    #[arg(long)]
63    pub frozen: bool,
64
65    /// Explain dependency selection and install decisions
66    #[arg(long)]
67    pub explain: bool,
68
69    /// Emit machine-readable install plan JSON
70    #[arg(long)]
71    pub plan_json: bool,
72
73    /// Retry failed downloads this many times (minimum 1)
74    #[arg(long, default_value_t = 3)]
75    pub retry: u32,
76
77    /// Show additional install details (package origins, preflight info)
78    #[arg(long, short)]
79    pub verbose: bool,
80
81    /// Use PURL (Package URL) specification for resolving packages
82    #[arg(long)]
83    pub purl: bool
84}
85
86impl Runnable for InstallArgs {
87    fn run(&self, yes: bool) -> anyhow::Result<()> {
88        let plugin_manager = PluginManager::new()?;
89
90        super::run(
91            &self.sources,
92            self.repo.clone(),
93            self.force,
94            self.all_optional,
95            yes,
96            self.scope,
97            self.local,
98            self.global,
99            self.save,
100            self.r#type.as_deref(),
101            self.dry_run,
102            Some(&plugin_manager),
103            self.build,
104            self.frozen,
105            self.explain,
106            self.plan_json,
107            self.retry,
108            self.verbose,
109            self.purl,
110            None
111        )
112    }
113}