PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/components/depot/tests/support/command.rs

https://gitlab.com/github-cloud-corporation/habitat
Rust | 210 lines | 167 code | 29 blank | 14 comment | 8 complexity | 13c73950a07b20985424080351cbc3e2 MD5 | raw file
  1. // Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. use std::io::prelude::*;
  15. use std::io;
  16. use std::process::{Command, Child, Stdio, ExitStatus};
  17. use std::fmt;
  18. use std::error::Error;
  19. use std::result;
  20. use std::thread;
  21. use std::collections::HashMap;
  22. pub struct Cmd {
  23. pub child: Option<Child>,
  24. pub status: Option<ExitStatus>,
  25. pub stdout: Option<String>,
  26. pub stderr: Option<String>,
  27. }
  28. impl Cmd {
  29. pub fn stdout(&self) -> &str {
  30. match self.stdout {
  31. Some(ref stdout) => stdout,
  32. None => panic!("No stdout available - process needs a wait"),
  33. }
  34. }
  35. pub fn stderr(&self) -> &str {
  36. match self.stderr {
  37. Some(ref stderr) => stderr,
  38. None => panic!("No stderr available - process needs a wait"),
  39. }
  40. }
  41. pub fn status(&self) -> &ExitStatus {
  42. match self.status {
  43. Some(ref status) => status,
  44. None => panic!("No status available - process needs a wait or kill"),
  45. }
  46. }
  47. pub fn wait_with_output(&mut self) -> &Self {
  48. // The child is unavailable for more calls after this
  49. let child = self.child.take().unwrap();
  50. let output = match child.wait_with_output() {
  51. Ok(output) => output,
  52. Err(e) => panic!("{:?}", e),
  53. };
  54. self.status = Some(output.status);
  55. let stdout = String::from_utf8(output.stdout).unwrap_or_else(|x| panic!("{:?}", x));
  56. let stderr = String::from_utf8(output.stderr).unwrap_or_else(|x| panic!("{:?}", x));
  57. println!("OUT: {}", stdout);
  58. println!("ERR: {}", stderr);
  59. self.stdout = Some(stdout);
  60. self.stderr = Some(stderr);
  61. self
  62. }
  63. }
  64. #[derive(Debug)]
  65. pub enum CmdError {
  66. Io(io::Error),
  67. }
  68. pub type CmdResult<T> = result::Result<T, CmdError>;
  69. impl fmt::Display for CmdError {
  70. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  71. match *self {
  72. CmdError::Io(ref err) => err.fmt(f),
  73. }
  74. }
  75. }
  76. impl Error for CmdError {
  77. fn description(&self) -> &str {
  78. match *self {
  79. CmdError::Io(ref err) => err.description(),
  80. }
  81. }
  82. }
  83. impl From<io::Error> for CmdError {
  84. fn from(err: io::Error) -> CmdError {
  85. CmdError::Io(err)
  86. }
  87. }
  88. #[derive(Debug)]
  89. pub struct CommandArgs {
  90. pub cmd: String,
  91. pub args: Vec<String>,
  92. pub env: HashMap<String, String>,
  93. pub cwd: Option<String>,
  94. }
  95. impl CommandArgs {
  96. fn new<S: Into<String>>(cmd: S) -> CommandArgs {
  97. CommandArgs {
  98. cmd: cmd.into(),
  99. args: Vec::new(),
  100. env: HashMap::new(),
  101. cwd: None,
  102. }
  103. }
  104. fn arg<S: Into<String>>(&mut self, arg: S) -> &mut CommandArgs {
  105. self.args.push(arg.into());
  106. self
  107. }
  108. fn env<S: Into<String>>(&mut self, k: S, v: S) -> &mut CommandArgs {
  109. self.env.insert(k.into(), v.into());
  110. self
  111. }
  112. }
  113. impl fmt::Display for CommandArgs {
  114. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  115. write!(f,
  116. "Command: C: {} A: {:?} E: {:?} CWD: {:?}",
  117. self.cmd,
  118. self.args,
  119. self.env,
  120. self.cwd)
  121. }
  122. }
  123. pub fn command(cmd: &str, args: &[&str]) -> Command {
  124. command_with_env(cmd, args, None)
  125. }
  126. pub fn command_with_env(cmd: &str, args: &[&str], env: Option<&HashMap<&str, &str>>) -> Command {
  127. let mut cmd_args = CommandArgs::new(cmd);
  128. for a in args {
  129. cmd_args.arg(*a);
  130. }
  131. if let Some(real_env) = env {
  132. for (k, v) in real_env {
  133. cmd_args.env(*k, *v);
  134. }
  135. }
  136. run_command(cmd_args)
  137. }
  138. pub fn run_command(cmd_args: CommandArgs) -> Command {
  139. println!("{}: {}",
  140. thread::current().name().unwrap_or("main"),
  141. cmd_args);
  142. let mut command = Command::new(&cmd_args.cmd);
  143. command.args(&cmd_args.args);
  144. command.stdin(Stdio::null());
  145. command.stdout(Stdio::piped());
  146. command.stderr(Stdio::piped());
  147. for (k, v) in cmd_args.env {
  148. command.env(k, v);
  149. }
  150. command
  151. }
  152. pub fn spawn(mut command: Command) -> CmdResult<Cmd> {
  153. let child = try!(command.spawn());
  154. Ok(Cmd {
  155. child: Some(child),
  156. status: None,
  157. stdout: None,
  158. stderr: None,
  159. })
  160. }
  161. pub fn studio_run(cmd: &str, args: &[&str]) -> CmdResult<Cmd> {
  162. let real_cmd = "studio";
  163. let mut real_args = vec!["-r", "/hab/studios/functional-tests", "run", cmd];
  164. real_args.extend_from_slice(args);
  165. let mut command = command(real_cmd, &real_args[..]);
  166. command.current_dir("/src");
  167. spawn(command)
  168. }
  169. pub fn run(cmd: &str, args: &[&str]) -> CmdResult<Cmd> {
  170. let command = command(cmd, args);
  171. spawn(command)
  172. }
  173. pub fn plan_build(to_build: &str) -> CmdResult<Cmd> {
  174. studio_run("/src/components/plan-build/bin/hab-plan-build.sh",
  175. &[to_build])
  176. }
  177. pub fn sup(args: &[&str]) -> CmdResult<Cmd> {
  178. let sup = super::path::sup();
  179. let command = command(&sup, args);
  180. spawn(command)
  181. }