#![experimental]
use std::cmp::{max,min};
use std::io::{Command,IoResult};
use std::io::process::{Process,ProcessExit,ProcessOutput,StdioContainer};
#[cfg(windows)]
use std::os;
use std::str;
#[cfg(unix)]
#[experimental]
pub struct CommandExt {
cmd: Command,
header: bool,
}
#[cfg(windows)]
#[experimental]
pub struct CommandExt {
cmd: Command,
shargs: String,
header: bool,
}
#[cfg(unix)]
#[experimental]
fn build_command(cmd: &str) -> Command {
Command::new(cmd)
}
#[cfg(windows)]
#[experimental]
fn build_command(_: &str) -> Command {
let mut new_cmd = Command::new("sh");
new_cmd.arg("-c");
new_cmd
}
#[experimental]
pub fn to_procout<'a>() -> |Command|:'a -> IoResult<ProcessOutput> {
|cmd| -> IoResult<ProcessOutput> {
cmd.output()
}
}
#[experimental]
pub fn to_proc<'a>() -> |Command|:'a -> IoResult<Process> {
|cmd| -> IoResult<Process> {
cmd.spawn()
}
}
#[experimental]
pub fn to_res<'a>() -> |Command|:'a -> Result<u8,u8> {
|cmd| -> Result<u8,u8> {
let ref mut mcmd = cmd.clone();
mcmd.stdout(StdioContainer::InheritFd(1));
mcmd.stderr(StdioContainer::InheritFd(2));
match mcmd.spawn() {
Ok(mut p) => match p.wait() {
Ok(pe) => match pe {
ProcessExit::ExitStatus(code) => {
if code == 0 {
Ok(code as u8)
} else {
Err(code as u8)
}
},
ProcessExit::ExitSignal(code) => Err(code as u8),
},
Err(_) => Err(1),
},
Err(e) => panic!("Failed to execute: {} {}", e.kind, e.desc),
}
}
}
#[experimental]
impl CommandExt {
#[cfg(unix)]
#[experimental]
pub fn new(cmd: &str) -> CommandExt {
CommandExt{
cmd: build_command(cmd),
header: false,
}
}
#[cfg(windows)]
#[experimental]
pub fn new(cmd: &str) -> CommandExt {
CommandExt{
cmd: build_command(cmd),
shargs: cmd.to_string(),
header: false,
}
}
#[experimental]
pub fn wd(&mut self, wd: &Path) -> &mut CommandExt {
self.cmd.cwd(wd);
self
}
#[experimental]
pub fn header(&mut self, show_header: bool) -> &mut CommandExt {
self.header = show_header;
self
}
#[cfg(unix)]
#[experimental]
pub fn arg(&mut self, arg: &str) -> &mut CommandExt {
self.cmd.arg(arg);
self
}
#[cfg(windows)]
#[experimental]
pub fn arg(&mut self, arg: &str) -> &mut CommandExt {
self.shargs.push_str(" ");
self.shargs.push_str(arg);
self
}
#[cfg(unix)]
#[experimental]
pub fn args(&mut self, args: &[&str]) -> &mut CommandExt {
self.cmd.args(args);
self
}
#[cfg(windows)]
#[experimental]
pub fn args(&mut self, args: &[&str]) -> &mut CommandExt {
for arg in args.iter() {
self.shargs.push_str(" ");
self.shargs.push_str(*arg);
}
self
}
#[experimental]
pub fn env(&mut self, key: &str, val: &str) -> &mut CommandExt {
self.cmd.env(key, val);
self
}
#[experimental]
pub fn env_set_all(&mut self, env: &[(&str,&str)]) -> &mut CommandExt {
self.cmd.env_set_all(env);
self
}
#[cfg(unix)]
#[experimental]
pub fn exec<T>(&self, execfn: |Command| -> T) -> T {
if self.header {
header(format!(" Executing '{}'", self.cmd).as_slice());
}
(execfn)(self.cmd.clone())
}
#[cfg(windows)]
#[experimental]
pub fn exec<T>(&self, execfn: |Command| -> T) -> T {
let ref shargs = self.shargs;
let mut new_cmd = self.cmd.clone();
new_cmd.arg(shargs);
if self.header {
header(format!(" Executing '{}'", new_cmd).as_slice());
}
(execfn)(new_cmd)
}
}
#[experimental]
pub fn header(msg: &str) {
println!("{:#<80}", "#");
println!("{}", msg);
println!("{:#<80}", "#");
}
#[experimental]
pub fn nproc() -> int {
match CommandExt::new("nproc").exec(to_procout()) {
Ok(p) => {
match str::from_utf8(p.output.as_slice()).unwrap().trim().parse() {
Some(i) => i,
None => panic!("unable to cast nproc output!"),
}
},
Err(e) => panic!("Failed to execute nproc: {}", e),
}
}
#[experimental]
pub fn usable_cores() -> int {
let usable = nproc() - 1;
min(4, max(1, usable))
}
#[cfg(unix)]
#[experimental]
pub fn mh() -> String {
match CommandExt::new("uname").arg("-m").exec(to_procout()) {
Ok(o) => {
let mut res = String::from_utf8_lossy(o.output.as_slice());
res.to_mut().trim().to_string()
},
Err(e) => panic!("Failed to execute uname: {}", e),
}
}
#[cfg(windows)]
#[experimental]
pub fn mh() -> String {
let pa = "PROCESSOR_ARCHITECTURE";
let val = match os::getenv(pa) {
Some(v) => v,
None => "".to_string(),
};
if !(val == "AMD64") {
let paw = "PROCESSOR_ARCHITEW6432";
let val1 = match os::getenv(paw) {
Some(v) => v,
None => "".to_string(),
};
if val1 == "AMD64" {
val1
} else {
"x86".to_string()
}
} else {
val
}
}
#[experimental]
pub fn is_64() -> bool {
cfg!(target_word_size = "64")
}
#[experimental]
pub fn is_32() -> bool {
cfg!(target_word_size = "32")
}
#[cfg(test)]
mod test {
use super::{mh,nproc,to_procout,to_res};
use super::is_64;
use super::is_32;
use super::CommandExt;
use std::num::SignedInt;
#[test]
fn test_nproc() {
assert!(SignedInt::is_positive(nproc()));
}
#[test]
#[cfg(target_arch = "x86_64")]
fn test_mh() {
assert_eq!(mh(), "x86_64");
}
#[test]
#[cfg(target_arch = "x86")]
fn test_mh() {
assert_eq!(mh(), "i686");
}
#[test]
#[cfg(target_arch = "x86_64")]
fn test_is_64() {
assert!(is_64());
assert!(!is_32());
}
#[test]
#[cfg(target_arch = "x86")]
fn test_is_32() {
assert!(is_32());
assert!(!is_64());
}
#[test]
fn test_command_ext() {
let cmd = CommandExt::new("echo").arg("test").exec(to_procout());
let output = cmd.unwrap();
if cfg!(unix) {
assert_eq!([116, 101, 115, 116, 10], output.output);
} else if cfg!(windows) {
assert_eq!(vec![116, 101, 115, 116, 10], output.output);
}
assert!(output.error.is_empty());
assert!(output.status.success());
}
#[test]
fn test_output_env() {
let cmd = CommandExt::new("env").env("TST", "1").exec(to_procout());
let output = cmd.unwrap();
assert!(output.error.is_empty());
assert!(output.status.success());
}
#[test]
fn test_output_env_set_all() {
let env = [("TST", "1"),("USR","2")];
let cmd = CommandExt::new("env").env_set_all(&env).exec(to_procout());
let output = cmd.unwrap();
if cfg!(unix) {
assert_eq!(12,output.output.len());
}
assert!(output.error.is_empty());
assert!(output.status.success());
}
#[test]
fn test_spawn() {
let res = CommandExt::new("echo").arg("Testing Spawn").exec(to_res());
assert_eq!(Ok(0), res);
}
#[test]
fn test_spawn_header() {
let mut cmd = CommandExt::new("echo");
cmd.arg("Testing Spawn");
cmd.header(true);
let res = cmd.exec(to_res());
assert_eq!(Ok(0), res);
}
#[test]
fn test_spawn_env() {
let cmd = CommandExt::new("env").env("TST", "1").exec(to_res());
assert_eq!(Ok(0), cmd);
}
#[test]
fn test_spawn_env_set_all() {
let env = [("TST", "1"),("USR","2")];
let cmd = CommandExt::new("env").env_set_all(&env).exec(to_res());
assert_eq!(Ok(0), cmd);
}
}