##// END OF EJS Templates
copies: follow copies across merge base without source file (issue6163)...
copies: follow copies across merge base without source file (issue6163) As in the previous patch, consider these two histories: @ 4 'rename x to y' | o 3 'add x again' | o 2 'remove x' | | o 1 'modify x' |/ o 0 'add x' @ 4 'rename x to y' | o 3 'add x again' | | o 2 'modify x' | | | o 1 'add x' |/ o 0 'base' We trace copies from the 'modify x' commit to commit 4 by going via the merge base (commit 0). When tracing file 'y' (_tracefile()) in the first case, we immediately find the rename from 'x'. We check to see if 'x' exists in the merge base, which it does, so we consider it a valid copy. In the second case, 'x' does not exist in the merge base, so it's not considered a valid copy. As a workaround, this patch makes it so we also attempt the check in mergecopies's base commit (commit 1 in the second case). That feels pretty ugly to me, but I don't have any better ideas. Note that we actually also check not only that the filename matches, but also that the file's nodeid matches. I don't know why we do that, but it was like that already before I rewrote mergecopies(). That means that the rebase will still fail in cases like this (again, it already failed before my rewrite): @ 4 'rename x to y' | o 3 'add x again with content X2' | o 2 'remove x' | | o 1 'modify x to content X2' |/ o 1 'modify x to content X1' | o 0 'add x with content X0' Differential Revision: https://phab.mercurial-scm.org/D6604

File last commit:

r40155:e70b616a default
r42798:819712de default
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
}