Skip to main content

gh_download/cli/
types.rs

1use std::path::PathBuf;
2
3use clap::{ArgAction, Parser, ValueEnum};
4use serde::Deserialize;
5
6use crate::i18n::Language;
7
8pub const DEFAULT_DOWNLOAD_CONCURRENCY: usize = 4;
9
10fn parse_concurrency(value: &str) -> Result<usize, String> {
11    let parsed = value
12        .parse::<usize>()
13        .map_err(|_| "concurrency must be a positive integer".to_string())?;
14    if parsed == 0 {
15        return Err("concurrency must be at least 1".to_string());
16    }
17    Ok(parsed)
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum, Default, Deserialize)]
21#[serde(rename_all = "lowercase")]
22pub enum PrefixProxyMode {
23    #[default]
24    Direct,
25    Fallback,
26    Prefer,
27}
28
29impl PrefixProxyMode {
30    pub fn as_str(self) -> &'static str {
31        match self {
32            Self::Direct => "direct",
33            Self::Fallback => "fallback",
34            Self::Prefer => "prefer",
35        }
36    }
37}
38
39#[derive(Debug, Parser, Clone)]
40#[command(name = "gh-download", version, long_about = None)]
41pub(crate) struct ParsedCli {
42    #[arg()]
43    pub repo: String,
44
45    #[arg()]
46    pub remote_path: String,
47
48    #[arg()]
49    pub local_target: PathBuf,
50
51    #[arg(long, value_name = "PATH")]
52    pub config: Option<PathBuf>,
53
54    #[arg(long = "ref", value_name = "REF")]
55    pub git_ref: Option<String>,
56
57    #[arg(long, value_name = "TOKEN")]
58    pub token: Option<String>,
59
60    #[arg(long, value_name = "URL")]
61    pub api_base: Option<String>,
62
63    #[arg(long, value_name = "URL")]
64    pub proxy_base: Option<String>,
65
66    #[arg(long = "prefix-mode", value_enum, value_name = "MODE")]
67    pub prefix_mode: Option<PrefixProxyMode>,
68
69    #[arg(
70        short = 'c',
71        long,
72        value_name = "N",
73        value_parser = parse_concurrency
74    )]
75    pub concurrency: Option<usize>,
76
77    #[arg(long = "lang", value_enum, value_name = "LANG")]
78    pub language: Option<Language>,
79
80    #[arg(long, action = ArgAction::SetTrue)]
81    pub overwrite: bool,
82
83    #[arg(long, action = ArgAction::SetTrue)]
84    pub json: bool,
85
86    #[arg(long, action = ArgAction::SetTrue)]
87    pub debug: bool,
88
89    #[arg(long, action = ArgAction::SetTrue)]
90    pub no_color: bool,
91}
92
93#[derive(Debug, Clone, PartialEq, Eq)]
94pub struct CliInvocation {
95    pub cli: Cli,
96    pub config_path: Option<PathBuf>,
97    pub explicit_concurrency: Option<usize>,
98}
99
100#[derive(Debug, Parser, Clone, PartialEq, Eq)]
101#[command(name = "gh-download", version, long_about = None)]
102pub struct Cli {
103    #[arg()]
104    pub repo: String,
105
106    #[arg()]
107    pub remote_path: String,
108
109    #[arg()]
110    pub local_target: PathBuf,
111
112    #[arg(long = "ref", value_name = "REF")]
113    pub git_ref: Option<String>,
114
115    #[arg(long, value_name = "TOKEN")]
116    pub token: Option<String>,
117
118    #[arg(long, value_name = "URL")]
119    pub api_base: Option<String>,
120
121    #[arg(long, value_name = "URL")]
122    pub proxy_base: Option<String>,
123
124    #[arg(long = "prefix-mode", value_enum, value_name = "MODE")]
125    pub prefix_mode: Option<PrefixProxyMode>,
126
127    #[arg(
128        short = 'c',
129        long,
130        value_name = "N",
131        default_value_t = DEFAULT_DOWNLOAD_CONCURRENCY,
132        value_parser = parse_concurrency
133    )]
134    pub concurrency: usize,
135
136    #[arg(long = "lang", value_enum, value_name = "LANG")]
137    pub language: Option<Language>,
138
139    #[arg(long, action = ArgAction::SetTrue)]
140    pub overwrite: bool,
141
142    #[arg(long, action = ArgAction::SetTrue)]
143    pub json: bool,
144
145    #[arg(long, action = ArgAction::SetTrue)]
146    pub debug: bool,
147
148    #[arg(long, action = ArgAction::SetTrue)]
149    pub no_color: bool,
150}
151
152#[derive(Debug, Clone, PartialEq, Eq)]
153pub struct ResolvedOptions {
154    pub repo: String,
155    pub remote_path: String,
156    pub local_target: PathBuf,
157    pub git_ref: Option<String>,
158    pub token: Option<String>,
159    pub api_base: String,
160    pub proxy_base: String,
161    pub prefix_mode: PrefixProxyMode,
162    pub concurrency: usize,
163    pub language: Language,
164    pub overwrite: bool,
165    pub json: bool,
166    pub debug: bool,
167    pub no_color: bool,
168}
169
170impl From<ParsedCli> for CliInvocation {
171    fn from(value: ParsedCli) -> Self {
172        let explicit_concurrency = value.concurrency;
173        let cli = Cli {
174            repo: value.repo,
175            remote_path: value.remote_path,
176            local_target: value.local_target,
177            git_ref: value.git_ref,
178            token: value.token,
179            api_base: value.api_base,
180            proxy_base: value.proxy_base,
181            prefix_mode: value.prefix_mode,
182            concurrency: explicit_concurrency.unwrap_or(DEFAULT_DOWNLOAD_CONCURRENCY),
183            language: value.language,
184            overwrite: value.overwrite,
185            json: value.json,
186            debug: value.debug,
187            no_color: value.no_color,
188        };
189
190        Self {
191            cli,
192            config_path: value.config,
193            explicit_concurrency,
194        }
195    }
196}