Optimize grouping for *nix archs

This commit is contained in:
Michael Aaron Murphy 2017-10-14 21:25:56 -04:00
parent 1bc58b2fbb
commit ad1b4f3b2b
4 changed files with 76 additions and 3 deletions

1
Cargo.lock generated
View File

@ -8,6 +8,7 @@ dependencies = [
"diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"ignore 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -40,6 +40,9 @@ num_cpus = "1.6.2"
regex = "0.2"
regex-syntax = "0.4"
[target.'cfg(all(unix, not(target_os = "redox")))'.dependencies]
libc = "0.2"
[dev-dependencies]
diff = "0.1"
tempdir = "0.3"

View File

@ -1,7 +1,7 @@
use std::env;
use std::process::{Command, Stdio};
use std::process::Command;
use std::sync::{Arc, Mutex};
use std::io::{self, Write};
use std::io;
lazy_static! {
/// On non-Windows systems, the `SHELL` environment variable will be used to determine the
@ -29,8 +29,12 @@ impl<'a> CommandTicket<'a> {
}
/// Executes the command stored within the ticket, and
/// clearing the command's buffer when finished.
/// clearing the command's buffer when finished.'
#[cfg(not(all(unix, not(target_os = "redox"))))]
pub fn then_execute(self) {
use std::process::Stdio;
use std::io::Write;
// Spawn a shell with the supplied command.
let cmd = Command::new(COMMAND.0.as_str())
.arg(COMMAND.1)
@ -58,4 +62,67 @@ impl<'a> CommandTicket<'a> {
// Clear the buffer for later re-use.
self.command.clear();
}
#[cfg(all(unix, not(target_os = "redox")))]
pub fn then_execute(self) {
use libc::*;
use std::fs::File;
use std::os::unix::process::CommandExt;
use std::os::unix::io::FromRawFd;
// Initial a pair of pipes that will be used to
// pipe the std{out,err} of the spawned process.
let mut stdout_fds = [0; 2];
let mut stderr_fds = [0; 2];
unsafe {
pipe(stdout_fds.as_mut_ptr());
pipe(stderr_fds.as_mut_ptr());
}
// Spawn a shell with the supplied command.
let cmd = Command::new(COMMAND.0.as_str())
.arg(COMMAND.1)
.arg(&self.command)
.before_exec(move || unsafe {
// Configure the pipes accordingly in the child.
dup2(stdout_fds[1], STDOUT_FILENO);
dup2(stderr_fds[1], STDERR_FILENO);
close(stdout_fds[0]);
close(stdout_fds[1]);
close(stderr_fds[0]);
close(stderr_fds[1]);
Ok(())
})
.spawn();
// Open the read end of the pipes as `File`s.
let (mut pout, mut perr) = unsafe {
close(stdout_fds[1]);
close(stderr_fds[1]);
(
File::from_raw_fd(stdout_fds[0]),
File::from_raw_fd(stderr_fds[0]),
)
};
match cmd {
Ok(mut child) => {
let _ = child.wait();
// Create a lock to ensure that this thread has exclusive access to writing.
let _lock = self.out_perm.lock().unwrap();
// And then write the outputs of the process until EOF is sent to each file.
let stdout = io::stdout();
let stderr = io::stderr();
let _ = io::copy(&mut pout, &mut stdout.lock());
let _ = io::copy(&mut perr, &mut stderr.lock());
}
Err(why) => eprintln!("fd: exec error: {}", why),
}
// Clear the command string's buffer for later re-use.
self.command.clear();
}
}

View File

@ -5,6 +5,8 @@ extern crate clap;
extern crate ignore;
#[macro_use]
extern crate lazy_static;
#[cfg(all(unix, not(target_os = "redox")))]
extern crate libc;
extern crate num_cpus;
extern crate regex;
extern crate regex_syntax;