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