polyhorn_cli/core/tasks/
install_dependencies.rs1use ansi_term::Color;
2use dialoguer::Confirm;
3use std::io::Error;
4use std::process::{Command, Stdio};
5
6use crate::core::{Manager, Task};
7
8pub struct DependencyCheck {
10 pub command: Vec<String>,
12}
13
14pub struct Dependency {
16 pub name: String,
18
19 pub check: DependencyCheck,
21
22 pub install_command: Vec<String>,
24}
25
26impl Dependency {
27 pub fn cli(name: &str, check_command: &[&str], install_command: &[&str]) -> Dependency {
30 Dependency {
31 name: name.to_owned(),
32 check: DependencyCheck {
33 command: check_command.iter().map(|&arg| arg.to_owned()).collect(),
34 },
35 install_command: install_command.iter().map(|&arg| arg.to_owned()).collect(),
36 }
37 }
38}
39
40pub struct InstallDependencies {
43 pub dependencies: Vec<Dependency>,
45}
46
47impl InstallDependencies {
48 fn check(&self) -> Vec<&Dependency> {
49 self.dependencies
50 .iter()
51 .filter_map(|dependency| {
52 let mut command = Command::new(&dependency.check.command[0]);
53 command.args(&dependency.check.command[1..]);
54 let output = command.output().ok();
55
56 match output.map(|output| output.status.success()) {
57 Some(true) => None,
58 _ => Some(dependency),
59 }
60 })
61 .collect()
62 }
63}
64
65impl Task for InstallDependencies {
66 type Context = ();
67 type Error = Error;
68
69 fn verb(&self) -> &str {
70 "Checking"
71 }
72
73 fn message(&self) -> &str {
74 "dependencies"
75 }
76
77 fn detail(&self) -> &str {
78 ""
79 }
80
81 fn run(
82 &self,
83 context: Self::Context,
84 _manager: &mut Manager,
85 ) -> Result<Self::Context, Self::Error> {
86 let missing = self.check();
87
88 if missing.is_empty() {
89 return Ok(context);
90 }
91
92 eprintln!("\n\nThe following dependencies haven't been found and need to be installed:\n",);
93
94 for dependency in missing.iter() {
95 eprintln!(
96 " {} {}",
97 Color::Cyan.bold().paint(&dependency.name),
98 Color::Fixed(8).paint(format!("({})", dependency.install_command.join(" ")))
99 );
100 }
101
102 eprintln!("");
103
104 if Confirm::new()
105 .with_prompt("Do you want Polyhorn to install these dependencies automatically?")
106 .interact()?
107 {
108 for dependency in missing {
109 eprintln!(
110 "\nInstalling {} ...\n",
111 Color::Cyan.bold().paint(&dependency.name),
112 );
113 let mut command = Command::new(&dependency.install_command[0]);
114 command.args(&dependency.install_command[1..]);
115 command.stdout(Stdio::inherit());
116 command.stderr(Stdio::inherit());
117
118 match command.status() {
119 Ok(status) if status.success() => {}
120 Ok(status) => match status.code() {
121 Some(code) => std::process::exit(code),
122 None => std::process::exit(1),
123 },
124 Err(_) => {}
125 }
126
127 eprint!("");
128 }
129 } else {
130 std::process::exit(1);
131 }
132
133 eprintln!("");
134
135 Ok(context)
136 }
137}