|
4 | 4 | // https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
|
5 | 5 | // modified, or distributed except according to those terms.
|
6 | 6 |
|
7 |
| -use command::{Command, CommandProvider, CommandResult}; |
| 7 | +use command::{Command, CommandProvider, CommandResult, CommandRunnable}; |
8 | 8 | use erased_serde::Serialize;
|
9 | 9 | use errors::*;
|
10 |
| -use ExecutableProvider; |
11 |
| -use host::*; |
| 10 | +use Executable; |
| 11 | +use futures::{future, Future}; |
| 12 | +use host::Host; |
| 13 | +use Runnable; |
12 | 14 | use std::process;
|
| 15 | +use std::sync::Arc; |
13 | 16 |
|
14 | 17 | const DEFAULT_SHELL: [&'static str; 2] = ["/bin/sh", "-c"];
|
15 | 18 |
|
16 |
| -pub struct Nix<'a> { |
17 |
| - host: &'a Host, |
| 19 | +pub struct Nix<H: Host> { |
| 20 | + host: Arc<H>, |
18 | 21 | inner: Command
|
19 | 22 | }
|
20 | 23 |
|
21 | 24 | #[doc(hidden)]
|
22 | 25 | #[derive(Serialize, Deserialize)]
|
23 |
| -pub enum RemoteProvider { |
| 26 | +pub enum NixRunnable { |
24 | 27 | Available,
|
25 | 28 | Exec(Command),
|
26 | 29 | }
|
27 | 30 |
|
28 |
| -impl <'de>ExecutableProvider<'de> for RemoteProvider { |
29 |
| - fn exec(self, host: &Host) -> Result<Box<Serialize>> { |
30 |
| - match self { |
31 |
| - RemoteProvider::Available => Ok(Box::new(Nix::available(host))), |
32 |
| - RemoteProvider::Exec(inner) => { |
33 |
| - let p = Nix { host, inner }; |
34 |
| - Ok(Box::new(p.exec()?)) |
35 |
| - } |
36 |
| - } |
| 31 | +impl <H: Host + 'static>CommandProvider<H> for Nix<H> { |
| 32 | + fn available(host: &Arc<H>) -> Box<Future<Item = bool, Error = Error>> { |
| 33 | + host.run(Runnable::Command(CommandRunnable::Nix(NixRunnable::Available))) |
| 34 | + .chain_err(|| ErrorKind::Runnable { endpoint: "Command::Nix", func: "available" }) |
37 | 35 | }
|
38 |
| -} |
39 | 36 |
|
40 |
| -impl <'a>CommandProvider<'a> for Nix<'a> { |
41 |
| - fn available(host: &Host) -> bool { |
42 |
| - if host.is_local() { |
43 |
| - cfg!(not(windows)) |
44 |
| - } else { |
45 |
| - unimplemented!(); |
46 |
| - // let r = RemoteProvider::Available; |
47 |
| - // self.host.send(r).chain_err(|| ErrorKind::RemoteProvider("Command", "available"))?; |
48 |
| - // Ok(self.host.recv()?) |
49 |
| - } |
| 37 | + fn try_new(host: &Arc<H>, cmd: &str, shell: Option<&[&str]>) -> Box<Future<Item = Option<Nix<H>>, Error = Error>> { |
| 38 | + let cmd_owned = cmd.to_owned(); |
| 39 | + let shell_owned: Vec<String> = shell.unwrap_or(&DEFAULT_SHELL).to_owned().iter().map(|s| s.to_string()).collect(); |
| 40 | + let host = host.clone(); |
| 41 | + |
| 42 | + Box::new(Self::available(&host).and_then(move |available| { |
| 43 | + if available { |
| 44 | + let inner = Command { |
| 45 | + shell: shell_owned, |
| 46 | + cmd: cmd_owned, |
| 47 | + }; |
| 48 | + future::ok(Some(Nix { host, inner })) |
| 49 | + } else { |
| 50 | + future::ok(None) |
| 51 | + } |
| 52 | + })) |
50 | 53 | }
|
51 | 54 |
|
52 |
| - fn try_new(host: &'a Host, cmd: &[&str], shell: Option<&[&str]>) -> Option<Nix<'a>> { |
53 |
| - if Self::available(host) { |
54 |
| - let inner = Command { |
55 |
| - shell: shell.unwrap_or(&DEFAULT_SHELL).to_owned().iter().map(|s| s.to_string()).collect(), |
56 |
| - cmd: cmd.to_owned().iter().map(|s| s.to_string()).collect(), |
57 |
| - }; |
58 |
| - Some(Nix { host, inner }) |
59 |
| - } else { |
60 |
| - None |
61 |
| - } |
| 55 | + fn exec(&mut self) -> Box<Future<Item = CommandResult, Error = Error>> { |
| 56 | + self.host.run(Runnable::Command(CommandRunnable::Nix(NixRunnable::Exec(self.inner.clone())))) |
| 57 | + .chain_err(|| ErrorKind::Runnable { endpoint: "Command::Nix", func: "exec" }) |
62 | 58 | }
|
| 59 | +} |
63 | 60 |
|
64 |
| - fn exec(&self) -> Result<CommandResult> { |
65 |
| - if self.host.is_local() { |
66 |
| - let (shell, shell_args) = self.inner.shell.split_first() |
67 |
| - .ok_or("Invalid shell provided")?; |
68 |
| - let out = process::Command::new(shell) |
69 |
| - .args(shell_args) |
70 |
| - .args(&self.inner.cmd) |
71 |
| - .output() |
72 |
| - .chain_err(|| "Command execution failed")?; |
73 |
| - Ok(CommandResult { |
74 |
| - success: out.status.success(), |
75 |
| - exit_code: out.status.code(), |
76 |
| - stdout: out.stdout, |
77 |
| - stderr: out.stderr |
78 |
| - }) |
79 |
| - } else { |
80 |
| - unimplemented!(); |
81 |
| - // let r = RemoteProvider::Load; |
82 |
| - // self.host.send(r).chain_err(|| ErrorKind::RemoteProvider("Command", "exec"))?; |
83 |
| - // let result: CommandResult = self.host.recv()?; |
84 |
| - // Ok(result) |
| 61 | +impl Executable for NixRunnable { |
| 62 | + fn exec(self) -> Box<Future<Item = Box<Serialize>, Error = Error>> { |
| 63 | + match self { |
| 64 | + NixRunnable::Available => |
| 65 | + Box::new(future::ok(Box::new( |
| 66 | + cfg!(unix) |
| 67 | + ) as Box<Serialize>)), |
| 68 | + NixRunnable::Exec(inner) => { |
| 69 | + Box::new(future::lazy(move || -> future::FutureResult<Box<Serialize>, Error> { |
| 70 | + let (shell, shell_args) = match inner.shell.split_first() { |
| 71 | + Some((s, a)) => (s, a), |
| 72 | + None => return future::err("Invalid shell provided".into()), |
| 73 | + }; |
| 74 | + |
| 75 | + let out = process::Command::new(shell) |
| 76 | + .args(shell_args) |
| 77 | + .arg(&inner.cmd) |
| 78 | + .output() |
| 79 | + .chain_err(|| "Command execution failed"); |
| 80 | + match out { |
| 81 | + Ok(output) => future::ok(Box::new(CommandResult { |
| 82 | + success: output.status.success(), |
| 83 | + exit_code: output.status.code(), |
| 84 | + stdout: output.stdout, |
| 85 | + stderr: output.stderr, |
| 86 | + }) as Box<Serialize>), |
| 87 | + Err(e) => future::err(e), |
| 88 | + } |
| 89 | + })) |
| 90 | + } |
85 | 91 | }
|
86 | 92 | }
|
87 | 93 | }
|
0 commit comments