Improve execution of .bat and .cmd files on Windows

This commit is contained in:
Diego Giagio 2018-10-15 18:44:54 +02:00
parent 8d21006f05
commit c0f14251a4

View File

@ -1,41 +1,22 @@
use std::env; use std::env;
use std::io;
use std::path::Path;
use std::process::Command; use std::process::Command;
use std::process::Stdio; use std::process::Stdio;
use std::path::Path;
use std::io;
#[cfg(target_family = "windows")]
const PATH_SEPARATOR: char = ';';
#[cfg(target_family = "unix")]
const PATH_SEPARATOR: char = ':';
pub fn execute(target: &Path) -> io::Result<i32> { pub fn execute(target: &Path) -> io::Result<i32> {
let target_dir = target.parent()
.and_then(|dir| dir.to_str())
.expect("Unable to construct target directory");
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={:?}", 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!("args={:?}", args); trace!("args={:?}", args);
do_execute(target_file_name, &args, &path_env) do_execute(target, &args)
} }
#[cfg(target_family = "unix")] #[cfg(target_family = "unix")]
fn do_execute(target: &str, args: &[String], path_env: &str) -> io::Result<i32> { fn do_execute(target: &Path, args: &[String]) -> io::Result<i32> {
Ok(Command::new(target) Ok(Command::new(target)
.args(args) .args(args)
.env("PATH", path_env)
.stdin(Stdio::inherit()) .stdin(Stdio::inherit())
.stdout(Stdio::inherit()) .stdout(Stdio::inherit())
.stderr(Stdio::inherit()) .stderr(Stdio::inherit())
@ -45,15 +26,36 @@ fn do_execute(target: &str, args: &[String], path_env: &str) -> io::Result<i32>
} }
#[cfg(target_family = "windows")] #[cfg(target_family = "windows")]
fn do_execute(target: &str, args: &[String], path_env: &str) -> io::Result<i32> { fn is_script(target: &Path) -> bool {
const SCRIPT_EXTENSIONS: &[&str] = &["bat", "cmd"];
SCRIPT_EXTENSIONS.contains(
&target.extension()
.unwrap_or_default()
.to_string_lossy()
.to_lowercase().as_str())
}
#[cfg(target_family = "windows")]
fn do_execute(target: &Path, args: &[String]) -> io::Result<i32> {
let target_str = target.as_os_str().to_str().unwrap();
if is_script(target) {
let mut cmd_args = Vec::with_capacity(args.len() + 2); let mut cmd_args = Vec::with_capacity(args.len() + 2);
cmd_args.push("/c".to_string()); cmd_args.push("/c".to_string());
cmd_args.push(target.to_string()); cmd_args.push(target_str.to_string());
cmd_args.extend_from_slice(&args); cmd_args.extend_from_slice(&args);
Ok(Command::new("cmd") Ok(Command::new("cmd")
.args(cmd_args) .args(cmd_args)
.env("PATH", path_env) .stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()?
.wait()?
.code().unwrap_or(1))
} else {
Ok(Command::new(target)
.args(args)
.stdin(Stdio::inherit()) .stdin(Stdio::inherit())
.stdout(Stdio::inherit()) .stdout(Stdio::inherit())
.stderr(Stdio::inherit()) .stderr(Stdio::inherit())
@ -61,3 +63,4 @@ fn do_execute(target: &str, args: &[String], path_env: &str) -> io::Result<i32>
.wait()? .wait()?
.code().unwrap_or(1)) .code().unwrap_or(1))
} }
}