##// END OF EJS Templates
py: error out if a "skip" character was given with non-dict to util.dirs()...
py: error out if a "skip" character was given with non-dict to util.dirs() util.dirs() keeps track of the directories in its input collection. If a "skip" character is given to it, it will assume the input is a dirstate map and it will skip entries that are in the given "skip" state. I think this is used only for skipping removed entries ("r") in the dirtate. The C implementation of util.dirs() errors out if it was given a skip character and a non-dict was passed. The pure implementation simply ignored the request skip state. Let's make it easier to discover bugs here by erroring out in the pure implementation too. Let's also switch to checking for the dict-ness, to make the C implementation (since that's clearly been sufficient for many years). This last change makes test-issue660.t pass on py3 in pure mode, since the old check was for existence of iteritems(), which doesn't exist on py3. Differential Revision: https://phab.mercurial-scm.org/D6669

File last commit:

r40155:e70b616a default
r42864:b5092c23 stable
Show More
uihandler.rs
87 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 futures::Future;
use futures::future::IntoFuture;
use std::io;
use std::os::unix::io::AsRawFd;
use std::os::unix::process::ExitStatusExt;
use std::process::{Command, Stdio};
use tokio;
use tokio_process::{ChildStdin, CommandExt};
use super::message::CommandSpec;
use super::procutil;
/// Callback to process shell command requests received from server.
pub trait SystemHandler: Sized {
type PagerStdin: AsRawFd;
type SpawnPagerResult: IntoFuture<Item = (Self, Self::PagerStdin), Error = io::Error>;
type RunSystemResult: IntoFuture<Item = (Self, i32), Error = io::Error>;
/// Handles pager command request.
///
/// Returns the pipe to be attached to the server if the pager is spawned.
fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult;
/// Handles system command request.
///
/// Returns command exit code (positive) or signal number (negative).
fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult;
}
/// Default cHg implementation to process requests received from server.
pub struct ChgUiHandler {
}
impl ChgUiHandler {
pub fn new() -> ChgUiHandler {
ChgUiHandler {}
}
}
impl SystemHandler for ChgUiHandler {
type PagerStdin = ChildStdin;
type SpawnPagerResult = io::Result<(Self, Self::PagerStdin)>;
type RunSystemResult = Box<dyn Future<Item = (Self, i32), Error = io::Error> + Send>;
fn spawn_pager(self, spec: CommandSpec) -> Self::SpawnPagerResult {
let mut pager = new_shell_command(&spec)
.stdin(Stdio::piped())
.spawn_async()?;
let pin = pager.stdin().take().unwrap();
procutil::set_blocking_fd(pin.as_raw_fd())?;
// TODO: if pager exits, notify the server with SIGPIPE immediately.
// otherwise the server won't get SIGPIPE if it does not write
// anything. (issue5278)
// kill(peerpid, SIGPIPE);
tokio::spawn(pager.map(|_| ()).map_err(|_| ())); // just ignore errors
Ok((self, pin))
}
fn run_system(self, spec: CommandSpec) -> Self::RunSystemResult {
let fut = new_shell_command(&spec)
.spawn_async()
.into_future()
.flatten()
.map(|status| {
let code = status.code().or_else(|| status.signal().map(|n| -n))
.expect("either exit code or signal should be set");
(self, code)
});
Box::new(fut)
}
}
fn new_shell_command(spec: &CommandSpec) -> Command {
let mut builder = Command::new("/bin/sh");
builder
.arg("-c")
.arg(&spec.command)
.current_dir(&spec.current_dir)
.env_clear()
.envs(spec.envs.iter().cloned());
builder
}