openfare_lib/extension/
process.rs1use anyhow::{format_err, Context, Result};
2
3use super::commands;
4use super::common;
5
6#[derive(Debug, serde::Serialize, serde::Deserialize)]
7pub struct StaticData {
8 pub name: String,
9 pub registry_host_names: Vec<String>,
10 pub version: String,
11}
12
13#[derive(Debug, Clone)]
14pub struct ProcessExtension {
15 process_path_: std::path::PathBuf,
16 name_: String,
17 registry_host_names_: Vec<String>,
18 version_: String,
19}
20
21impl common::FromProcess for ProcessExtension {
22 fn from_process(
23 process_path: &std::path::PathBuf,
24 extension_config_path: &std::path::PathBuf,
25 ) -> Result<Self>
26 where
27 Self: Sized,
28 {
29 let static_data: StaticData = if extension_config_path.is_file() {
30 let file = std::fs::File::open(&extension_config_path)?;
31 let reader = std::io::BufReader::new(file);
32 serde_json::from_reader(reader)?
33 } else {
34 let static_data: Box<StaticData> = run_process(&process_path, &vec!["static-data"])?;
35 let static_data = *static_data;
36
37 let file = std::fs::OpenOptions::new()
38 .write(true)
39 .create(true)
40 .open(&extension_config_path)
41 .context(format!(
42 "Can't open/create file for writing: {}",
43 extension_config_path.display()
44 ))?;
45 let writer = std::io::BufWriter::new(file);
46 serde_json::to_writer(writer, &static_data)?;
47 static_data
48 };
49
50 Ok(ProcessExtension {
51 process_path_: process_path.clone(),
52 name_: static_data.name,
53 registry_host_names_: static_data.registry_host_names,
54 version_: static_data.version,
55 })
56 }
57}
58
59impl common::Extension for ProcessExtension {
60 fn name(&self) -> String {
61 self.name_.clone()
62 }
63
64 fn registries(&self) -> Vec<String> {
65 self.registry_host_names_.clone()
66 }
67
68 fn version(&self) -> String {
69 self.version_.clone()
70 }
71
72 fn package_dependencies_locks(
73 &self,
74 package_name: &str,
75 package_version: &Option<&str>,
76 extension_args: &Vec<String>,
77 ) -> Result<commands::package_dependencies_locks::PackageDependenciesLocks> {
78 let mut args = vec![
79 super::commands::package_dependencies_locks::COMMAND_NAME,
80 "--package-name",
81 package_name,
82 ];
83 if let Some(package_version) = package_version {
84 args.push("--package-version");
85 args.push(package_version);
86 }
87 for extension_arg in extension_args {
88 args.push("--extension-args");
89 args.push(extension_arg);
90 }
91 let output: Box<commands::package_dependencies_locks::PackageDependenciesLocks> =
92 run_process(&self.process_path_, &args)?;
93 Ok(*output)
94 }
95
96 fn project_dependencies_locks(
98 &self,
99 working_directory: &std::path::PathBuf,
100 extension_args: &Vec<String>,
101 ) -> Result<commands::project_dependencies_locks::ProjectDependenciesLocks> {
102 let working_directory = working_directory.to_str().ok_or(format_err!(
103 "Failed to parse path into string: {}",
104 working_directory.display()
105 ))?;
106 let mut args = vec![
107 super::commands::project_dependencies_locks::COMMAND_NAME,
108 "--working-directory",
109 working_directory,
110 ];
111 for extension_arg in extension_args {
112 args.push("--extension-args");
113 args.push(extension_arg);
114 }
115
116 let output: Box<commands::project_dependencies_locks::ProjectDependenciesLocks> =
117 run_process(&self.process_path_, &args)?;
118 Ok(*output)
119 }
120}
121
122#[derive(Debug, Clone, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
123pub struct ProcessResult<T> {
124 pub ok: Option<T>,
125 pub err: Option<String>,
126}
127
128fn run_process<'a, T: ?Sized>(process_path: &std::path::PathBuf, args: &Vec<&str>) -> Result<Box<T>>
129where
130 for<'de> T: serde::Deserialize<'de> + 'a,
131{
132 log::debug!(
133 "Executing extensions process call with arguments\n{:?}",
134 args
135 );
136 let process = process_path.to_str().ok_or(format_err!(
137 "Failed to parse string from process path: {}",
138 process_path.display()
139 ))?;
140 let handle = std::process::Command::new(process)
141 .args(args)
142 .stdin(std::process::Stdio::null())
143 .stderr(std::process::Stdio::piped())
144 .stdout(std::process::Stdio::piped())
145 .output()?;
146
147 let stdout = String::from_utf8_lossy(&handle.stdout);
148 let stdout = stdout.to_string();
149
150 let result = hex::decode(&stdout)?.clone();
151 let process_result: ProcessResult<T> =
152 bincode::deserialize(&result).expect("deserialize result with bincode");
153
154 if let Some(result) = process_result.ok {
155 Ok(Box::new(result))
156 } else if let Some(result) = process_result.err {
157 Err(format_err!(result))
158 } else {
159 Err(format_err!("Failed to find ok or err result from process."))
160 }
161}