vouch_lib/extension/
process.rs

1use anyhow::{format_err, Context, Result};
2
3use super::common;
4
5#[derive(serde::Serialize, serde::Deserialize)]
6pub struct StaticData {
7    pub name: String,
8    pub registry_host_names: Vec<String>,
9}
10
11#[derive(Debug, Clone)]
12pub struct ProcessExtension {
13    process_path_: std::path::PathBuf,
14    name_: String,
15    registry_host_names_: Vec<String>,
16}
17
18impl common::FromProcess for ProcessExtension {
19    fn from_process(
20        process_path: &std::path::PathBuf,
21        extension_config_path: &std::path::PathBuf,
22    ) -> Result<Self>
23    where
24        Self: Sized,
25    {
26        let static_data: StaticData = if extension_config_path.is_file() {
27            let file = std::fs::File::open(&extension_config_path)?;
28            let reader = std::io::BufReader::new(file);
29            serde_yaml::from_reader(reader)?
30        } else {
31            let static_data: Box<StaticData> = run_process(&process_path, &vec!["static-data"])?;
32            let static_data = *static_data;
33
34            let file = std::fs::OpenOptions::new()
35                .write(true)
36                .create(true)
37                .open(&extension_config_path)
38                .context(format!(
39                    "Can't open/create file for writing: {}",
40                    extension_config_path.display()
41                ))?;
42            let writer = std::io::BufWriter::new(file);
43            serde_yaml::to_writer(writer, &static_data)?;
44            static_data
45        };
46
47        Ok(ProcessExtension {
48            process_path_: process_path.clone(),
49            name_: static_data.name,
50            registry_host_names_: static_data.registry_host_names,
51        })
52    }
53}
54
55impl common::Extension for ProcessExtension {
56    fn name(&self) -> String {
57        self.name_.clone()
58    }
59
60    fn registries(&self) -> Vec<String> {
61        self.registry_host_names_.clone()
62    }
63
64    /// Returns a list of local package dependencies specification files.
65    fn identify_local_dependencies(
66        &self,
67        working_directory: &std::path::PathBuf,
68    ) -> Result<Vec<common::DependenciesSpec>> {
69        let working_directory = working_directory.to_str().ok_or(format_err!(
70            "Failed to parse path into string: {}",
71            working_directory.display()
72        ))?;
73        let args = vec!["identify-local-dependencies", working_directory];
74        let output: Box<Vec<common::DependenciesSpec>> = run_process(&self.process_path_, &args)?;
75        Ok(*output)
76    }
77
78    /// Given a package name and version, queries the remote registry for package metadata.
79    fn registries_package_metadata(
80        &self,
81        package_name: &str,
82        package_version: &Option<&str>,
83    ) -> Result<Vec<common::RegistryPackageMetadata>> {
84        let mut args = vec!["registries-package-metadata", package_name];
85        if let Some(package_version) = package_version {
86            args.push(package_version.clone());
87        }
88
89        let output: Box<Vec<common::RegistryPackageMetadata>> =
90            run_process(&self.process_path_, &args)?;
91        Ok(*output)
92    }
93}
94
95fn run_process<'a, T: ?Sized>(process_path: &std::path::PathBuf, args: &Vec<&str>) -> Result<Box<T>>
96where
97    for<'de> T: serde::Deserialize<'de> + 'a,
98{
99    log::debug!(
100        "Executing extensions process call with arguments\n{:?}",
101        args
102    );
103    let process = process_path.to_str().ok_or(format_err!(
104        "Failed to parse string from process path: {}",
105        process_path.display()
106    ))?;
107    let handle = std::process::Command::new(process)
108        .args(args)
109        .stdin(std::process::Stdio::null())
110        .stderr(std::process::Stdio::piped())
111        .stdout(std::process::Stdio::piped())
112        .output()?;
113
114    let stdout = String::from_utf8_lossy(&handle.stdout);
115    let output = serde_json::from_str(&stdout)?;
116    Ok(Box::new(output))
117}