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    /// 'gh: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, conflicts_with = "deps_only")]
45    pub save: bool,
46
47    /// Install only the dependencies of the given packages, not the packages
48    /// themselves
49    #[arg(long, conflicts_with_all = &["save", "build_deps_only"])]
50    pub deps_only: bool,
51
52    /// Install only the build dependencies of the given packages
53    #[arg(long, conflicts_with_all = &["save", "deps_only"])]
54    pub build_deps_only: bool,
55
56    /// The type of package to build if building from source (e.g. 'source',
57    /// 'pre-compiled').
58    #[arg(long)]
59    pub r#type: Option<String>,
60
61    /// Do not actually perform the installation, just show what would be done
62    #[arg(long)]
63    pub dry_run: bool,
64
65    /// Force building from source even if a pre-compiled archive is available
66    /// in the registry
67    #[arg(long, short = 'b')]
68    pub build: bool,
69
70    /// Enforce zoi.lock exactly (project install only, no lockfile updates)
71    #[arg(long)]
72    pub frozen: bool,
73
74    /// Explain dependency selection and install decisions
75    #[arg(long)]
76    pub explain: bool,
77
78    /// Emit machine-readable install plan JSON
79    #[arg(long, requires = "dry_run")]
80    pub plan_json: bool,
81
82    /// Retry failed downloads this many times (minimum 1)
83    #[arg(long, default_value_t = 3)]
84    pub retry: u32,
85
86    /// Show additional install details (package origins, preflight info)
87    #[arg(long, short)]
88    pub verbose: bool,
89
90    /// Use PURL (Package URL) specification for resolving packages
91    #[arg(long)]
92    pub purl: bool
93}
94
95impl Runnable for InstallArgs {
96    fn run(&self, yes: bool) -> anyhow::Result<()> {
97        let plugin_manager = PluginManager::new()?;
98
99        super::run(
100            &self.sources,
101            self.repo.clone(),
102            self.force,
103            self.all_optional,
104            yes,
105            self.scope,
106            self.local,
107            self.global,
108            self.save,
109            self.deps_only,
110            self.build_deps_only,
111            self.r#type.as_deref(),
112            self.dry_run,
113            Some(&plugin_manager),
114            self.build,
115            self.frozen,
116            self.explain,
117            self.plan_json,
118            self.retry,
119            self.verbose,
120            self.purl,
121            None
122        )
123    }
124}