alpm_pkginfo/cli.rs
1//! Command-line argument handling for `alpm-pkginfo`.
2
3use std::{
4 fmt::{Display, Formatter},
5 path::PathBuf,
6 str::FromStr,
7};
8
9use alpm_types::{
10 Architecture,
11 Backup,
12 BuildDate,
13 ExtraData,
14 FullVersion,
15 Group,
16 InstalledSize,
17 License,
18 Name,
19 OptionalDependency,
20 PackageDescription,
21 PackageRelation,
22 Packager,
23 Url,
24};
25use clap::{Args, Parser, Subcommand, ValueEnum};
26use strum::Display;
27
28use crate::{Error, PackageInfoSchema, RelationOrSoname};
29
30/// A type wrapping a PathBuf with a default value
31///
32/// This type is used in circumstances where an output file is required that defaults to
33/// ".PKGINFO"
34#[derive(Clone, Debug)]
35pub struct OutputFile(pub PathBuf);
36
37impl Default for OutputFile {
38 fn default() -> Self {
39 OutputFile(PathBuf::from(".PKGINFO"))
40 }
41}
42
43impl Display for OutputFile {
44 fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
45 write!(fmt, "{}", self.0.display())
46 }
47}
48
49impl FromStr for OutputFile {
50 type Err = Error;
51
52 fn from_str(s: &str) -> Result<Self, Self::Err> {
53 Ok(OutputFile(PathBuf::from(s)))
54 }
55}
56
57/// The command-line interface handling for `alpm-pkginfo`.
58#[derive(Clone, Debug, Parser)]
59#[command(about, author, name = "alpm-pkginfo", version)]
60pub struct Cli {
61 /// The `alpm-pkginfo` commands.
62 #[command(subcommand)]
63 pub command: Command,
64}
65
66/// The `alpm-pkginfo` commands.
67#[allow(clippy::large_enum_variant)]
68#[derive(Clone, Debug, Subcommand)]
69pub enum Command {
70 #[command()]
71 /// Create a PKGINFO file according to a schema
72 ///
73 /// If the input can be validated according to the schema, the program writes a valid PKGINFO
74 /// file and exits with no output and a return code of 0. If the input can not be validated
75 /// according to the schema, an error is emitted on stderr and the program exits with a
76 /// non-zero exit code.
77 Create {
78 /// The `create` command.
79 #[command(subcommand)]
80 command: CreateCommand,
81 },
82 #[command()]
83 /// Validate a PKGINFO file
84 ///
85 /// Validate a PKGINFO file according to a schema.
86 /// If the file can be validated, the program exits with no output and a return code of 0.
87 /// If the file can not be validated, an error is emitted on stderr and the program exits with
88 /// a non-zero exit code.
89 Validate {
90 /// An optional input file path to read from
91 ///
92 /// If no file is specified, stdin is read from and expected to contain PKGINFO data to
93 /// validate.
94 #[arg(value_name = "FILE")]
95 file: Option<PathBuf>,
96
97 /// Provide the PKGINFO schema version to use.
98 ///
99 /// If no schema version is provided, it will be deduced from the file itself.
100 #[arg(short, long, value_name = "VERSION")]
101 schema: Option<PackageInfoSchema>,
102 },
103
104 /// Parse a PKGINFO file and output it in a different file format
105 ///
106 /// If the input can be validated according to a known schema, the program writes the PKGINFO
107 /// data to stdout in a different file format (optionally, a file path to write to may be
108 /// provided) and exits with a return code of 0. Currently only JSON is supported as output
109 /// format. If the input can not be validated according to a known schema, an error is
110 /// emitted on stderr and the program exits with a non-zero exit code.
111 #[command()]
112 Format {
113 /// An optional input file path to read from
114 ///
115 /// If no file path is specified, stdin is read from and expected to contain PKGINFO data
116 /// to format.
117 #[arg(value_name = "FILE")]
118 file: Option<PathBuf>,
119
120 /// Provide the PKGINFO schema version to use.
121 ///
122 /// If no schema version is provided, it will be deduced from the file itself.
123 #[arg(short, long, value_name = "VERSION")]
124 schema: Option<PackageInfoSchema>,
125
126 /// The output format to use
127 ///
128 /// Currently only "json" (the default) is supported
129 #[arg(
130 short,
131 long,
132 value_name = "OUTPUT_FORMAT",
133 default_value_t = OutputFormat::Json
134 )]
135 output_format: OutputFormat,
136
137 /// Pretty-print the output
138 ///
139 /// Has no effect if the output format can not be pretty printed.
140 #[arg(short, long)]
141 pretty: bool,
142 },
143}
144
145/// Arguments for creating a PKGINFO file according to the format version 1 schema
146///
147/// This struct is defined separately for reusing it for v1 and v2 because both share
148/// a set of overlapping fields.
149#[derive(Args, Clone, Debug)]
150pub struct V1CreateArgs {
151 /// The pkgname to use in the PKGINFO
152 ///
153 /// The pkgname must follow the alpm-package-name format (see `man 7 alpm-package-name`).
154 #[arg(env = "PKGINFO_PKGNAME", long, value_name = "PKGNAME")]
155 pub pkgname: Name,
156
157 /// The pkgbase to use in the PKGINFO
158 ///
159 /// The pkgbase must follow the alpm-package-name format (see `man 7 alpm-package-name`).
160 #[arg(env = "PKGINFO_PKGBASE", long, value_name = "PKGBASE")]
161 pub pkgbase: Name,
162
163 /// The pkgver to use in the PKGINFO
164 ///
165 /// The pkgver value must follow the alpm-pkgver format (see `man 7 alpm-pkgver`).
166 #[arg(env = "PKGINFO_PKGVER", long, value_name = "PKGVER")]
167 pub pkgver: FullVersion,
168
169 /// The package description to use in the PKGINFO
170 ///
171 /// The value must follow the format described in the PKGINFO format (see `man 5 PKGINFO`).
172 #[arg(env = "PKGINFO_PKGDESC", long, value_name = "PKGDESC")]
173 pub pkgdesc: PackageDescription,
174
175 /// Provide a url
176 #[arg(env = "PKGINFO_URL", long, value_name = "URL")]
177 pub url: Url,
178
179 /// Provide a builddate
180 #[arg(env = "PKGINFO_BUILDDATE", long, value_name = "BUILDDATE")]
181 pub builddate: BuildDate,
182
183 /// Provide a packager
184 #[arg(env = "PKGINFO_PACKAGER", long, value_name = "PACKAGER")]
185 pub packager: Packager,
186
187 /// Provide a size
188 #[arg(env = "PKGINFO_SIZE", long, value_name = "SIZE")]
189 pub size: InstalledSize,
190
191 /// Provide a architecture
192 #[arg(env = "PKGINFO_ARCH", long, value_name = "ARCH")]
193 pub arch: Architecture,
194
195 /// Provide one or more licenses
196 #[arg(
197 env = "PKGINFO_LICENSE",
198 value_delimiter = ' ',
199 long,
200 value_name = "LICENSE"
201 )]
202 pub license: Vec<License>,
203
204 /// Provide one or more replaces
205 #[arg(
206 env = "PKGINFO_REPLACES",
207 value_delimiter = ' ',
208 long,
209 value_name = "REPLACES"
210 )]
211 pub replaces: Vec<PackageRelation>,
212
213 /// Provide one or more groups
214 #[arg(
215 env = "PKGINFO_GROUP",
216 value_delimiter = ' ',
217 long,
218 value_name = "GROUP"
219 )]
220 pub group: Vec<Group>,
221
222 /// Provide one or more conflicts
223 #[arg(
224 env = "PKGINFO_CONFLICT",
225 value_delimiter = ' ',
226 long,
227 value_name = "CONFLICT"
228 )]
229 pub conflict: Vec<PackageRelation>,
230
231 /// Provide one or more provides
232 #[arg(
233 env = "PKGINFO_PROVIDES",
234 value_delimiter = ' ',
235 long,
236 value_name = "PROVIDES"
237 )]
238 pub provides: Vec<RelationOrSoname>,
239
240 /// Provide one or more backups
241 #[arg(
242 env = "PKGINFO_BACKUP",
243 value_delimiter = ' ',
244 long,
245 value_name = "BACKUP"
246 )]
247 pub backup: Vec<Backup>,
248
249 /// Provide one or more depends
250 #[arg(
251 env = "PKGINFO_DEPEND",
252 value_delimiter = ' ',
253 long,
254 value_name = "DEPEND"
255 )]
256 pub depend: Vec<RelationOrSoname>,
257
258 /// Provide one or more optdepend
259 #[arg(
260 env = "PKGINFO_OPTDEPEND",
261 value_delimiter = ',',
262 long,
263 value_name = "OPTDEPEND"
264 )]
265 pub optdepend: Vec<OptionalDependency>,
266
267 /// Provide one or more makedepend
268 #[arg(
269 env = "PKGINFO_MAKEDEPEND",
270 value_delimiter = ' ',
271 long,
272 value_name = "MAKEDEPEND"
273 )]
274 pub makedepend: Vec<PackageRelation>,
275
276 /// Provide one or more checkdepend
277 #[arg(
278 env = "PKGINFO_CHECKDEPEND",
279 value_delimiter = ' ',
280 long,
281 value_name = "CHECKDEPEND"
282 )]
283 pub checkdepend: Vec<PackageRelation>,
284
285 /// An optional custom file to write to
286 #[arg(default_value_t = OutputFile::default(), env = "PKGINFO_OUTPUT_FILE", value_name = "FILE")]
287 pub output: OutputFile,
288}
289
290/// Create an PKGINFO file according to a schema
291///
292/// If the input can be validated according to the schema, the program exits with no output and
293/// a return code of 0. If the input can not be validated according to the schema, an error
294/// is emitted on stderr and the program exits with a non-zero exit code.
295#[derive(Clone, Debug, Subcommand)]
296pub enum CreateCommand {
297 /// Create a PKGINFO version 1 file
298 V1 {
299 /// Arguments for the `create v1` command.
300 #[command(flatten)]
301 args: V1CreateArgs,
302 },
303 /// Create a PKGINFO version 2 file
304 V2 {
305 /// Arguments for the `create v2` command.
306 #[command(flatten)]
307 args: V1CreateArgs,
308
309 /// Provide one or more Xdata
310 #[arg(env = "PKGINFO_XDATA", long, value_name = "XDATA")]
311 xdata: Vec<ExtraData>,
312 },
313}
314
315/// Output format for the format command
316#[derive(Clone, Debug, Default, Display, ValueEnum)]
317#[non_exhaustive]
318pub enum OutputFormat {
319 /// The JSON output format.
320 #[default]
321 #[strum(to_string = "json")]
322 Json,
323}