rust/hg-core/src/dirstate/parsers.rs
changeset 48083 bf8837e3d7ce
parent 48044 f2a9db29cb2d
child 48271 269ff8978086
equal deleted inserted replaced
48082:d3eb5f50052c 48083:bf8837e3d7ce
     3 // This software may be used and distributed according to the terms of the
     3 // This software may be used and distributed according to the terms of the
     4 // GNU General Public License version 2 or any later version.
     4 // GNU General Public License version 2 or any later version.
     5 
     5 
     6 use crate::errors::HgError;
     6 use crate::errors::HgError;
     7 use crate::utils::hg_path::HgPath;
     7 use crate::utils::hg_path::HgPath;
     8 use crate::{
     8 use crate::{dirstate::EntryState, DirstateEntry, DirstateParents};
     9     dirstate::{CopyMap, EntryState, StateMap},
       
    10     DirstateEntry, DirstateParents,
       
    11 };
       
    12 use byteorder::{BigEndian, WriteBytesExt};
     9 use byteorder::{BigEndian, WriteBytesExt};
    13 use bytes_cast::{unaligned, BytesCast};
    10 use bytes_cast::{unaligned, BytesCast};
    14 use micro_timer::timed;
    11 use micro_timer::timed;
    15 use std::convert::{TryFrom, TryInto};
    12 use std::convert::TryFrom;
    16 
    13 
    17 /// Parents are stored in the dirstate as byte hashes.
    14 /// Parents are stored in the dirstate as byte hashes.
    18 pub const PARENT_SIZE: usize = 20;
    15 pub const PARENT_SIZE: usize = 20;
    19 /// Dirstate entries have a static part of 8 + 32 + 32 + 32 + 32 bits.
    16 /// Dirstate entries have a static part of 8 + 32 + 32 + 32 + 32 bits.
    20 const MIN_ENTRY_SIZE: usize = 17;
    17 const MIN_ENTRY_SIZE: usize = 17;
   139     }
   136     }
   140 }
   137 }
   141 
   138 
   142 /// Seconds since the Unix epoch
   139 /// Seconds since the Unix epoch
   143 pub struct Timestamp(pub i64);
   140 pub struct Timestamp(pub i64);
   144 
       
   145 pub fn pack_dirstate(
       
   146     state_map: &mut StateMap,
       
   147     copy_map: &CopyMap,
       
   148     parents: DirstateParents,
       
   149     now: Timestamp,
       
   150 ) -> Result<Vec<u8>, HgError> {
       
   151     // TODO move away from i32 before 2038.
       
   152     let now: i32 = now.0.try_into().expect("time overflow");
       
   153 
       
   154     let expected_size: usize = state_map
       
   155         .iter()
       
   156         .map(|(filename, _)| {
       
   157             packed_entry_size(filename, copy_map.get(filename).map(|p| &**p))
       
   158         })
       
   159         .sum();
       
   160     let expected_size = expected_size + PARENT_SIZE * 2;
       
   161 
       
   162     let mut packed = Vec::with_capacity(expected_size);
       
   163 
       
   164     packed.extend(parents.p1.as_bytes());
       
   165     packed.extend(parents.p2.as_bytes());
       
   166 
       
   167     for (filename, entry) in state_map.iter_mut() {
       
   168         entry.clear_ambiguous_mtime(now);
       
   169         pack_entry(
       
   170             filename,
       
   171             entry,
       
   172             copy_map.get(filename).map(|p| &**p),
       
   173             &mut packed,
       
   174         )
       
   175     }
       
   176 
       
   177     if packed.len() != expected_size {
       
   178         return Err(HgError::CorruptedRepository(format!(
       
   179             "bad dirstate size: {} != {}",
       
   180             expected_size,
       
   181             packed.len()
       
   182         )));
       
   183     }
       
   184 
       
   185     Ok(packed)
       
   186 }
       
   187 
       
   188 #[cfg(test)]
       
   189 mod tests {
       
   190     use super::*;
       
   191     use crate::{utils::hg_path::HgPathBuf, FastHashMap};
       
   192     use pretty_assertions::assert_eq;
       
   193 
       
   194     #[test]
       
   195     fn test_pack_dirstate_empty() {
       
   196         let mut state_map = StateMap::default();
       
   197         let copymap = FastHashMap::default();
       
   198         let parents = DirstateParents {
       
   199             p1: b"12345678910111213141".into(),
       
   200             p2: b"00000000000000000000".into(),
       
   201         };
       
   202         let now = Timestamp(15000000);
       
   203         let expected = b"1234567891011121314100000000000000000000".to_vec();
       
   204 
       
   205         assert_eq!(
       
   206             expected,
       
   207             pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
       
   208         );
       
   209 
       
   210         assert!(state_map.is_empty())
       
   211     }
       
   212     #[test]
       
   213     fn test_pack_dirstate_one_entry() {
       
   214         let expected_state_map: StateMap = [(
       
   215             HgPathBuf::from_bytes(b"f1"),
       
   216             DirstateEntry::from_v1_data(
       
   217                 EntryState::Normal,
       
   218                 0o644,
       
   219                 0,
       
   220                 791231220,
       
   221             ),
       
   222         )]
       
   223         .iter()
       
   224         .cloned()
       
   225         .collect();
       
   226         let mut state_map = expected_state_map.clone();
       
   227 
       
   228         let copymap = FastHashMap::default();
       
   229         let parents = DirstateParents {
       
   230             p1: b"12345678910111213141".into(),
       
   231             p2: b"00000000000000000000".into(),
       
   232         };
       
   233         let now = Timestamp(15000000);
       
   234         let expected = [
       
   235             49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
       
   236             51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
       
   237             48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
       
   238             41, 58, 244, 0, 0, 0, 2, 102, 49,
       
   239         ]
       
   240         .to_vec();
       
   241 
       
   242         assert_eq!(
       
   243             expected,
       
   244             pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
       
   245         );
       
   246 
       
   247         assert_eq!(expected_state_map, state_map);
       
   248     }
       
   249     #[test]
       
   250     fn test_pack_dirstate_one_entry_with_copy() {
       
   251         let expected_state_map: StateMap = [(
       
   252             HgPathBuf::from_bytes(b"f1"),
       
   253             DirstateEntry::from_v1_data(
       
   254                 EntryState::Normal,
       
   255                 0o644,
       
   256                 0,
       
   257                 791231220,
       
   258             ),
       
   259         )]
       
   260         .iter()
       
   261         .cloned()
       
   262         .collect();
       
   263         let mut state_map = expected_state_map.clone();
       
   264         let mut copymap = FastHashMap::default();
       
   265         copymap.insert(
       
   266             HgPathBuf::from_bytes(b"f1"),
       
   267             HgPathBuf::from_bytes(b"copyname"),
       
   268         );
       
   269         let parents = DirstateParents {
       
   270             p1: b"12345678910111213141".into(),
       
   271             p2: b"00000000000000000000".into(),
       
   272         };
       
   273         let now = Timestamp(15000000);
       
   274         let expected = [
       
   275             49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
       
   276             51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
       
   277             48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
       
   278             41, 58, 244, 0, 0, 0, 11, 102, 49, 0, 99, 111, 112, 121, 110, 97,
       
   279             109, 101,
       
   280         ]
       
   281         .to_vec();
       
   282 
       
   283         assert_eq!(
       
   284             expected,
       
   285             pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
       
   286         );
       
   287         assert_eq!(expected_state_map, state_map);
       
   288     }
       
   289 
       
   290     #[test]
       
   291     fn test_parse_pack_one_entry_with_copy() {
       
   292         let mut state_map: StateMap = [(
       
   293             HgPathBuf::from_bytes(b"f1"),
       
   294             DirstateEntry::from_v1_data(
       
   295                 EntryState::Normal,
       
   296                 0o644,
       
   297                 0,
       
   298                 791231220,
       
   299             ),
       
   300         )]
       
   301         .iter()
       
   302         .cloned()
       
   303         .collect();
       
   304         let mut copymap = FastHashMap::default();
       
   305         copymap.insert(
       
   306             HgPathBuf::from_bytes(b"f1"),
       
   307             HgPathBuf::from_bytes(b"copyname"),
       
   308         );
       
   309         let parents = DirstateParents {
       
   310             p1: b"12345678910111213141".into(),
       
   311             p2: b"00000000000000000000".into(),
       
   312         };
       
   313         let now = Timestamp(15000000);
       
   314         let result =
       
   315             pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
       
   316                 .unwrap();
       
   317 
       
   318         let (new_parents, entries, copies) =
       
   319             parse_dirstate(result.as_slice()).unwrap();
       
   320         let new_state_map: StateMap = entries
       
   321             .into_iter()
       
   322             .map(|(path, entry)| (path.to_owned(), entry))
       
   323             .collect();
       
   324         let new_copy_map: CopyMap = copies
       
   325             .into_iter()
       
   326             .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
       
   327             .collect();
       
   328 
       
   329         assert_eq!(
       
   330             (&parents, state_map, copymap),
       
   331             (new_parents, new_state_map, new_copy_map)
       
   332         )
       
   333     }
       
   334 
       
   335     #[test]
       
   336     fn test_parse_pack_multiple_entries_with_copy() {
       
   337         let mut state_map: StateMap = [
       
   338             (
       
   339                 HgPathBuf::from_bytes(b"f1"),
       
   340                 DirstateEntry::from_v1_data(
       
   341                     EntryState::Normal,
       
   342                     0o644,
       
   343                     0,
       
   344                     791231220,
       
   345                 ),
       
   346             ),
       
   347             (
       
   348                 HgPathBuf::from_bytes(b"f2"),
       
   349                 DirstateEntry::from_v1_data(
       
   350                     EntryState::Merged,
       
   351                     0o777,
       
   352                     1000,
       
   353                     791231220,
       
   354                 ),
       
   355             ),
       
   356             (
       
   357                 HgPathBuf::from_bytes(b"f3"),
       
   358                 DirstateEntry::from_v1_data(
       
   359                     EntryState::Removed,
       
   360                     0o644,
       
   361                     234553,
       
   362                     791231220,
       
   363                 ),
       
   364             ),
       
   365             (
       
   366                 HgPathBuf::from_bytes(b"f4\xF6"),
       
   367                 DirstateEntry::from_v1_data(EntryState::Added, 0o644, -1, -1),
       
   368             ),
       
   369         ]
       
   370         .iter()
       
   371         .cloned()
       
   372         .collect();
       
   373         let mut copymap = FastHashMap::default();
       
   374         copymap.insert(
       
   375             HgPathBuf::from_bytes(b"f1"),
       
   376             HgPathBuf::from_bytes(b"copyname"),
       
   377         );
       
   378         copymap.insert(
       
   379             HgPathBuf::from_bytes(b"f4\xF6"),
       
   380             HgPathBuf::from_bytes(b"copyname2"),
       
   381         );
       
   382         let parents = DirstateParents {
       
   383             p1: b"12345678910111213141".into(),
       
   384             p2: b"00000000000000000000".into(),
       
   385         };
       
   386         let now = Timestamp(15000000);
       
   387         let result =
       
   388             pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
       
   389                 .unwrap();
       
   390 
       
   391         let (new_parents, entries, copies) =
       
   392             parse_dirstate(result.as_slice()).unwrap();
       
   393         let new_state_map: StateMap = entries
       
   394             .into_iter()
       
   395             .map(|(path, entry)| (path.to_owned(), entry))
       
   396             .collect();
       
   397         let new_copy_map: CopyMap = copies
       
   398             .into_iter()
       
   399             .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
       
   400             .collect();
       
   401 
       
   402         assert_eq!(
       
   403             (&parents, state_map, copymap),
       
   404             (new_parents, new_state_map, new_copy_map)
       
   405         )
       
   406     }
       
   407 
       
   408     #[test]
       
   409     /// https://www.mercurial-scm.org/repo/hg/rev/af3f26b6bba4
       
   410     fn test_parse_pack_one_entry_with_copy_and_time_conflict() {
       
   411         let mut state_map: StateMap = [(
       
   412             HgPathBuf::from_bytes(b"f1"),
       
   413             DirstateEntry::from_v1_data(
       
   414                 EntryState::Normal,
       
   415                 0o644,
       
   416                 0,
       
   417                 15000000,
       
   418             ),
       
   419         )]
       
   420         .iter()
       
   421         .cloned()
       
   422         .collect();
       
   423         let mut copymap = FastHashMap::default();
       
   424         copymap.insert(
       
   425             HgPathBuf::from_bytes(b"f1"),
       
   426             HgPathBuf::from_bytes(b"copyname"),
       
   427         );
       
   428         let parents = DirstateParents {
       
   429             p1: b"12345678910111213141".into(),
       
   430             p2: b"00000000000000000000".into(),
       
   431         };
       
   432         let now = Timestamp(15000000);
       
   433         let result =
       
   434             pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
       
   435                 .unwrap();
       
   436 
       
   437         let (new_parents, entries, copies) =
       
   438             parse_dirstate(result.as_slice()).unwrap();
       
   439         let new_state_map: StateMap = entries
       
   440             .into_iter()
       
   441             .map(|(path, entry)| (path.to_owned(), entry))
       
   442             .collect();
       
   443         let new_copy_map: CopyMap = copies
       
   444             .into_iter()
       
   445             .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
       
   446             .collect();
       
   447 
       
   448         assert_eq!(
       
   449             (
       
   450                 &parents,
       
   451                 [(
       
   452                     HgPathBuf::from_bytes(b"f1"),
       
   453                     DirstateEntry::from_v1_data(
       
   454                         EntryState::Normal,
       
   455                         0o644,
       
   456                         0,
       
   457                         -1
       
   458                     )
       
   459                 )]
       
   460                 .iter()
       
   461                 .cloned()
       
   462                 .collect::<StateMap>(),
       
   463                 copymap,
       
   464             ),
       
   465             (new_parents, new_state_map, new_copy_map)
       
   466         )
       
   467     }
       
   468 }