##// END OF EJS Templates
rust-chg: upgrade to 2018 edition and remove useless extern crates...
rust-chg: upgrade to 2018 edition and remove useless extern crates Differential Revision: https://phab.mercurial-scm.org/D8399

File last commit:

r45179:1f5ab1a9 default
r45179:1f5ab1a9 default
Show More
main.rs
97 lines | 2.9 KiB | application/rls-services+xml | RustLexer
// Copyright 2018 Yuya Nishihara <yuya@tcha.org>
//
// This software may be used and distributed according to the terms of the
// GNU General Public License version 2 or any later version.
use chg::locator::{self, Locator};
use chg::procutil;
use chg::{ChgClientExt, ChgUiHandler};
use futures::sync::oneshot;
use std::env;
use std::io;
use std::process;
use std::time::Instant;
use tokio::prelude::*;
struct DebugLogger {
start: Instant,
}
impl DebugLogger {
pub fn new() -> DebugLogger {
DebugLogger {
start: Instant::now(),
}
}
}
impl log::Log for DebugLogger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
metadata.target().starts_with("chg::")
}
fn log(&self, record: &log::Record) {
if self.enabled(record.metadata()) {
// just make the output looks similar to chg of C
let l = format!("{}", record.level()).to_lowercase();
let t = self.start.elapsed();
writeln!(
io::stderr(),
"chg: {}: {}.{:06} {}",
l,
t.as_secs(),
t.subsec_micros(),
record.args()
)
.unwrap_or(());
}
}
fn flush(&self) {}
}
fn main() {
if env::var_os("CHGDEBUG").is_some() {
log::set_boxed_logger(Box::new(DebugLogger::new()))
.expect("any logger should not be installed yet");
log::set_max_level(log::LevelFilter::Debug);
}
// TODO: add loop detection by $CHGINTERNALMARK
let code = run().unwrap_or_else(|err| {
writeln!(io::stderr(), "chg: abort: {}", err).unwrap_or(());
255
});
process::exit(code);
}
fn run() -> io::Result<i32> {
let umask = unsafe { procutil::get_umask() }; // not thread safe
let mut loc = Locator::prepare_from_env()?;
loc.set_early_args(locator::collect_early_args(env::args_os().skip(1)));
let handler = ChgUiHandler::new();
let (result_tx, result_rx) = oneshot::channel();
let fut = loc
.connect()
.and_then(|(_, client)| client.attach_io(io::stdin(), io::stdout(), io::stderr()))
.and_then(move |client| client.set_umask(umask))
.and_then(|client| {
let pid = client.server_spec().process_id.unwrap();
let pgid = client.server_spec().process_group_id;
procutil::setup_signal_handler_once(pid, pgid)?;
Ok(client)
})
.and_then(|client| client.run_command_chg(handler, env::args_os().skip(1)))
.map(|(_client, _handler, code)| {
procutil::restore_signal_handler_once()?;
Ok(code)
})
.or_else(|err| Ok(Err(err))) // pass back error to caller
.map(|res| result_tx.send(res).unwrap());
tokio::run(fut);
result_rx.wait().unwrap_or(Err(io::Error::new(
io::ErrorKind::Other,
"no exit code set",
)))
}