rust/hg-core/src/copy_tracing.rs
changeset 45988 ed0e1339e4a8
parent 45987 8b99c473aae2
child 45989 10bb0856bb9f
equal deleted inserted replaced
45987:8b99c473aae2 45988:ed0e1339e4a8
       
     1 use crate::utils::hg_path::HgPath;
     1 use crate::utils::hg_path::HgPathBuf;
     2 use crate::utils::hg_path::HgPathBuf;
     2 use crate::Revision;
     3 use crate::Revision;
     3 
     4 
     4 use im_rc::ordmap::DiffItem;
     5 use im_rc::ordmap::DiffItem;
     5 use im_rc::ordmap::OrdMap;
     6 use im_rc::ordmap::OrdMap;
    32     removed: HashSet<HgPathBuf>,
    33     removed: HashSet<HgPathBuf>,
    33     merged: HashSet<HgPathBuf>,
    34     merged: HashSet<HgPathBuf>,
    34     salvaged: HashSet<HgPathBuf>,
    35     salvaged: HashSet<HgPathBuf>,
    35     copied_from_p1: PathCopies,
    36     copied_from_p1: PathCopies,
    36     copied_from_p2: PathCopies,
    37     copied_from_p2: PathCopies,
       
    38 }
       
    39 
       
    40 /// Represent active changes that affect the copy tracing.
       
    41 enum Action<'a> {
       
    42     /// The parent ? children edge is removing a file
       
    43     ///
       
    44     /// (actually, this could be the edge from the other parent, but it does
       
    45     /// not matters)
       
    46     Removed(&'a HgPath),
       
    47     /// The parent ? children edge introduce copy information between (dest,
       
    48     /// source)
       
    49     Copied(&'a HgPath, &'a HgPath),
    37 }
    50 }
    38 
    51 
    39 impl ChangedFiles {
    52 impl ChangedFiles {
    40     pub fn new(
    53     pub fn new(
    41         removed: HashSet<HgPathBuf>,
    54         removed: HashSet<HgPathBuf>,
    59             merged: HashSet::new(),
    72             merged: HashSet::new(),
    60             salvaged: HashSet::new(),
    73             salvaged: HashSet::new(),
    61             copied_from_p1: PathCopies::new(),
    74             copied_from_p1: PathCopies::new(),
    62             copied_from_p2: PathCopies::new(),
    75             copied_from_p2: PathCopies::new(),
    63         }
    76         }
       
    77     }
       
    78 
       
    79     /// Return an iterator over all the `Action` in this instance.
       
    80     fn iter_actions(&self, parent: usize) -> impl Iterator<Item = Action> {
       
    81         let copies_iter = match parent {
       
    82             1 => self.copied_from_p1.iter(),
       
    83             2 => self.copied_from_p2.iter(),
       
    84             _ => unreachable!(),
       
    85         };
       
    86         let remove_iter = self.removed.iter();
       
    87         let copies_iter = copies_iter.map(|(x, y)| Action::Copied(x, y));
       
    88         let remove_iter = remove_iter.map(|x| Action::Removed(x));
       
    89         copies_iter.chain(remove_iter)
    64     }
    90     }
    65 }
    91 }
    66 
    92 
    67 /// A struct responsible for answering "is X ancestors of Y" quickly
    93 /// A struct responsible for answering "is X ancestors of Y" quickly
    68 ///
    94 ///
   140             // We will chain the copies information accumulated for `rev` with
   166             // We will chain the copies information accumulated for `rev` with
   141             // the individual copies information for each of its children.
   167             // the individual copies information for each of its children.
   142             // Creating a new PathCopies for each `rev` ? `children` vertex.
   168             // Creating a new PathCopies for each `rev` ? `children` vertex.
   143             let (p1, p2, changes) = rev_info(*child);
   169             let (p1, p2, changes) = rev_info(*child);
   144 
   170 
   145             let (parent, child_copies) = if rev == p1 {
   171             let parent = if rev == p1 {
   146                 (1, &changes.copied_from_p1)
   172                 1
   147             } else {
   173             } else {
   148                 assert_eq!(rev, p2);
   174                 assert_eq!(rev, p2);
   149                 (2, &changes.copied_from_p2)
   175                 2
   150             };
   176             };
   151             let mut new_copies = copies.clone();
   177             let mut new_copies = copies.clone();
   152 
   178 
   153             for (dest, source) in child_copies {
   179             for action in changes.iter_actions(parent) {
   154                 let entry;
   180                 match action {
   155                 if let Some(v) = copies.get(source) {
   181                     Action::Copied(dest, source) => {
   156                     entry = match &v.path {
   182                         let entry;
   157                         Some(path) => Some((*(path)).to_owned()),
   183                         if let Some(v) = copies.get(source) {
   158                         None => Some(source.to_owned()),
   184                             entry = match &v.path {
       
   185                                 Some(path) => Some((*(path)).to_owned()),
       
   186                                 None => Some(source.to_owned()),
       
   187                             }
       
   188                         } else {
       
   189                             entry = Some(source.to_owned());
       
   190                         }
       
   191                         // Each new entry is introduced by the children, we
       
   192                         // record this information as we will need it to take
       
   193                         // the right decision when merging conflicting copy
       
   194                         // information. See merge_copies_dict for details.
       
   195                         let ttpc = TimeStampedPathCopy {
       
   196                             rev: *child,
       
   197                             path: entry,
       
   198                         };
       
   199                         new_copies.insert(dest.to_owned(), ttpc);
   159                     }
   200                     }
   160                 } else {
   201                     Action::Removed(f) => {
   161                     entry = Some(source.to_owned());
   202                         // We must drop copy information for removed file.
   162                 }
   203                         //
   163                 // Each new entry is introduced by the children, we record this
   204                         // We need to explicitly record them as dropped to
   164                 // information as we will need it to take the right decision
   205                         // propagate this information when merging two
   165                 // when merging conflicting copy information. See
   206                         // TimeStampedPathCopies object.
   166                 // merge_copies_dict for details.
   207                         if new_copies.contains_key(f.as_ref()) {
   167                 let ttpc = TimeStampedPathCopy {
   208                             let ttpc = TimeStampedPathCopy {
   168                     rev: *child,
   209                                 rev: *child,
   169                     path: entry,
   210                                 path: None,
   170                 };
   211                             };
   171                 new_copies.insert(dest.to_owned(), ttpc);
   212                             new_copies.insert(f.to_owned(), ttpc);
   172             }
   213                         }
   173 
   214                     }
   174             // We must drop copy information for removed file.
       
   175             //
       
   176             // We need to explicitly record them as dropped to propagate this
       
   177             // information when merging two TimeStampedPathCopies object.
       
   178             for f in changes.removed.iter() {
       
   179                 if new_copies.contains_key(f.as_ref()) {
       
   180                     let ttpc = TimeStampedPathCopy {
       
   181                         rev: *child,
       
   182                         path: None,
       
   183                     };
       
   184                     new_copies.insert(f.to_owned(), ttpc);
       
   185                 }
   215                 }
   186             }
   216             }
   187 
   217 
   188             // Merge has two parents needs to combines their copy information.
   218             // Merge has two parents needs to combines their copy information.
   189             //
   219             //