forked from mirrors/gecko-dev
--HG-- rename : third_party/rust/crossbeam-deque/.cargo-checksum.json => third_party/rust/crossbeam-deque-0.2.0/.cargo-checksum.json rename : third_party/rust/crossbeam-deque/.travis.yml => third_party/rust/crossbeam-deque-0.2.0/.travis.yml rename : third_party/rust/crossbeam-deque/CHANGELOG.md => third_party/rust/crossbeam-deque-0.2.0/CHANGELOG.md rename : third_party/rust/crossbeam-deque/Cargo.toml => third_party/rust/crossbeam-deque-0.2.0/Cargo.toml rename : third_party/rust/bitflags-0.7.0/LICENSE-APACHE => third_party/rust/crossbeam-deque-0.2.0/LICENSE-APACHE rename : third_party/rust/crossbeam-deque/README.md => third_party/rust/crossbeam-deque-0.2.0/README.md rename : third_party/rust/crossbeam-deque/src/lib.rs => third_party/rust/crossbeam-deque-0.2.0/src/lib.rs rename : third_party/rust/crossbeam-epoch/.cargo-checksum.json => third_party/rust/crossbeam-epoch-0.3.1/.cargo-checksum.json rename : third_party/rust/crossbeam-epoch/.travis.yml => third_party/rust/crossbeam-epoch-0.3.1/.travis.yml rename : third_party/rust/crossbeam-epoch/CHANGELOG.md => third_party/rust/crossbeam-epoch-0.3.1/CHANGELOG.md rename : third_party/rust/crossbeam-epoch/Cargo.toml => third_party/rust/crossbeam-epoch-0.3.1/Cargo.toml rename : third_party/rust/tokio-io/LICENSE-APACHE => third_party/rust/crossbeam-epoch-0.3.1/LICENSE-APACHE rename : third_party/rust/crossbeam-epoch/README.md => third_party/rust/crossbeam-epoch-0.3.1/README.md rename : third_party/rust/crossbeam-epoch/examples/sanitize.rs => third_party/rust/crossbeam-epoch-0.3.1/examples/sanitize.rs rename : third_party/rust/crossbeam-epoch/src/atomic.rs => third_party/rust/crossbeam-epoch-0.3.1/src/atomic.rs rename : third_party/rust/crossbeam-epoch/src/collector.rs => third_party/rust/crossbeam-epoch-0.3.1/src/collector.rs rename : third_party/rust/crossbeam-epoch/src/default.rs => third_party/rust/crossbeam-epoch-0.3.1/src/default.rs rename : third_party/rust/crossbeam-epoch/src/deferred.rs => third_party/rust/crossbeam-epoch-0.3.1/src/deferred.rs rename : third_party/rust/crossbeam-epoch/src/epoch.rs => third_party/rust/crossbeam-epoch-0.3.1/src/epoch.rs rename : third_party/rust/crossbeam-epoch/src/garbage.rs => third_party/rust/crossbeam-epoch-0.3.1/src/garbage.rs rename : third_party/rust/crossbeam-epoch/src/guard.rs => third_party/rust/crossbeam-epoch-0.3.1/src/guard.rs rename : third_party/rust/crossbeam-epoch/src/internal.rs => third_party/rust/crossbeam-epoch-0.3.1/src/internal.rs rename : third_party/rust/crossbeam-epoch/src/lib.rs => third_party/rust/crossbeam-epoch-0.3.1/src/lib.rs rename : third_party/rust/crossbeam-epoch/src/sync/list.rs => third_party/rust/crossbeam-epoch-0.3.1/src/sync/list.rs rename : third_party/rust/crossbeam-epoch/src/sync/queue.rs => third_party/rust/crossbeam-epoch-0.3.1/src/sync/queue.rs rename : third_party/rust/crossbeam-utils/.cargo-checksum.json => third_party/rust/crossbeam-utils-0.2.2/.cargo-checksum.json rename : third_party/rust/crossbeam-utils/CHANGELOG.md => third_party/rust/crossbeam-utils-0.2.2/CHANGELOG.md rename : third_party/rust/crossbeam-utils/Cargo.toml => third_party/rust/crossbeam-utils-0.2.2/Cargo.toml rename : third_party/rust/bitflags-0.7.0/LICENSE-APACHE => third_party/rust/crossbeam-utils-0.2.2/LICENSE-APACHE rename : third_party/rust/crossbeam-utils/src/atomic_option.rs => third_party/rust/crossbeam-utils-0.2.2/src/atomic_option.rs rename : third_party/rust/crossbeam-utils/src/lib.rs => third_party/rust/crossbeam-utils-0.2.2/src/lib.rs rename : third_party/rust/crossbeam-utils/src/scoped.rs => third_party/rust/crossbeam-utils-0.2.2/src/scoped.rs rename : third_party/rust/bitflags-0.7.0/LICENSE-APACHE => third_party/rust/indexmap/LICENSE-APACHE rename : third_party/rust/lazycell/.cargo-checksum.json => third_party/rust/lazycell-0.4.0/.cargo-checksum.json rename : third_party/rust/lazycell/CHANGELOG.md => third_party/rust/lazycell-0.4.0/CHANGELOG.md rename : third_party/rust/lazycell/Cargo.toml => third_party/rust/lazycell-0.4.0/Cargo.toml rename : third_party/rust/bitflags-0.7.0/LICENSE-APACHE => third_party/rust/lazycell-0.4.0/LICENSE-APACHE rename : third_party/rust/lazycell/LICENSE-MIT => third_party/rust/lazycell-0.4.0/LICENSE-MIT rename : third_party/rust/lazycell/README.md => third_party/rust/lazycell-0.4.0/README.md rename : third_party/rust/lazycell/src/lib.rs => third_party/rust/lazycell-0.4.0/src/lib.rs rename : third_party/rust/bitflags-0.7.0/LICENSE-APACHE => third_party/rust/rand-0.3.22/LICENSE-APACHE rename : third_party/rust/bitflags-0.7.0/LICENSE-MIT => third_party/rust/rand-0.3.22/LICENSE-MIT rename : third_party/rust/rand/appveyor.yml => third_party/rust/rand-0.3.22/appveyor.yml rename : third_party/rust/slab/.cargo-checksum.json => third_party/rust/slab-0.3.0/.cargo-checksum.json rename : third_party/rust/slab/Cargo.toml => third_party/rust/slab-0.3.0/Cargo.toml rename : third_party/rust/slab/README.md => third_party/rust/slab-0.3.0/README.md rename : third_party/rust/slab/src/lib.rs => third_party/rust/slab-0.3.0/src/lib.rs rename : third_party/rust/tokio-io/src/read_to_end.rs => third_party/rust/tokio-io/src/io/read_to_end.rs rename : third_party/rust/tokio-io/src/read_until.rs => third_party/rust/tokio-io/src/io/read_until.rs
249 lines
7.5 KiB
Rust
249 lines
7.5 KiB
Rust
use {TryRead, TryWrite};
|
|
use std::mem;
|
|
use mio::*;
|
|
use std::io;
|
|
use mio::deprecated::{EventLoop, Handler};
|
|
use mio::deprecated::unix::{PipeReader, PipeWriter};
|
|
use std::process::{Command, Stdio, Child};
|
|
|
|
|
|
struct SubprocessClient {
|
|
stdin: Option<PipeWriter>,
|
|
stdout: Option<PipeReader>,
|
|
stderr: Option<PipeReader>,
|
|
stdin_token : Token,
|
|
stdout_token : Token,
|
|
stderr_token : Token,
|
|
output : Vec<u8>,
|
|
output_stderr : Vec<u8>,
|
|
input : Vec<u8>,
|
|
input_offset : usize,
|
|
buf : [u8; 65536],
|
|
}
|
|
|
|
|
|
// Sends a message and expects to receive the same exact message, one at a time
|
|
impl SubprocessClient {
|
|
fn new(stdin: Option<PipeWriter>, stdout : Option<PipeReader>, stderr : Option<PipeReader>, data : &[u8]) -> SubprocessClient {
|
|
SubprocessClient {
|
|
stdin: stdin,
|
|
stdout: stdout,
|
|
stderr: stderr,
|
|
stdin_token : Token(0),
|
|
stdout_token : Token(1),
|
|
stderr_token : Token(2),
|
|
output : Vec::<u8>::new(),
|
|
output_stderr : Vec::<u8>::new(),
|
|
buf : [0; 65536],
|
|
input : data.to_vec(),
|
|
input_offset : 0,
|
|
}
|
|
}
|
|
|
|
fn readable(&mut self, event_loop: &mut EventLoop<SubprocessClient>) -> io::Result<()> {
|
|
let mut eof = false;
|
|
match self.stdout {
|
|
None => unreachable!(),
|
|
Some (ref mut stdout) => match stdout.try_read(&mut self.buf[..]) {
|
|
Ok(None) => {
|
|
}
|
|
Ok(Some(r)) => {
|
|
if r == 0 {
|
|
eof = true;
|
|
} else {
|
|
self.output.extend(&self.buf[0..r]);
|
|
}
|
|
}
|
|
Err(e) => {
|
|
return Err(e);
|
|
}
|
|
}
|
|
};
|
|
if eof {
|
|
drop(self.stdout.take());
|
|
match self.stderr {
|
|
None => event_loop.shutdown(),
|
|
Some(_) => {},
|
|
}
|
|
}
|
|
return Ok(());
|
|
}
|
|
|
|
fn readable_stderr(&mut self, event_loop: &mut EventLoop<SubprocessClient>) -> io::Result<()> {
|
|
let mut eof = false;
|
|
match self.stderr {
|
|
None => unreachable!(),
|
|
Some(ref mut stderr) => match stderr.try_read(&mut self.buf[..]) {
|
|
Ok(None) => {
|
|
}
|
|
Ok(Some(r)) => {
|
|
if r == 0 {
|
|
eof = true;
|
|
} else {
|
|
self.output_stderr.extend(&self.buf[0..r]);
|
|
}
|
|
}
|
|
Err(e) => {
|
|
return Err(e);
|
|
}
|
|
}
|
|
};
|
|
if eof {
|
|
drop(self.stderr.take());
|
|
match self.stdout {
|
|
None => event_loop.shutdown(),
|
|
Some(_) => {},
|
|
}
|
|
}
|
|
return Ok(());
|
|
}
|
|
|
|
fn writable(&mut self, event_loop: &mut EventLoop<SubprocessClient>) -> io::Result<()> {
|
|
let mut ok = true;
|
|
match self.stdin {
|
|
None => unreachable!(),
|
|
Some(ref mut stdin) => match stdin.try_write(&(&self.input)[self.input_offset..]) {
|
|
Ok(None) => {
|
|
},
|
|
Ok(Some(r)) => {
|
|
if r == 0 {
|
|
ok = false;
|
|
} else {
|
|
self.input_offset += r;
|
|
}
|
|
},
|
|
Err(_) => {
|
|
ok = false;
|
|
},
|
|
}
|
|
}
|
|
if self.input_offset == self.input.len() || !ok {
|
|
drop(self.stdin.take());
|
|
match self.stderr {
|
|
None => match self.stdout {
|
|
None => event_loop.shutdown(),
|
|
Some(_) => {},
|
|
},
|
|
Some(_) => {},
|
|
}
|
|
}
|
|
return Ok(());
|
|
}
|
|
|
|
}
|
|
|
|
impl Handler for SubprocessClient {
|
|
type Timeout = usize;
|
|
type Message = ();
|
|
|
|
fn ready(&mut self, event_loop: &mut EventLoop<SubprocessClient>, token: Token,
|
|
_: Ready) {
|
|
if token == self.stderr_token {
|
|
let _x = self.readable_stderr(event_loop);
|
|
} else {
|
|
let _x = self.readable(event_loop);
|
|
}
|
|
if token == self.stdin_token {
|
|
let _y = self.writable(event_loop);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
const TEST_DATA : [u8; 1024 * 4096] = [42; 1024 * 4096];
|
|
pub fn subprocess_communicate(mut process : Child, input : &[u8]) -> (Vec<u8>, Vec<u8>) {
|
|
let mut event_loop = EventLoop::<SubprocessClient>::new().unwrap();
|
|
let stdin : Option<PipeWriter>;
|
|
let stdin_exists : bool;
|
|
match process.stdin {
|
|
None => stdin_exists = false,
|
|
Some(_) => stdin_exists = true,
|
|
}
|
|
if stdin_exists {
|
|
match PipeWriter::from_stdin(process.stdin.take().unwrap()) {
|
|
Err(e) => panic!(e),
|
|
Ok(pipe) => stdin = Some(pipe),
|
|
}
|
|
} else {
|
|
stdin = None;
|
|
}
|
|
let stdout_exists : bool;
|
|
let stdout : Option<PipeReader>;
|
|
match process.stdout {
|
|
None => stdout_exists = false,
|
|
Some(_) => stdout_exists = true,
|
|
}
|
|
if stdout_exists {
|
|
match PipeReader::from_stdout(process.stdout.take().unwrap()) {
|
|
Err(e) => panic!(e),
|
|
Ok(pipe) => stdout = Some(pipe),
|
|
}
|
|
} else {
|
|
stdout = None;
|
|
}
|
|
let stderr_exists : bool;
|
|
let stderr : Option<PipeReader>;
|
|
match process.stderr {
|
|
None => stderr_exists = false,
|
|
Some(_) => stderr_exists = true,
|
|
}
|
|
if stderr_exists {
|
|
match PipeReader::from_stderr(process.stderr.take().unwrap()) {
|
|
Err(e) => panic!(e),
|
|
Ok(pipe) => stderr = Some(pipe),
|
|
}
|
|
} else {
|
|
stderr = None
|
|
}
|
|
|
|
let mut subprocess = SubprocessClient::new(stdin,
|
|
stdout,
|
|
stderr,
|
|
input);
|
|
match subprocess.stdout {
|
|
Some(ref sub_stdout) => event_loop.register(sub_stdout, subprocess.stdout_token, Ready::readable(),
|
|
PollOpt::level()).unwrap(),
|
|
None => {},
|
|
}
|
|
|
|
match subprocess.stderr {
|
|
Some(ref sub_stderr) => event_loop.register(sub_stderr, subprocess.stderr_token, Ready::readable(),
|
|
PollOpt::level()).unwrap(),
|
|
None => {},
|
|
}
|
|
|
|
// Connect to the server
|
|
match subprocess.stdin {
|
|
Some (ref sub_stdin) => event_loop.register(sub_stdin, subprocess.stdin_token, Ready::writable(),
|
|
PollOpt::level()).unwrap(),
|
|
None => {},
|
|
}
|
|
|
|
// Start the event loop
|
|
event_loop.run(&mut subprocess).unwrap();
|
|
let _ = process.wait();
|
|
|
|
let ret_stdout = mem::replace(&mut subprocess.output, Vec::<u8>::new());
|
|
let ret_stderr = mem::replace(&mut subprocess.output_stderr, Vec::<u8>::new());
|
|
return (ret_stdout, ret_stderr);
|
|
}
|
|
|
|
#[test]
|
|
fn test_subprocess_pipe() {
|
|
let process =
|
|
Command::new("/bin/cat")
|
|
.stdin(Stdio::piped())
|
|
.stdout(Stdio::piped())
|
|
.stderr(Stdio::piped())
|
|
.spawn().unwrap();
|
|
let (ret_stdout, ret_stderr) = subprocess_communicate(process, &TEST_DATA[..]);
|
|
assert_eq!(TEST_DATA.len(), ret_stdout.len());
|
|
assert_eq!(0usize, ret_stderr.len());
|
|
let mut i : usize = 0;
|
|
for item in TEST_DATA.iter() {
|
|
assert_eq!(*item, ret_stdout[i]);
|
|
i += 1;
|
|
}
|
|
}
|