Show More
@@ -64,9 +64,9 checksum = "08c48aae112d48ed9f069b33538e | |||
|
64 | 64 | |
|
65 | 65 | [[package]] |
|
66 | 66 | name = "bytes-cast" |
|
67 |
version = "0. |
|
|
67 | version = "0.2.0" | |
|
68 | 68 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
69 | checksum = "3196ba300c7bc9282a4331e878496cb3e9603a898a8f1446601317163e16ca52" | |
|
69 | checksum = "0d434f9a4ecbe987e7ccfda7274b6f82ea52c9b63742565a65cb5e8ba0f2c452" | |
|
70 | 70 | dependencies = [ |
|
71 | 71 | "bytes-cast-derive", |
|
72 | 72 | ] |
@@ -9,7 +9,7 edition = "2018" | |||
|
9 | 9 | name = "hg" |
|
10 | 10 | |
|
11 | 11 | [dependencies] |
|
12 |
bytes-cast = "0. |
|
|
12 | bytes-cast = "0.2" | |
|
13 | 13 | byteorder = "1.3.4" |
|
14 | 14 | derive_more = "0.99" |
|
15 | 15 | home = "0.5" |
@@ -4,7 +4,7 | |||
|
4 | 4 | // GNU General Public License version 2 or any later version. |
|
5 | 5 | |
|
6 | 6 | use crate::errors::HgError; |
|
7 | use crate::utils::hg_path::HgPath; | |
|
7 | use crate::utils::hg_path::{HgPath, HgPathBuf}; | |
|
8 | 8 | use crate::{ |
|
9 | 9 | dirstate::{CopyMap, EntryState, RawEntry, StateMap}, |
|
10 | 10 | DirstateEntry, DirstateParents, |
@@ -82,9 +82,71 pub fn parse_dirstate_entries<'a>( | |||
|
82 | 82 | Ok(parents) |
|
83 | 83 | } |
|
84 | 84 | |
|
85 | fn packed_filename_and_copy_source_size( | |
|
86 | filename: &HgPathBuf, | |
|
87 | copy_source: Option<&HgPathBuf>, | |
|
88 | ) -> usize { | |
|
89 | filename.len() | |
|
90 | + if let Some(source) = copy_source { | |
|
91 | b"\0".len() + source.len() | |
|
92 | } else { | |
|
93 | 0 | |
|
94 | } | |
|
95 | } | |
|
96 | ||
|
97 | pub fn packed_entry_size( | |
|
98 | filename: &HgPathBuf, | |
|
99 | copy_source: Option<&HgPathBuf>, | |
|
100 | ) -> usize { | |
|
101 | MIN_ENTRY_SIZE | |
|
102 | + packed_filename_and_copy_source_size(filename, copy_source) | |
|
103 | } | |
|
104 | ||
|
105 | pub fn pack_entry( | |
|
106 | filename: &HgPathBuf, | |
|
107 | entry: &DirstateEntry, | |
|
108 | copy_source: Option<&HgPathBuf>, | |
|
109 | packed: &mut Vec<u8>, | |
|
110 | ) { | |
|
111 | let length = packed_filename_and_copy_source_size(filename, copy_source); | |
|
112 | ||
|
113 | // Unwrapping because `impl std::io::Write for Vec<u8>` never errors | |
|
114 | packed.write_u8(entry.state.into()).unwrap(); | |
|
115 | packed.write_i32::<BigEndian>(entry.mode).unwrap(); | |
|
116 | packed.write_i32::<BigEndian>(entry.size).unwrap(); | |
|
117 | packed.write_i32::<BigEndian>(entry.mtime).unwrap(); | |
|
118 | packed.write_i32::<BigEndian>(length as i32).unwrap(); | |
|
119 | packed.extend(filename.as_bytes()); | |
|
120 | if let Some(source) = copy_source { | |
|
121 | packed.push(b'\0'); | |
|
122 | packed.extend(source.as_bytes()); | |
|
123 | } | |
|
124 | } | |
|
125 | ||
|
85 | 126 | /// Seconds since the Unix epoch |
|
86 | 127 | pub struct Timestamp(pub u64); |
|
87 | 128 | |
|
129 | pub fn clear_ambiguous_mtime( | |
|
130 | entry: &mut DirstateEntry, | |
|
131 | mtime_now: i32, | |
|
132 | ) -> bool { | |
|
133 | let ambiguous = | |
|
134 | entry.state == EntryState::Normal && entry.mtime == mtime_now; | |
|
135 | if ambiguous { | |
|
136 | // The file was last modified "simultaneously" with the current | |
|
137 | // write to dirstate (i.e. within the same second for file- | |
|
138 | // systems with a granularity of 1 sec). This commonly happens | |
|
139 | // for at least a couple of files on 'update'. | |
|
140 | // The user could change the file without changing its size | |
|
141 | // within the same second. Invalidate the file's mtime in | |
|
142 | // dirstate, forcing future 'status' calls to compare the | |
|
143 | // contents of the file if the size is the same. This prevents | |
|
144 | // mistakenly treating such files as clean. | |
|
145 | entry.mtime = -1; | |
|
146 | } | |
|
147 | ambiguous | |
|
148 | } | |
|
149 | ||
|
88 | 150 | pub fn pack_dirstate( |
|
89 | 151 | state_map: &mut StateMap, |
|
90 | 152 | copy_map: &CopyMap, |
@@ -97,11 +159,7 pub fn pack_dirstate( | |||
|
97 | 159 | let expected_size: usize = state_map |
|
98 | 160 | .iter() |
|
99 | 161 | .map(|(filename, _)| { |
|
100 | let mut length = MIN_ENTRY_SIZE + filename.len(); | |
|
101 | if let Some(copy) = copy_map.get(filename) { | |
|
102 | length += copy.len() + 1; | |
|
103 | } | |
|
104 | length | |
|
162 | packed_entry_size(filename, copy_map.get(filename)) | |
|
105 | 163 | }) |
|
106 | 164 | .sum(); |
|
107 | 165 | let expected_size = expected_size + PARENT_SIZE * 2; |
@@ -112,39 +170,8 pub fn pack_dirstate( | |||
|
112 | 170 | packed.extend(parents.p2.as_bytes()); |
|
113 | 171 | |
|
114 | 172 | for (filename, entry) in state_map.iter_mut() { |
|
115 | let new_filename = filename.to_owned(); | |
|
116 | let mut new_mtime: i32 = entry.mtime; | |
|
117 | if entry.state == EntryState::Normal && entry.mtime == now { | |
|
118 | // The file was last modified "simultaneously" with the current | |
|
119 | // write to dirstate (i.e. within the same second for file- | |
|
120 | // systems with a granularity of 1 sec). This commonly happens | |
|
121 | // for at least a couple of files on 'update'. | |
|
122 | // The user could change the file without changing its size | |
|
123 | // within the same second. Invalidate the file's mtime in | |
|
124 | // dirstate, forcing future 'status' calls to compare the | |
|
125 | // contents of the file if the size is the same. This prevents | |
|
126 | // mistakenly treating such files as clean. | |
|
127 | new_mtime = -1; | |
|
128 | *entry = DirstateEntry { | |
|
129 | mtime: new_mtime, | |
|
130 | ..*entry | |
|
131 | }; | |
|
132 | } | |
|
133 | let mut new_filename = new_filename.into_vec(); | |
|
134 | if let Some(copy) = copy_map.get(filename) { | |
|
135 | new_filename.push(b'\0'); | |
|
136 | new_filename.extend(copy.bytes()); | |
|
137 | } | |
|
138 | ||
|
139 | // Unwrapping because `impl std::io::Write for Vec<u8>` never errors | |
|
140 | packed.write_u8(entry.state.into()).unwrap(); | |
|
141 | packed.write_i32::<BigEndian>(entry.mode).unwrap(); | |
|
142 | packed.write_i32::<BigEndian>(entry.size).unwrap(); | |
|
143 | packed.write_i32::<BigEndian>(new_mtime).unwrap(); | |
|
144 | packed | |
|
145 | .write_i32::<BigEndian>(new_filename.len() as i32) | |
|
146 | .unwrap(); | |
|
147 | packed.extend(new_filename) | |
|
173 | clear_ambiguous_mtime(entry, now); | |
|
174 | pack_entry(filename, entry, copy_map.get(filename), &mut packed) | |
|
148 | 175 | } |
|
149 | 176 | |
|
150 | 177 | if packed.len() != expected_size { |
@@ -1,11 +1,14 | |||
|
1 | use std::collections::BTreeMap; | |
|
1 | use bytes_cast::BytesCast; | |
|
2 | 2 | use std::path::PathBuf; |
|
3 | use std::{collections::BTreeMap, convert::TryInto}; | |
|
3 | 4 | |
|
4 | 5 | use super::path_with_basename::WithBasename; |
|
6 | use crate::dirstate::parsers::clear_ambiguous_mtime; | |
|
7 | use crate::dirstate::parsers::pack_entry; | |
|
8 | use crate::dirstate::parsers::packed_entry_size; | |
|
5 | 9 | use crate::dirstate::parsers::parse_dirstate_entries; |
|
6 | 10 | use crate::dirstate::parsers::parse_dirstate_parents; |
|
7 | 11 | use crate::dirstate::parsers::Timestamp; |
|
8 | ||
|
9 | 12 | use crate::matchers::Matcher; |
|
10 | 13 | use crate::revlog::node::NULL_NODE; |
|
11 | 14 | use crate::utils::hg_path::{HgPath, HgPathBuf}; |
@@ -327,11 +330,38 impl super::dispatch::DirstateMapMethods | |||
|
327 | 330 | |
|
328 | 331 | fn pack( |
|
329 | 332 | &mut self, |
|
330 |
|
|
|
331 |
|
|
|
333 | parents: DirstateParents, | |
|
334 | now: Timestamp, | |
|
332 | 335 | ) -> Result<Vec<u8>, DirstateError> { |
|
333 | let _ = self.iter_node_data_mut(); | |
|
334 | todo!() | |
|
336 | // Optizimation (to be measured?): pre-compute size to avoid `Vec` | |
|
337 | // reallocations | |
|
338 | let mut size = parents.as_bytes().len(); | |
|
339 | for (path, node) in self.iter_nodes() { | |
|
340 | if node.entry.is_some() { | |
|
341 | size += packed_entry_size( | |
|
342 | path.full_path(), | |
|
343 | node.copy_source.as_ref(), | |
|
344 | ) | |
|
345 | } | |
|
346 | } | |
|
347 | ||
|
348 | let mut packed = Vec::with_capacity(size); | |
|
349 | packed.extend(parents.as_bytes()); | |
|
350 | ||
|
351 | let now: i32 = now.0.try_into().expect("time overflow"); | |
|
352 | for (path, opt_entry, copy_source) in self.iter_node_data_mut() { | |
|
353 | if let Some(entry) = opt_entry { | |
|
354 | clear_ambiguous_mtime(entry, now); | |
|
355 | pack_entry( | |
|
356 | path.full_path(), | |
|
357 | entry, | |
|
358 | copy_source.as_ref(), | |
|
359 | &mut packed, | |
|
360 | ); | |
|
361 | } | |
|
362 | } | |
|
363 | self.dirty_parents = false; | |
|
364 | Ok(packed) | |
|
335 | 365 | } |
|
336 | 366 | |
|
337 | 367 | fn build_file_fold_map(&mut self) -> &FastHashMap<HgPathBuf, HgPathBuf> { |
General Comments 0
You need to be logged in to leave comments.
Login now