Changeset View
Changeset View
Standalone View
Standalone View
rust/hg-core/src/copy_tracing.rs
Show All 10 Lines | |||||
use std::collections::HashMap; | use std::collections::HashMap; | ||||
use std::convert::TryInto; | use std::convert::TryInto; | ||||
pub type PathCopies = HashMap<HgPathBuf, HgPathBuf>; | pub type PathCopies = HashMap<HgPathBuf, HgPathBuf>; | ||||
type PathToken = usize; | type PathToken = usize; | ||||
#[derive(Clone, Debug, PartialEq, Copy)] | #[derive(Clone, Debug, PartialEq, Copy)] | ||||
struct TimeStampedPathCopy { | struct CopySource { | ||||
/// revision at which the copy information was added | /// revision at which the copy information was added | ||||
rev: Revision, | rev: Revision, | ||||
/// the copy source, (Set to None in case of deletion of the associated | /// the copy source, (Set to None in case of deletion of the associated | ||||
/// key) | /// key) | ||||
path: Option<PathToken>, | path: Option<PathToken>, | ||||
} | } | ||||
/// maps CopyDestination to Copy Source (+ a "timestamp" for the operation) | /// maps CopyDestination to Copy Source (+ a "timestamp" for the operation) | ||||
type InternalPathCopies = OrdMap<PathToken, TimeStampedPathCopy>; | type InternalPathCopies = OrdMap<PathToken, CopySource>; | ||||
/// hold parent 1, parent 2 and relevant files actions. | /// hold parent 1, parent 2 and relevant files actions. | ||||
pub type RevInfo<'a> = (Revision, Revision, ChangedFiles<'a>); | pub type RevInfo<'a> = (Revision, Revision, ChangedFiles<'a>); | ||||
/// represent the files affected by a changesets | /// represent the files affected by a changesets | ||||
/// | /// | ||||
/// This hold a subset of mercurial.metadata.ChangingFiles as we do not need | /// This hold a subset of mercurial.metadata.ChangingFiles as we do not need | ||||
/// all the data categories tracked by it. | /// all the data categories tracked by it. | ||||
▲ Show 20 Lines • Show All 479 Lines • ▼ Show 20 Line(s) | for action in changes.iter_actions(parent) { | ||||
entry = Some(source.to_owned()); | entry = Some(source.to_owned()); | ||||
} | } | ||||
// Each new entry is introduced by the children, we | // Each new entry is introduced by the children, we | ||||
// record this information as we will need it to take | // record this information as we will need it to take | ||||
// the right decision when merging conflicting copy | // the right decision when merging conflicting copy | ||||
// information. See merge_copies_dict for details. | // information. See merge_copies_dict for details. | ||||
match copies.entry(dest) { | match copies.entry(dest) { | ||||
Entry::Vacant(slot) => { | Entry::Vacant(slot) => { | ||||
let ttpc = TimeStampedPathCopy { | let ttpc = CopySource { | ||||
rev: current_rev, | rev: current_rev, | ||||
path: entry, | path: entry, | ||||
}; | }; | ||||
slot.insert(ttpc); | slot.insert(ttpc); | ||||
} | } | ||||
Entry::Occupied(mut slot) => { | Entry::Occupied(mut slot) => { | ||||
let mut ttpc = slot.get_mut(); | let mut ttpc = slot.get_mut(); | ||||
oracle.record_overwrite(ttpc.rev, current_rev); | oracle.record_overwrite(ttpc.rev, current_rev); | ||||
Show All 32 Lines | fn merge_copies_dict<A: Fn(Revision, Revision) -> bool>( | ||||
changes: &ChangedFiles, | changes: &ChangedFiles, | ||||
oracle: &mut AncestorOracle<A>, | oracle: &mut AncestorOracle<A>, | ||||
) -> InternalPathCopies { | ) -> InternalPathCopies { | ||||
// This closure exist as temporary help while multiple developper are | // This closure exist as temporary help while multiple developper are | ||||
// actively working on this code. Feel free to re-inline it once this | // actively working on this code. Feel free to re-inline it once this | ||||
// code is more settled. | // code is more settled. | ||||
let cmp_value = |oracle: &mut AncestorOracle<A>, | let cmp_value = |oracle: &mut AncestorOracle<A>, | ||||
dest: &PathToken, | dest: &PathToken, | ||||
src_minor: &TimeStampedPathCopy, | src_minor: &CopySource, | ||||
src_major: &TimeStampedPathCopy| { | src_major: &CopySource| { | ||||
compare_value( | compare_value( | ||||
path_map, | path_map, | ||||
current_merge, | current_merge, | ||||
changes, | changes, | ||||
oracle, | oracle, | ||||
dest, | dest, | ||||
src_minor, | src_minor, | ||||
src_major, | src_major, | ||||
Show All 31 Lines | if minor.is_empty() { | ||||
if overwrite { | if overwrite { | ||||
oracle.record_overwrite(src_minor.rev, current_merge); | oracle.record_overwrite(src_minor.rev, current_merge); | ||||
oracle.record_overwrite(src_major.rev, current_merge); | oracle.record_overwrite(src_major.rev, current_merge); | ||||
let path = match pick { | let path = match pick { | ||||
MergePick::Major => src_major.path, | MergePick::Major => src_major.path, | ||||
MergePick::Minor => src_minor.path, | MergePick::Minor => src_minor.path, | ||||
MergePick::Any => src_major.path, | MergePick::Any => src_major.path, | ||||
}; | }; | ||||
let src = TimeStampedPathCopy { | let src = CopySource { | ||||
rev: current_merge, | rev: current_merge, | ||||
path, | path, | ||||
}; | }; | ||||
major.insert(dest, src); | major.insert(dest, src); | ||||
} else { | } else { | ||||
match pick { | match pick { | ||||
MergePick::Any | MergePick::Major => None, | MergePick::Any | MergePick::Major => None, | ||||
MergePick::Minor => major.insert(dest, src_minor), | MergePick::Minor => major.insert(dest, src_minor), | ||||
Show All 18 Lines | if minor.is_empty() { | ||||
if overwrite { | if overwrite { | ||||
oracle.record_overwrite(src_minor.rev, current_merge); | oracle.record_overwrite(src_minor.rev, current_merge); | ||||
oracle.record_overwrite(src_major.rev, current_merge); | oracle.record_overwrite(src_major.rev, current_merge); | ||||
let path = match pick { | let path = match pick { | ||||
MergePick::Major => src_minor.path, | MergePick::Major => src_minor.path, | ||||
MergePick::Minor => src_major.path, | MergePick::Minor => src_major.path, | ||||
MergePick::Any => src_major.path, | MergePick::Any => src_major.path, | ||||
}; | }; | ||||
let src = TimeStampedPathCopy { | let src = CopySource { | ||||
rev: current_merge, | rev: current_merge, | ||||
path, | path, | ||||
}; | }; | ||||
minor.insert(dest, src); | minor.insert(dest, src); | ||||
} else { | } else { | ||||
match pick { | match pick { | ||||
MergePick::Any | MergePick::Major => None, | MergePick::Any | MergePick::Major => None, | ||||
MergePick::Minor => minor.insert(dest, src_major), | MergePick::Minor => minor.insert(dest, src_major), | ||||
}; | }; | ||||
} | } | ||||
} | } | ||||
}; | }; | ||||
} | } | ||||
minor | minor | ||||
} else { | } else { | ||||
let mut override_minor = Vec::new(); | let mut override_minor = Vec::new(); | ||||
let mut override_major = Vec::new(); | let mut override_major = Vec::new(); | ||||
let mut to_major = |k: &PathToken, v: &TimeStampedPathCopy| { | let mut to_major = |k: &PathToken, v: &CopySource| { | ||||
override_major.push((k.clone(), v.clone())) | override_major.push((k.clone(), v.clone())) | ||||
}; | }; | ||||
let mut to_minor = |k: &PathToken, v: &TimeStampedPathCopy| { | let mut to_minor = |k: &PathToken, v: &CopySource| { | ||||
override_minor.push((k.clone(), v.clone())) | override_minor.push((k.clone(), v.clone())) | ||||
}; | }; | ||||
// The diff function leverage detection of the identical subpart if | // The diff function leverage detection of the identical subpart if | ||||
// minor and major has some common ancestors. This make it very | // minor and major has some common ancestors. This make it very | ||||
// fast is most case. | // fast is most case. | ||||
// | // | ||||
// In case where the two map are vastly different in size, the current | // In case where the two map are vastly different in size, the current | ||||
Show All 20 Lines | if minor.is_empty() { | ||||
oracle.record_overwrite(src_major.rev, current_merge); | oracle.record_overwrite(src_major.rev, current_merge); | ||||
let path = match pick { | let path = match pick { | ||||
MergePick::Major => src_major.path, | MergePick::Major => src_major.path, | ||||
MergePick::Minor => src_minor.path, | MergePick::Minor => src_minor.path, | ||||
// If the two entry are identical, no need to do | // If the two entry are identical, no need to do | ||||
// anything (but diff should not have yield them) | // anything (but diff should not have yield them) | ||||
MergePick::Any => src_major.path, | MergePick::Any => src_major.path, | ||||
}; | }; | ||||
let src = TimeStampedPathCopy { | let src = CopySource { | ||||
rev: current_merge, | rev: current_merge, | ||||
path, | path, | ||||
}; | }; | ||||
to_minor(dest, &src); | to_minor(dest, &src); | ||||
to_major(dest, &src); | to_major(dest, &src); | ||||
} else { | } else { | ||||
match pick { | match pick { | ||||
MergePick::Major => to_minor(dest, src_major), | MergePick::Major => to_minor(dest, src_major), | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Line(s) | |||||
/// decide which side prevails in case of conflicting values | /// decide which side prevails in case of conflicting values | ||||
#[allow(clippy::if_same_then_else)] | #[allow(clippy::if_same_then_else)] | ||||
fn compare_value<A: Fn(Revision, Revision) -> bool>( | fn compare_value<A: Fn(Revision, Revision) -> bool>( | ||||
path_map: &TwoWayPathMap, | path_map: &TwoWayPathMap, | ||||
current_merge: Revision, | current_merge: Revision, | ||||
changes: &ChangedFiles, | changes: &ChangedFiles, | ||||
oracle: &mut AncestorOracle<A>, | oracle: &mut AncestorOracle<A>, | ||||
dest: &PathToken, | dest: &PathToken, | ||||
src_minor: &TimeStampedPathCopy, | src_minor: &CopySource, | ||||
src_major: &TimeStampedPathCopy, | src_major: &CopySource, | ||||
) -> (MergePick, bool) { | ) -> (MergePick, bool) { | ||||
if src_major.rev == current_merge { | if src_major.rev == current_merge { | ||||
if src_minor.rev == current_merge { | if src_minor.rev == current_merge { | ||||
if src_major.path.is_none() { | if src_major.path.is_none() { | ||||
// We cannot get different copy information for both p1 and p2 | // We cannot get different copy information for both p1 and p2 | ||||
// from the same revision. Unless this was a | // from the same revision. Unless this was a | ||||
// deletion | // deletion | ||||
(MergePick::Any, false) | (MergePick::Any, false) | ||||
▲ Show 20 Lines • Show All 86 Lines • Show Last 20 Lines |