vouch_lib/extension/
process.rs1use 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 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 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}