Honor the exit code from the child in the parent

This commit is contained in:
Diego Giagio 2018-10-15 02:25:19 +02:00
parent 07e29916be
commit 32fa7cbda8
2 changed files with 50 additions and 32 deletions

View File

@ -2,6 +2,7 @@ use std::env;
use std::process::Command; use std::process::Command;
use std::process::Stdio; use std::process::Stdio;
use std::path::Path; use std::path::Path;
use std::io;
#[cfg(target_family = "windows")] #[cfg(target_family = "windows")]
const PATH_SEPARATOR: char = ';'; const PATH_SEPARATOR: char = ';';
@ -9,23 +10,31 @@ const PATH_SEPARATOR: char = ';';
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
const PATH_SEPARATOR: char = ':'; const PATH_SEPARATOR: char = ':';
pub fn execute(path: &Path, prog: &str) { pub fn execute(target: &Path) -> io::Result<i32> {
let path_str = path.as_os_str().to_os_string().into_string().unwrap(); let target_dir = target.parent()
let path_env = match env::var("PATH") { .and_then(|dir| dir.to_str())
Ok(p) => format!("{}{}{}", &path_str, PATH_SEPARATOR, &p), .expect("Unable to construct target directory");
_ => path_str let target_file_name = target.file_name()
}; .and_then(|file_name| file_name.to_str())
.expect("Unable to identify target file name");
trace!("target={:?}", target);
trace!("target_dir={:?}", target_dir);
trace!("target_file_name={:?}", target_file_name);
let current_path_env = env::var("PATH").unwrap_or(String::new());
let path_env = format!("{}{}{}", target_dir, PATH_SEPARATOR, current_path_env);
trace!("path_env={:?}", path_env);
let args: Vec<String> = env::args().skip(1).collect(); let args: Vec<String> = env::args().skip(1).collect();
trace!("PATH={:?} prog={:?} args={:?}", path_env, prog, args); trace!("args={:?}", args);
Command::new(prog)
Ok(Command::new(target_file_name)
.env("PATH", path_env) .env("PATH", path_env)
.args(args) .args(args)
.stdin(Stdio::inherit()) .stdin(Stdio::inherit())
.stdout(Stdio::inherit()) .stdout(Stdio::inherit())
.stderr(Stdio::inherit()) .stderr(Stdio::inherit())
.spawn() .spawn()?
.unwrap_or_else(|_| panic!("{} failed to start", prog)) .wait()?
.wait() .code().unwrap_or(1))
.unwrap_or_else(|_| panic!("{} failed to wait", prog));
} }

View File

@ -1,40 +1,40 @@
extern crate dirs; extern crate dirs;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate simple_logger; extern crate simple_logger;
use log::Level;
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::ffi::*; use std::ffi::*;
use std::fs; use std::fs;
use std::io; use std::io;
use std::path::*; use std::path::*;
use log::Level; use std::process;
mod extractor; mod extractor;
mod executor; mod executor;
static PROG_BUF: &'static [u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0"; static TARGET_FILE_NAME_BUF: &'static [u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0";
fn prog() -> &'static str { fn target_file_name() -> &'static str {
let nul_pos = PROG_BUF.iter() let nul_pos = TARGET_FILE_NAME_BUF.iter()
.position(|elem| *elem == b'\0') .position(|elem| *elem == b'\0')
.expect("PROG_BUF has no NUL terminator"); .expect("TARGET_FILE_NAME_BUF has no NUL terminator");
let slice = &PROG_BUF[..(nul_pos + 1)]; let slice = &TARGET_FILE_NAME_BUF[..(nul_pos + 1)];
CStr::from_bytes_with_nul(slice) CStr::from_bytes_with_nul(slice)
.expect("Can't convert PROG_BUF slice to CStr") .expect("Can't convert TARGET_FILE_NAME_BUF slice to CStr")
.to_str() .to_str()
.expect("Can't convert PROG_BUF CStr to str") .expect("Can't convert TARGET_FILE_NAME_BUF CStr to str")
} }
fn cache_path(prog: &str) -> PathBuf { fn cache_path(target: &str) -> PathBuf {
dirs::data_local_dir() dirs::data_local_dir()
.expect("No data local dir found") .expect("No data local dir found")
.join("warp") .join("warp")
.join("packages") .join("packages")
.join(prog) .join(target)
} }
fn extract(exe_path: &Path, cache_path: &Path) -> io::Result<()> { fn extract(exe_path: &Path, cache_path: &Path) -> io::Result<()> {
@ -48,26 +48,35 @@ fn main() -> Result<(), Box<Error>> {
simple_logger::init_with_level(Level::Trace)?; simple_logger::init_with_level(Level::Trace)?;
} }
let prog = prog(); let self_path = env::current_exe()?;
let cache_path = cache_path(prog); let self_file_name = self_path.file_name().unwrap();
let exe_path = env::current_exe()?; let cache_path = cache_path(&self_file_name.to_string_lossy());
trace!("prog={:?}, cache_path={:?}, exe_path={:?}", prog, cache_path, exe_path);
trace!("self_path={:?}", self_path);
trace!("self_file_name={:?}", self_file_name);
trace!("cache_path={:?}", cache_path);
let target_file_name = target_file_name();
let target_path = cache_path.join(target_file_name);
trace!("target_exec={:?}", target_file_name);
trace!("target_path={:?}", target_path);
match fs::metadata(&cache_path) { match fs::metadata(&cache_path) {
Ok(cache) => { Ok(cache) => {
if cache.modified()? >= fs::metadata(&exe_path)?.modified()? { if cache.modified()? >= fs::metadata(&self_path)?.modified()? {
trace!("cache is up-to-date"); trace!("cache is up-to-date");
} else { } else {
trace!("cache is outdated"); trace!("cache is outdated");
extract(&exe_path, &cache_path)?; extract(&self_path, &cache_path)?;
} }
} }
Err(_) => { Err(_) => {
trace!("cache not found"); trace!("cache not found");
extract(&exe_path, &cache_path)?; extract(&self_path, &cache_path)?;
} }
} }
executor::execute(&cache_path, &prog); let exit_code = executor::execute(&target_path)?;
Ok(()) process::exit(exit_code);
} }