alpm_srcinfo/
commands.rs

1//! Functions called from the binary.
2use std::{
3    io::{self, IsTerminal},
4    path::{Path, PathBuf},
5};
6
7use alpm_common::MetadataFile;
8use alpm_types::Architecture;
9
10use crate::{
11    SourceInfo,
12    SourceInfoSchema,
13    SourceInfoV1,
14    cli::{PackagesOutputFormat, SourceInfoOutputFormat},
15    error::Error,
16    source_info::v1::merged::MergedPackage,
17};
18
19/// Take a [PKGBUILD], create [SRCINFO] data from it and print it.
20///
21/// # Errors
22///
23/// Returns an error if
24///
25/// - running the [`alpm-pkgbuild-bridge`] script fails,
26/// - or parsing the output of the ``alpm-pkgbuild-bridge`] script fails.
27///
28/// [PKGBUILD]: https://man.archlinux.org/man/PKGBUILD.5
29/// [SRCINFO]: https://alpm.archlinux.page/specifications/SRCINFO.5.html
30/// [`alpm-pkgbuild-bridge`]: https://gitlab.archlinux.org/archlinux/alpm/alpm-pkgbuild-bridge
31pub fn create(
32    pkgbuild_path: &Path,
33    output_format: SourceInfoOutputFormat,
34    pretty: bool,
35) -> Result<(), Error> {
36    let source_info = SourceInfoV1::from_pkgbuild(pkgbuild_path)?;
37
38    match output_format {
39        SourceInfoOutputFormat::Json => {
40            let json = if pretty {
41                serde_json::to_string_pretty(&source_info)?
42            } else {
43                serde_json::to_string(&source_info)?
44            };
45            println!("{json}");
46        }
47        SourceInfoOutputFormat::Srcinfo => {
48            print!("{}", source_info.as_srcinfo())
49        }
50    }
51
52    Ok(())
53}
54
55/// Validates a SRCINFO file from a path or stdin.
56///
57/// Wraps the [`parse`] function and allows to ensure that no errors occurred during parsing.
58pub fn validate(file: Option<&PathBuf>, schema: Option<SourceInfoSchema>) -> Result<(), Error> {
59    let _result = parse(file, schema)?;
60
61    Ok(())
62}
63
64/// Parses a SRCINFO file from a path or stdin and outputs it in the specified format on stdout.
65///
66/// # Errors
67///
68/// Returns an error if the input can not be parsed and validated, or if the output can not be
69/// formatted in the selected output format.
70pub fn format_source_info(
71    file: Option<&PathBuf>,
72    schema: Option<SourceInfoSchema>,
73    output_format: SourceInfoOutputFormat,
74    pretty: bool,
75) -> Result<(), Error> {
76    let srcinfo = parse(file, schema)?;
77    let SourceInfo::V1(source_info) = srcinfo;
78
79    match output_format {
80        SourceInfoOutputFormat::Json => {
81            let json = if pretty {
82                serde_json::to_string_pretty(&source_info)?
83            } else {
84                serde_json::to_string(&source_info)?
85            };
86            println!("{json}");
87        }
88        SourceInfoOutputFormat::Srcinfo => {
89            println!("{}", source_info.as_srcinfo())
90        }
91    }
92
93    Ok(())
94}
95
96/// Parses a SRCINFO file from a path or stdin and outputs all info grouped by packages for a given
97/// architecture in the specified format on stdout.
98///
99/// # Errors
100///
101/// Returns an error if the input can not be parsed and validated, or if the output can not be
102/// formatted in the selected output format.
103pub fn format_packages(
104    file: Option<&PathBuf>,
105    schema: Option<SourceInfoSchema>,
106    output_format: PackagesOutputFormat,
107    architecture: Architecture,
108    pretty: bool,
109) -> Result<(), Error> {
110    let srcinfo = parse(file, schema)?;
111    let SourceInfo::V1(source_info) = srcinfo;
112
113    let packages: Vec<MergedPackage> = source_info
114        .packages_for_architecture(architecture)
115        .collect();
116
117    match output_format {
118        PackagesOutputFormat::Json => {
119            let json = if pretty {
120                serde_json::to_string_pretty(&packages)?
121            } else {
122                serde_json::to_string(&packages)?
123            };
124            println!("{json}");
125        }
126    }
127
128    Ok(())
129}
130
131/// Parses and interprets a SRCINFO file from a path or stdin.
132///
133/// ## Note
134///
135/// If a command is piped to this process, the input is read from stdin.
136/// See [`IsTerminal`] for more information about how terminal detection works.
137///
138/// [`IsTerminal`]: https://doc.rust-lang.org/stable/std/io/trait.IsTerminal.html
139///
140/// # Errors
141///
142/// Returns an error if the input can not be parsed and validated, or if the output can not be
143/// formatted in the selected output format.
144///
145/// Furthermore, returns an error array with potentially un/-recoverable (linting-)errors, which
146/// needs to be explicitly handled by the caller.
147pub fn parse(
148    file: Option<&PathBuf>,
149    schema: Option<SourceInfoSchema>,
150) -> Result<SourceInfo, Error> {
151    if let Some(file) = file {
152        SourceInfo::from_file_with_schema(file, schema)
153    } else if !io::stdin().is_terminal() {
154        SourceInfo::from_stdin_with_schema(schema)
155    } else {
156        Err(Error::NoInputFile)
157    }
158}