Show More
@@ -1,16 +1,25 b'' | |||||
|
1 | // dirstate module | |||
|
2 | // | |||
|
3 | // Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | |||
|
4 | // | |||
|
5 | // This software may be used and distributed according to the terms of the | |||
|
6 | // GNU General Public License version 2 or any later version. | |||
|
7 | ||||
|
8 | use std::collections::HashMap; | |||
|
9 | ||||
1 | pub mod dirs_multiset; |
|
10 | pub mod dirs_multiset; | |
2 | pub mod parsers; |
|
11 | pub mod parsers; | |
3 |
|
12 | |||
4 |
#[derive(Debug, PartialEq, C |
|
13 | #[derive(Debug, PartialEq, Clone)] | |
5 |
pub struct DirstateParents |
|
14 | pub struct DirstateParents { | |
6 |
pub p1: |
|
15 | pub p1: [u8; 20], | |
7 |
pub p2: |
|
16 | pub p2: [u8; 20], | |
8 | } |
|
17 | } | |
9 |
|
18 | |||
10 | /// The C implementation uses all signed types. This will be an issue |
|
19 | /// The C implementation uses all signed types. This will be an issue | |
11 | /// either when 4GB+ source files are commonplace or in 2038, whichever |
|
20 | /// either when 4GB+ source files are commonplace or in 2038, whichever | |
12 | /// comes first. |
|
21 | /// comes first. | |
13 | #[derive(Debug, PartialEq)] |
|
22 | #[derive(Debug, PartialEq, Copy, Clone)] | |
14 | pub struct DirstateEntry { |
|
23 | pub struct DirstateEntry { | |
15 | pub state: i8, |
|
24 | pub state: i8, | |
16 | pub mode: i32, |
|
25 | pub mode: i32, | |
@@ -18,19 +27,12 b' pub struct DirstateEntry {' | |||||
18 | pub size: i32, |
|
27 | pub size: i32, | |
19 | } |
|
28 | } | |
20 |
|
29 | |||
21 |
pub type |
|
30 | pub type StateMap = HashMap<Vec<u8>, DirstateEntry>; | |
22 |
|
31 | pub type CopyMap = HashMap<Vec<u8>, Vec<u8>>; | ||
23 | #[derive(Debug, PartialEq)] |
|
|||
24 | pub struct CopyVecEntry<'a> { |
|
|||
25 | pub path: &'a [u8], |
|
|||
26 | pub copy_path: &'a [u8], |
|
|||
27 | } |
|
|||
28 |
|
||||
29 | pub type CopyVec<'a> = Vec<CopyVecEntry<'a>>; |
|
|||
30 |
|
32 | |||
31 | /// The Python implementation passes either a mapping (dirstate) or a flat |
|
33 | /// The Python implementation passes either a mapping (dirstate) or a flat | |
32 | /// iterable (manifest) |
|
34 | /// iterable (manifest) | |
33 | pub enum DirsIterable { |
|
35 | pub enum DirsIterable<'a> { | |
34 |
Dirstate(Dirstate |
|
36 | Dirstate(&'a HashMap<Vec<u8>, DirstateEntry>), | |
35 | Manifest(Vec<Vec<u8>>), |
|
37 | Manifest(&'a Vec<Vec<u8>>), | |
36 | } |
|
38 | } |
@@ -28,10 +28,10 b' impl DirsMultiset {' | |||||
28 |
|
28 | |||
29 | match iterable { |
|
29 | match iterable { | |
30 | DirsIterable::Dirstate(vec) => { |
|
30 | DirsIterable::Dirstate(vec) => { | |
31 |
for ( |
|
31 | for (filename, DirstateEntry { state, .. }) in vec { | |
32 | // This `if` is optimized out of the loop |
|
32 | // This `if` is optimized out of the loop | |
33 | if let Some(skip) = skip_state { |
|
33 | if let Some(skip) = skip_state { | |
34 | if skip != state { |
|
34 | if skip != *state { | |
35 | multiset.add_path(filename); |
|
35 | multiset.add_path(filename); | |
36 | } |
|
36 | } | |
37 | } else { |
|
37 | } else { | |
@@ -40,7 +40,7 b' impl DirsMultiset {' | |||||
40 | } |
|
40 | } | |
41 | } |
|
41 | } | |
42 | DirsIterable::Manifest(vec) => { |
|
42 | DirsIterable::Manifest(vec) => { | |
43 |
for |
|
43 | for filename in vec { | |
44 | multiset.add_path(filename); |
|
44 | multiset.add_path(filename); | |
45 | } |
|
45 | } | |
46 | } |
|
46 | } | |
@@ -108,10 +108,11 b' impl DirsMultiset {' | |||||
108 | #[cfg(test)] |
|
108 | #[cfg(test)] | |
109 | mod tests { |
|
109 | mod tests { | |
110 | use super::*; |
|
110 | use super::*; | |
|
111 | use std::collections::HashMap; | |||
111 |
|
112 | |||
112 | #[test] |
|
113 | #[test] | |
113 | fn test_delete_path_path_not_found() { |
|
114 | fn test_delete_path_path_not_found() { | |
114 | let mut map = DirsMultiset::new(DirsIterable::Manifest(vec![]), None); |
|
115 | let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None); | |
115 | let path = b"doesnotexist/"; |
|
116 | let path = b"doesnotexist/"; | |
116 | assert_eq!( |
|
117 | assert_eq!( | |
117 | Err(DirstateMapError::PathNotFound(path.to_vec())), |
|
118 | Err(DirstateMapError::PathNotFound(path.to_vec())), | |
@@ -122,7 +123,7 b' mod tests {' | |||||
122 | #[test] |
|
123 | #[test] | |
123 | fn test_delete_path_empty_path() { |
|
124 | fn test_delete_path_empty_path() { | |
124 | let mut map = |
|
125 | let mut map = | |
125 | DirsMultiset::new(DirsIterable::Manifest(vec![vec![]]), None); |
|
126 | DirsMultiset::new(DirsIterable::Manifest(&vec![vec![]]), None); | |
126 | let path = b""; |
|
127 | let path = b""; | |
127 | assert_eq!(Ok(()), map.delete_path(path)); |
|
128 | assert_eq!(Ok(()), map.delete_path(path)); | |
128 | assert_eq!( |
|
129 | assert_eq!( | |
@@ -162,7 +163,7 b' mod tests {' | |||||
162 |
|
163 | |||
163 | #[test] |
|
164 | #[test] | |
164 | fn test_add_path_empty_path() { |
|
165 | fn test_add_path_empty_path() { | |
165 | let mut map = DirsMultiset::new(DirsIterable::Manifest(vec![]), None); |
|
166 | let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None); | |
166 | let path = b""; |
|
167 | let path = b""; | |
167 | map.add_path(path); |
|
168 | map.add_path(path); | |
168 |
|
169 | |||
@@ -171,7 +172,7 b' mod tests {' | |||||
171 |
|
172 | |||
172 | #[test] |
|
173 | #[test] | |
173 | fn test_add_path_successful() { |
|
174 | fn test_add_path_successful() { | |
174 | let mut map = DirsMultiset::new(DirsIterable::Manifest(vec![]), None); |
|
175 | let mut map = DirsMultiset::new(DirsIterable::Manifest(&vec![]), None); | |
175 |
|
176 | |||
176 | map.add_path(b"a/"); |
|
177 | map.add_path(b"a/"); | |
177 | assert_eq!(1, *map.inner.get(&b"a".to_vec()).unwrap()); |
|
178 | assert_eq!(1, *map.inner.get(&b"a".to_vec()).unwrap()); | |
@@ -218,13 +219,13 b' mod tests {' | |||||
218 | fn test_dirsmultiset_new_empty() { |
|
219 | fn test_dirsmultiset_new_empty() { | |
219 | use DirsIterable::{Dirstate, Manifest}; |
|
220 | use DirsIterable::{Dirstate, Manifest}; | |
220 |
|
221 | |||
221 | let new = DirsMultiset::new(Manifest(vec![]), None); |
|
222 | let new = DirsMultiset::new(Manifest(&vec![]), None); | |
222 | let expected = DirsMultiset { |
|
223 | let expected = DirsMultiset { | |
223 | inner: HashMap::new(), |
|
224 | inner: HashMap::new(), | |
224 | }; |
|
225 | }; | |
225 | assert_eq!(expected, new); |
|
226 | assert_eq!(expected, new); | |
226 |
|
227 | |||
227 |
let new = DirsMultiset::new(Dirstate( |
|
228 | let new = DirsMultiset::new(Dirstate(&HashMap::new()), None); | |
228 | let expected = DirsMultiset { |
|
229 | let expected = DirsMultiset { | |
229 | inner: HashMap::new(), |
|
230 | inner: HashMap::new(), | |
230 | }; |
|
231 | }; | |
@@ -244,7 +245,7 b' mod tests {' | |||||
244 | .map(|(k, v)| (k.as_bytes().to_vec(), *v)) |
|
245 | .map(|(k, v)| (k.as_bytes().to_vec(), *v)) | |
245 | .collect(); |
|
246 | .collect(); | |
246 |
|
247 | |||
247 | let new = DirsMultiset::new(Manifest(input_vec), None); |
|
248 | let new = DirsMultiset::new(Manifest(&input_vec), None); | |
248 | let expected = DirsMultiset { |
|
249 | let expected = DirsMultiset { | |
249 | inner: expected_inner, |
|
250 | inner: expected_inner, | |
250 | }; |
|
251 | }; | |
@@ -269,7 +270,7 b' mod tests {' | |||||
269 | .map(|(k, v)| (k.as_bytes().to_vec(), *v)) |
|
270 | .map(|(k, v)| (k.as_bytes().to_vec(), *v)) | |
270 | .collect(); |
|
271 | .collect(); | |
271 |
|
272 | |||
272 | let new = DirsMultiset::new(Dirstate(input_map), None); |
|
273 | let new = DirsMultiset::new(Dirstate(&input_map), None); | |
273 | let expected = DirsMultiset { |
|
274 | let expected = DirsMultiset { | |
274 | inner: expected_inner, |
|
275 | inner: expected_inner, | |
275 | }; |
|
276 | }; | |
@@ -289,7 +290,7 b' mod tests {' | |||||
289 | .map(|(k, v)| (k.as_bytes().to_vec(), *v)) |
|
290 | .map(|(k, v)| (k.as_bytes().to_vec(), *v)) | |
290 | .collect(); |
|
291 | .collect(); | |
291 |
|
292 | |||
292 | let new = DirsMultiset::new(Manifest(input_vec), Some('n' as i8)); |
|
293 | let new = DirsMultiset::new(Manifest(&input_vec), Some('n' as i8)); | |
293 | let expected = DirsMultiset { |
|
294 | let expected = DirsMultiset { | |
294 | inner: expected_inner, |
|
295 | inner: expected_inner, | |
295 | }; |
|
296 | }; | |
@@ -318,11 +319,10 b' mod tests {' | |||||
318 | .map(|(k, v)| (k.as_bytes().to_vec(), *v)) |
|
319 | .map(|(k, v)| (k.as_bytes().to_vec(), *v)) | |
319 | .collect(); |
|
320 | .collect(); | |
320 |
|
321 | |||
321 | let new = DirsMultiset::new(Dirstate(input_map), Some('n' as i8)); |
|
322 | let new = DirsMultiset::new(Dirstate(&input_map), Some('n' as i8)); | |
322 | let expected = DirsMultiset { |
|
323 | let expected = DirsMultiset { | |
323 | inner: expected_inner, |
|
324 | inner: expected_inner, | |
324 | }; |
|
325 | }; | |
325 | assert_eq!(expected, new); |
|
326 | assert_eq!(expected, new); | |
326 | } |
|
327 | } | |
327 |
|
||||
328 | } |
|
328 | } |
@@ -4,31 +4,35 b'' | |||||
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::{ |
|
6 | use crate::{ | |
7 | CopyVec, CopyVecEntry, DirstateEntry, DirstatePackError, DirstateParents, |
|
7 | dirstate::{CopyMap, StateMap}, | |
8 | DirstateParseError, DirstateVec, |
|
8 | utils::copy_into_array, | |
|
9 | DirstateEntry, DirstatePackError, DirstateParents, DirstateParseError, | |||
9 | }; |
|
10 | }; | |
10 | use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; |
|
11 | use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; | |
11 | use std::collections::HashMap; |
|
12 | use std::convert::TryInto; | |
12 | use std::io::Cursor; |
|
13 | use std::io::Cursor; | |
|
14 | use std::time::Duration; | |||
13 |
|
15 | |||
14 | /// Parents are stored in the dirstate as byte hashes. |
|
16 | /// Parents are stored in the dirstate as byte hashes. | |
15 | const PARENT_SIZE: usize = 20; |
|
17 | pub const PARENT_SIZE: usize = 20; | |
16 | /// Dirstate entries have a static part of 8 + 32 + 32 + 32 + 32 bits. |
|
18 | /// Dirstate entries have a static part of 8 + 32 + 32 + 32 + 32 bits. | |
17 | const MIN_ENTRY_SIZE: usize = 17; |
|
19 | const MIN_ENTRY_SIZE: usize = 17; | |
18 |
|
20 | |||
|
21 | // TODO parse/pack: is mutate-on-loop better for performance? | |||
|
22 | ||||
19 | pub fn parse_dirstate( |
|
23 | pub fn parse_dirstate( | |
|
24 | state_map: &mut StateMap, | |||
|
25 | copy_map: &mut CopyMap, | |||
20 | contents: &[u8], |
|
26 | contents: &[u8], | |
21 |
) -> Result< |
|
27 | ) -> Result<DirstateParents, DirstateParseError> { | |
22 | if contents.len() < PARENT_SIZE * 2 { |
|
28 | if contents.len() < PARENT_SIZE * 2 { | |
23 | return Err(DirstateParseError::TooLittleData); |
|
29 | return Err(DirstateParseError::TooLittleData); | |
24 | } |
|
30 | } | |
25 |
|
31 | |||
26 | let mut dirstate_vec = vec![]; |
|
|||
27 | let mut copies = vec![]; |
|
|||
28 | let mut curr_pos = PARENT_SIZE * 2; |
|
32 | let mut curr_pos = PARENT_SIZE * 2; | |
29 | let parents = DirstateParents { |
|
33 | let parents = DirstateParents { | |
30 | p1: &contents[..PARENT_SIZE], |
|
34 | p1: copy_into_array(&contents[..PARENT_SIZE]), | |
31 | p2: &contents[PARENT_SIZE..curr_pos], |
|
35 | p2: copy_into_array(&contents[PARENT_SIZE..curr_pos]), | |
32 | }; |
|
36 | }; | |
33 |
|
37 | |||
34 | while curr_pos < contents.len() { |
|
38 | while curr_pos < contents.len() { | |
@@ -57,9 +61,9 b' pub fn parse_dirstate(' | |||||
57 | }; |
|
61 | }; | |
58 |
|
62 | |||
59 | if let Some(copy_path) = copy { |
|
63 | if let Some(copy_path) = copy { | |
60 | copies.push(CopyVecEntry { path, copy_path }); |
|
64 | copy_map.insert(path.to_owned(), copy_path.to_owned()); | |
61 | }; |
|
65 | }; | |
62 |
|
|
66 | state_map.insert( | |
63 | path.to_owned(), |
|
67 | path.to_owned(), | |
64 | DirstateEntry { |
|
68 | DirstateEntry { | |
65 | state, |
|
69 | state, | |
@@ -67,28 +71,28 b' pub fn parse_dirstate(' | |||||
67 | size, |
|
71 | size, | |
68 | mtime, |
|
72 | mtime, | |
69 | }, |
|
73 | }, | |
70 |
) |
|
74 | ); | |
71 | curr_pos = curr_pos + MIN_ENTRY_SIZE + (path_len); |
|
75 | curr_pos = curr_pos + MIN_ENTRY_SIZE + (path_len); | |
72 | } |
|
76 | } | |
73 |
|
77 | |||
74 | Ok((parents, dirstate_vec, copies)) |
|
78 | Ok(parents) | |
75 | } |
|
79 | } | |
76 |
|
80 | |||
|
81 | /// `now` is the duration in seconds since the Unix epoch | |||
77 | pub fn pack_dirstate( |
|
82 | pub fn pack_dirstate( | |
78 |
|
|
83 | state_map: &mut StateMap, | |
79 | copymap: &HashMap<Vec<u8>, Vec<u8>>, |
|
84 | copy_map: &CopyMap, | |
80 | parents: DirstateParents, |
|
85 | parents: DirstateParents, | |
81 |
now: |
|
86 | now: Duration, | |
82 |
) -> Result< |
|
87 | ) -> Result<Vec<u8>, DirstatePackError> { | |
83 | if parents.p1.len() != PARENT_SIZE || parents.p2.len() != PARENT_SIZE { |
|
88 | // TODO move away from i32 before 2038. | |
84 | return Err(DirstatePackError::CorruptedParent); |
|
89 | let now: i32 = now.as_secs().try_into().expect("time overflow"); | |
85 | } |
|
|||
86 |
|
90 | |||
87 |
let expected_size: usize = |
|
91 | let expected_size: usize = state_map | |
88 | .iter() |
|
92 | .iter() | |
89 |
.map(|( |
|
93 | .map(|(filename, _)| { | |
90 | let mut length = MIN_ENTRY_SIZE + filename.len(); |
|
94 | let mut length = MIN_ENTRY_SIZE + filename.len(); | |
91 | if let Some(ref copy) = copymap.get(filename) { |
|
95 | if let Some(ref copy) = copy_map.get(filename) { | |
92 | length += copy.len() + 1; |
|
96 | length += copy.len() + 1; | |
93 | } |
|
97 | } | |
94 | length |
|
98 | length | |
@@ -97,15 +101,15 b' pub fn pack_dirstate(' | |||||
97 | let expected_size = expected_size + PARENT_SIZE * 2; |
|
101 | let expected_size = expected_size + PARENT_SIZE * 2; | |
98 |
|
102 | |||
99 | let mut packed = Vec::with_capacity(expected_size); |
|
103 | let mut packed = Vec::with_capacity(expected_size); | |
100 |
let mut new_ |
|
104 | let mut new_state_map = vec![]; | |
101 |
|
105 | |||
102 | packed.extend(parents.p1); |
|
106 | packed.extend(&parents.p1); | |
103 | packed.extend(parents.p2); |
|
107 | packed.extend(&parents.p2); | |
104 |
|
108 | |||
105 |
for (ref filename, entry) in |
|
109 | for (ref filename, entry) in state_map.iter() { | |
106 |
let mut new_filename: Vec<u8> = filename.to_ |
|
110 | let mut new_filename: Vec<u8> = filename.to_vec(); | |
107 | let mut new_mtime: i32 = entry.mtime; |
|
111 | let mut new_mtime: i32 = entry.mtime; | |
108 |
if entry.state == 'n' as i8 && entry.mtime == now |
|
112 | if entry.state == 'n' as i8 && entry.mtime == now { | |
109 | // The file was last modified "simultaneously" with the current |
|
113 | // The file was last modified "simultaneously" with the current | |
110 | // write to dirstate (i.e. within the same second for file- |
|
114 | // write to dirstate (i.e. within the same second for file- | |
111 | // systems with a granularity of 1 sec). This commonly happens |
|
115 | // systems with a granularity of 1 sec). This commonly happens | |
@@ -116,8 +120,8 b' pub fn pack_dirstate(' | |||||
116 | // contents of the file if the size is the same. This prevents |
|
120 | // contents of the file if the size is the same. This prevents | |
117 | // mistakenly treating such files as clean. |
|
121 | // mistakenly treating such files as clean. | |
118 | new_mtime = -1; |
|
122 | new_mtime = -1; | |
119 |
new_ |
|
123 | new_state_map.push(( | |
120 | filename.to_owned(), |
|
124 | filename.to_owned().to_vec(), | |
121 | DirstateEntry { |
|
125 | DirstateEntry { | |
122 | mtime: new_mtime, |
|
126 | mtime: new_mtime, | |
123 | ..*entry |
|
127 | ..*entry | |
@@ -125,7 +129,7 b' pub fn pack_dirstate(' | |||||
125 | )); |
|
129 | )); | |
126 | } |
|
130 | } | |
127 |
|
131 | |||
128 | if let Some(copy) = copymap.get(filename) { |
|
132 | if let Some(copy) = copy_map.get(*filename) { | |
129 | new_filename.push('\0' as u8); |
|
133 | new_filename.push('\0' as u8); | |
130 | new_filename.extend(copy); |
|
134 | new_filename.extend(copy); | |
131 | } |
|
135 | } | |
@@ -142,66 +146,37 b' pub fn pack_dirstate(' | |||||
142 | return Err(DirstatePackError::BadSize(expected_size, packed.len())); |
|
146 | return Err(DirstatePackError::BadSize(expected_size, packed.len())); | |
143 | } |
|
147 | } | |
144 |
|
148 | |||
145 | Ok((packed, new_dirstate_vec)) |
|
149 | state_map.extend(new_state_map); | |
|
150 | ||||
|
151 | Ok(packed) | |||
146 | } |
|
152 | } | |
147 |
|
153 | |||
148 | #[cfg(test)] |
|
154 | #[cfg(test)] | |
149 | mod tests { |
|
155 | mod tests { | |
150 | use super::*; |
|
156 | use super::*; | |
|
157 | use std::collections::HashMap; | |||
151 |
|
158 | |||
152 | #[test] |
|
159 | #[test] | |
153 | fn test_pack_dirstate_empty() { |
|
160 | fn test_pack_dirstate_empty() { | |
154 | let dirstate_vec: DirstateVec = vec![]; |
|
161 | let mut state_map: StateMap = HashMap::new(); | |
155 | let copymap = HashMap::new(); |
|
162 | let copymap = HashMap::new(); | |
156 | let parents = DirstateParents { |
|
163 | let parents = DirstateParents { | |
157 | p1: b"12345678910111213141", |
|
164 | p1: *b"12345678910111213141", | |
158 | p2: b"00000000000000000000", |
|
165 | p2: *b"00000000000000000000", | |
159 | }; |
|
166 | }; | |
160 |
let now |
|
167 | let now = Duration::new(15000000, 0); | |
161 | let expected = |
|
168 | let expected = b"1234567891011121314100000000000000000000".to_vec(); | |
162 | (b"1234567891011121314100000000000000000000".to_vec(), vec![]); |
|
|||
163 |
|
169 | |||
164 | assert_eq!( |
|
170 | assert_eq!( | |
165 | expected, |
|
171 | expected, | |
166 |
pack_dirstate(& |
|
172 | pack_dirstate(&mut state_map, ©map, parents, now).unwrap() | |
167 | ); |
|
173 | ); | |
|
174 | ||||
|
175 | assert!(state_map.is_empty()) | |||
168 | } |
|
176 | } | |
169 | #[test] |
|
177 | #[test] | |
170 | fn test_pack_dirstate_one_entry() { |
|
178 | fn test_pack_dirstate_one_entry() { | |
171 |
let |
|
179 | let expected_state_map: StateMap = [( | |
172 | vec!['f' as u8, '1' as u8], |
|
|||
173 | DirstateEntry { |
|
|||
174 | state: 'n' as i8, |
|
|||
175 | mode: 0o644, |
|
|||
176 | size: 0, |
|
|||
177 | mtime: 791231220, |
|
|||
178 | }, |
|
|||
179 | )]; |
|
|||
180 | let copymap = HashMap::new(); |
|
|||
181 | let parents = DirstateParents { |
|
|||
182 | p1: b"12345678910111213141", |
|
|||
183 | p2: b"00000000000000000000", |
|
|||
184 | }; |
|
|||
185 | let now: i32 = 15000000; |
|
|||
186 | let expected = ( |
|
|||
187 | [ |
|
|||
188 | 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, |
|
|||
189 | 49, 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, |
|
|||
190 | 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, |
|
|||
191 | 0, 0, 0, 47, 41, 58, 244, 0, 0, 0, 2, 102, 49, |
|
|||
192 | ] |
|
|||
193 | .to_vec(), |
|
|||
194 | vec![], |
|
|||
195 | ); |
|
|||
196 |
|
||||
197 | assert_eq!( |
|
|||
198 | expected, |
|
|||
199 | pack_dirstate(&dirstate_vec, ©map, parents, now).unwrap() |
|
|||
200 | ); |
|
|||
201 | } |
|
|||
202 | #[test] |
|
|||
203 | fn test_pack_dirstate_one_entry_with_copy() { |
|
|||
204 | let dirstate_vec: DirstateVec = vec![( |
|
|||
205 | b"f1".to_vec(), |
|
180 | b"f1".to_vec(), | |
206 | DirstateEntry { |
|
181 | DirstateEntry { | |
207 | state: 'n' as i8, |
|
182 | state: 'n' as i8, | |
@@ -209,35 +184,36 b' mod tests {' | |||||
209 | size: 0, |
|
184 | size: 0, | |
210 | mtime: 791231220, |
|
185 | mtime: 791231220, | |
211 | }, |
|
186 | }, | |
212 |
)] |
|
187 | )] | |
213 | let mut copymap = HashMap::new(); |
|
188 | .iter() | |
214 | copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); |
|
189 | .cloned() | |
|
190 | .collect(); | |||
|
191 | let mut state_map = expected_state_map.clone(); | |||
|
192 | ||||
|
193 | let copymap = HashMap::new(); | |||
215 | let parents = DirstateParents { |
|
194 | let parents = DirstateParents { | |
216 | p1: b"12345678910111213141", |
|
195 | p1: *b"12345678910111213141", | |
217 | p2: b"00000000000000000000", |
|
196 | p2: *b"00000000000000000000", | |
218 | }; |
|
197 | }; | |
219 |
let now |
|
198 | let now = Duration::new(15000000, 0); | |
220 |
let expected = |
|
199 | let expected = [ | |
221 | [ |
|
200 | 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49, | |
222 | 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, |
|
201 | 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, | |
223 |
|
|
202 | 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47, | |
224 | 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, |
|
203 | 41, 58, 244, 0, 0, 0, 2, 102, 49, | |
225 | 0, 0, 0, 47, 41, 58, 244, 0, 0, 0, 11, 102, 49, 0, 99, 111, |
|
204 | ] | |
226 | 112, 121, 110, 97, 109, 101, |
|
205 | .to_vec(); | |
227 | ] |
|
|||
228 | .to_vec(), |
|
|||
229 | vec![], |
|
|||
230 | ); |
|
|||
231 |
|
206 | |||
232 | assert_eq!( |
|
207 | assert_eq!( | |
233 | expected, |
|
208 | expected, | |
234 |
pack_dirstate(& |
|
209 | pack_dirstate(&mut state_map, ©map, parents, now).unwrap() | |
235 | ); |
|
210 | ); | |
236 | } |
|
|||
237 |
|
211 | |||
|
212 | assert_eq!(expected_state_map, state_map); | |||
|
213 | } | |||
238 | #[test] |
|
214 | #[test] | |
239 |
fn test_parse |
|
215 | fn test_pack_dirstate_one_entry_with_copy() { | |
240 |
let |
|
216 | let expected_state_map: StateMap = [( | |
241 | b"f1".to_vec(), |
|
217 | b"f1".to_vec(), | |
242 | DirstateEntry { |
|
218 | DirstateEntry { | |
243 | state: 'n' as i8, |
|
219 | state: 'n' as i8, | |
@@ -245,36 +221,76 b' mod tests {' | |||||
245 | size: 0, |
|
221 | size: 0, | |
246 | mtime: 791231220, |
|
222 | mtime: 791231220, | |
247 | }, |
|
223 | }, | |
248 |
)] |
|
224 | )] | |
|
225 | .iter() | |||
|
226 | .cloned() | |||
|
227 | .collect(); | |||
|
228 | let mut state_map = expected_state_map.clone(); | |||
249 | let mut copymap = HashMap::new(); |
|
229 | let mut copymap = HashMap::new(); | |
250 | copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); |
|
230 | copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); | |
251 | let parents = DirstateParents { |
|
231 | let parents = DirstateParents { | |
252 | p1: b"12345678910111213141", |
|
232 | p1: *b"12345678910111213141", | |
253 | p2: b"00000000000000000000", |
|
233 | p2: *b"00000000000000000000", | |
254 | }; |
|
234 | }; | |
255 |
let now |
|
235 | let now = Duration::new(15000000, 0); | |
256 |
let |
|
236 | let expected = [ | |
257 | pack_dirstate(&dirstate_vec, ©map, parents, now).unwrap(); |
|
237 | 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49, | |
|
238 | 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, | |||
|
239 | 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47, | |||
|
240 | 41, 58, 244, 0, 0, 0, 11, 102, 49, 0, 99, 111, 112, 121, 110, 97, | |||
|
241 | 109, 101, | |||
|
242 | ] | |||
|
243 | .to_vec(); | |||
258 |
|
244 | |||
259 | assert_eq!( |
|
245 | assert_eq!( | |
260 |
|
|
246 | expected, | |
261 | parents, |
|
247 | pack_dirstate(&mut state_map, ©map, parents, now).unwrap() | |
262 | dirstate_vec, |
|
248 | ); | |
263 | copymap |
|
249 | assert_eq!(expected_state_map, state_map); | |
264 | .iter() |
|
250 | } | |
265 | .map(|(k, v)| CopyVecEntry { |
|
251 | ||
266 | path: k.as_slice(), |
|
252 | #[test] | |
267 | copy_path: v.as_slice() |
|
253 | fn test_parse_pack_one_entry_with_copy() { | |
268 | }) |
|
254 | let mut state_map: StateMap = [( | |
269 |
|
|
255 | b"f1".to_vec(), | |
270 | ), |
|
256 | DirstateEntry { | |
271 | parse_dirstate(result.0.as_slice()).unwrap() |
|
257 | state: 'n' as i8, | |
|
258 | mode: 0o644, | |||
|
259 | size: 0, | |||
|
260 | mtime: 791231220, | |||
|
261 | }, | |||
|
262 | )] | |||
|
263 | .iter() | |||
|
264 | .cloned() | |||
|
265 | .collect(); | |||
|
266 | let mut copymap = HashMap::new(); | |||
|
267 | copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); | |||
|
268 | let parents = DirstateParents { | |||
|
269 | p1: *b"12345678910111213141", | |||
|
270 | p2: *b"00000000000000000000", | |||
|
271 | }; | |||
|
272 | let now = Duration::new(15000000, 0); | |||
|
273 | let result = | |||
|
274 | pack_dirstate(&mut state_map, ©map, parents.clone(), now) | |||
|
275 | .unwrap(); | |||
|
276 | ||||
|
277 | let mut new_state_map: StateMap = HashMap::new(); | |||
|
278 | let mut new_copy_map: CopyMap = HashMap::new(); | |||
|
279 | let new_parents = parse_dirstate( | |||
|
280 | &mut new_state_map, | |||
|
281 | &mut new_copy_map, | |||
|
282 | result.as_slice(), | |||
|
283 | ) | |||
|
284 | .unwrap(); | |||
|
285 | assert_eq!( | |||
|
286 | (parents, state_map, copymap), | |||
|
287 | (new_parents, new_state_map, new_copy_map) | |||
272 | ) |
|
288 | ) | |
273 | } |
|
289 | } | |
274 |
|
290 | |||
275 | #[test] |
|
291 | #[test] | |
276 | fn test_parse_pack_multiple_entries_with_copy() { |
|
292 | fn test_parse_pack_multiple_entries_with_copy() { | |
277 |
let |
|
293 | let mut state_map: StateMap = [ | |
278 | ( |
|
294 | ( | |
279 | b"f1".to_vec(), |
|
295 | b"f1".to_vec(), | |
280 | DirstateEntry { |
|
296 | DirstateEntry { | |
@@ -311,39 +327,40 b' mod tests {' | |||||
311 | mtime: -1, |
|
327 | mtime: -1, | |
312 | }, |
|
328 | }, | |
313 | ), |
|
329 | ), | |
314 |
] |
|
330 | ] | |
|
331 | .iter() | |||
|
332 | .cloned() | |||
|
333 | .collect(); | |||
315 | let mut copymap = HashMap::new(); |
|
334 | let mut copymap = HashMap::new(); | |
316 | copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); |
|
335 | copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); | |
317 | copymap.insert(b"f4\xF6".to_vec(), b"copyname2".to_vec()); |
|
336 | copymap.insert(b"f4\xF6".to_vec(), b"copyname2".to_vec()); | |
318 | let parents = DirstateParents { |
|
337 | let parents = DirstateParents { | |
319 | p1: b"12345678910111213141", |
|
338 | p1: *b"12345678910111213141", | |
320 | p2: b"00000000000000000000", |
|
339 | p2: *b"00000000000000000000", | |
321 | }; |
|
340 | }; | |
322 |
let now |
|
341 | let now = Duration::new(15000000, 0); | |
323 | let result = |
|
342 | let result = | |
324 |
pack_dirstate(& |
|
343 | pack_dirstate(&mut state_map, ©map, parents.clone(), now) | |
|
344 | .unwrap(); | |||
325 |
|
345 | |||
|
346 | let mut new_state_map: StateMap = HashMap::new(); | |||
|
347 | let mut new_copy_map: CopyMap = HashMap::new(); | |||
|
348 | let new_parents = parse_dirstate( | |||
|
349 | &mut new_state_map, | |||
|
350 | &mut new_copy_map, | |||
|
351 | result.as_slice(), | |||
|
352 | ) | |||
|
353 | .unwrap(); | |||
326 | assert_eq!( |
|
354 | assert_eq!( | |
327 |
(parents, |
|
355 | (parents, state_map, copymap), | |
328 | parse_dirstate(result.0.as_slice()) |
|
356 | (new_parents, new_state_map, new_copy_map) | |
329 | .and_then(|(p, dvec, cvec)| Ok(( |
|
|||
330 | p, |
|
|||
331 | dvec, |
|
|||
332 | cvec.iter() |
|
|||
333 | .map(|entry| ( |
|
|||
334 | entry.path.to_vec(), |
|
|||
335 | entry.copy_path.to_vec() |
|
|||
336 | )) |
|
|||
337 | .collect() |
|
|||
338 | ))) |
|
|||
339 | .unwrap() |
|
|||
340 | ) |
|
357 | ) | |
341 | } |
|
358 | } | |
342 |
|
359 | |||
343 | #[test] |
|
360 | #[test] | |
344 | /// https://www.mercurial-scm.org/repo/hg/rev/af3f26b6bba4 |
|
361 | /// https://www.mercurial-scm.org/repo/hg/rev/af3f26b6bba4 | |
345 | fn test_parse_pack_one_entry_with_copy_and_time_conflict() { |
|
362 | fn test_parse_pack_one_entry_with_copy_and_time_conflict() { | |
346 |
let |
|
363 | let mut state_map: StateMap = [( | |
347 | b"f1".to_vec(), |
|
364 | b"f1".to_vec(), | |
348 | DirstateEntry { |
|
365 | DirstateEntry { | |
349 | state: 'n' as i8, |
|
366 | state: 'n' as i8, | |
@@ -351,21 +368,34 b' mod tests {' | |||||
351 | size: 0, |
|
368 | size: 0, | |
352 | mtime: 15000000, |
|
369 | mtime: 15000000, | |
353 | }, |
|
370 | }, | |
354 |
)] |
|
371 | )] | |
|
372 | .iter() | |||
|
373 | .cloned() | |||
|
374 | .collect(); | |||
355 | let mut copymap = HashMap::new(); |
|
375 | let mut copymap = HashMap::new(); | |
356 | copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); |
|
376 | copymap.insert(b"f1".to_vec(), b"copyname".to_vec()); | |
357 | let parents = DirstateParents { |
|
377 | let parents = DirstateParents { | |
358 | p1: b"12345678910111213141", |
|
378 | p1: *b"12345678910111213141", | |
359 | p2: b"00000000000000000000", |
|
379 | p2: *b"00000000000000000000", | |
360 | }; |
|
380 | }; | |
361 |
let now |
|
381 | let now = Duration::new(15000000, 0); | |
362 | let result = |
|
382 | let result = | |
363 |
pack_dirstate(& |
|
383 | pack_dirstate(&mut state_map, ©map, parents.clone(), now) | |
|
384 | .unwrap(); | |||
|
385 | ||||
|
386 | let mut new_state_map: StateMap = HashMap::new(); | |||
|
387 | let mut new_copy_map: CopyMap = HashMap::new(); | |||
|
388 | let new_parents = parse_dirstate( | |||
|
389 | &mut new_state_map, | |||
|
390 | &mut new_copy_map, | |||
|
391 | result.as_slice(), | |||
|
392 | ) | |||
|
393 | .unwrap(); | |||
364 |
|
394 | |||
365 | assert_eq!( |
|
395 | assert_eq!( | |
366 | ( |
|
396 | ( | |
367 | parents, |
|
397 | parents, | |
368 |
|
|
398 | [( | |
369 | b"f1".to_vec(), |
|
399 | b"f1".to_vec(), | |
370 | DirstateEntry { |
|
400 | DirstateEntry { | |
371 | state: 'n' as i8, |
|
401 | state: 'n' as i8, | |
@@ -373,16 +403,13 b' mod tests {' | |||||
373 | size: 0, |
|
403 | size: 0, | |
374 | mtime: -1 |
|
404 | mtime: -1 | |
375 | } |
|
405 | } | |
376 |
)] |
|
406 | )] | |
377 |
|
|
407 | .iter() | |
378 |
|
|
408 | .cloned() | |
379 | .map(|(k, v)| CopyVecEntry { |
|
409 | .collect::<StateMap>(), | |
380 | path: k.as_slice(), |
|
410 | copymap, | |
381 | copy_path: v.as_slice() |
|
|||
382 | }) |
|
|||
383 | .collect() |
|
|||
384 | ), |
|
411 | ), | |
385 | parse_dirstate(result.0.as_slice()).unwrap() |
|
412 | (new_parents, new_state_map, new_copy_map) | |
386 | ) |
|
413 | ) | |
387 | } |
|
414 | } | |
388 | } |
|
415 | } |
@@ -10,9 +10,8 b' pub mod discovery;' | |||||
10 | pub mod testing; // unconditionally built, for use from integration tests |
|
10 | pub mod testing; // unconditionally built, for use from integration tests | |
11 | pub use dirstate::{ |
|
11 | pub use dirstate::{ | |
12 | dirs_multiset::DirsMultiset, |
|
12 | dirs_multiset::DirsMultiset, | |
13 | parsers::{pack_dirstate, parse_dirstate}, |
|
13 | parsers::{pack_dirstate, parse_dirstate, PARENT_SIZE}, | |
14 |
Copy |
|
14 | CopyMap, DirsIterable, DirstateEntry, DirstateParents, StateMap, | |
15 | DirstateVec, |
|
|||
16 | }; |
|
15 | }; | |
17 | mod filepatterns; |
|
16 | mod filepatterns; | |
18 | pub mod utils; |
|
17 | pub mod utils; | |
@@ -60,6 +59,7 b' pub enum DirstateParseError {' | |||||
60 | TooLittleData, |
|
59 | TooLittleData, | |
61 | Overflow, |
|
60 | Overflow, | |
62 | CorruptedEntry(String), |
|
61 | CorruptedEntry(String), | |
|
62 | Damaged, | |||
63 | } |
|
63 | } | |
64 |
|
64 | |||
65 | #[derive(Debug, PartialEq)] |
|
65 | #[derive(Debug, PartialEq)] |
@@ -1,5 +1,22 b'' | |||||
1 | pub mod files; |
|
1 | pub mod files; | |
2 |
|
2 | |||
|
3 | use std::convert::AsMut; | |||
|
4 | ||||
|
5 | /// Takes a slice and copies it into an array. | |||
|
6 | /// | |||
|
7 | /// # Panics | |||
|
8 | /// | |||
|
9 | /// Will panic if the slice and target array don't have the same length. | |||
|
10 | pub fn copy_into_array<A, T>(slice: &[T]) -> A | |||
|
11 | where | |||
|
12 | A: Sized + Default + AsMut<[T]>, | |||
|
13 | T: Copy, | |||
|
14 | { | |||
|
15 | let mut a = Default::default(); | |||
|
16 | <A as AsMut<[T]>>::as_mut(&mut a).copy_from_slice(slice); | |||
|
17 | a | |||
|
18 | } | |||
|
19 | ||||
3 | /// Replaces the `from` slice with the `to` slice inside the `buf` slice. |
|
20 | /// Replaces the `from` slice with the `to` slice inside the `buf` slice. | |
4 | /// |
|
21 | /// | |
5 | /// # Examples |
|
22 | /// # Examples |
@@ -14,7 +14,7 b' use crate::dirstate::dirs_multiset::Dirs' | |||||
14 | use cpython::{ |
|
14 | use cpython::{ | |
15 | PyBytes, PyDict, PyErr, PyModule, PyObject, PyResult, PySequence, Python, |
|
15 | PyBytes, PyDict, PyErr, PyModule, PyObject, PyResult, PySequence, Python, | |
16 | }; |
|
16 | }; | |
17 |
use hg::{DirstateEntry, |
|
17 | use hg::{DirstateEntry, StateMap}; | |
18 | use libc::{c_char, c_int}; |
|
18 | use libc::{c_char, c_int}; | |
19 | #[cfg(feature = "python27")] |
|
19 | #[cfg(feature = "python27")] | |
20 | use python27_sys::PyCapsule_Import; |
|
20 | use python27_sys::PyCapsule_Import; | |
@@ -54,10 +54,7 b' pub fn decapsule_make_dirstate_tuple(' | |||||
54 | } |
|
54 | } | |
55 | } |
|
55 | } | |
56 |
|
56 | |||
57 | pub fn extract_dirstate_vec( |
|
57 | pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result<StateMap, PyErr> { | |
58 | py: Python, |
|
|||
59 | dmap: &PyDict, |
|
|||
60 | ) -> Result<DirstateVec, PyErr> { |
|
|||
61 | dmap.items(py) |
|
58 | dmap.items(py) | |
62 | .iter() |
|
59 | .iter() | |
63 | .map(|(filename, stats)| { |
|
60 | .map(|(filename, stats)| { |
@@ -15,7 +15,7 b' use cpython::{' | |||||
15 | ToPyObject, |
|
15 | ToPyObject, | |
16 | }; |
|
16 | }; | |
17 |
|
17 | |||
18 |
use crate::dirstate::extract_dirstate |
|
18 | use crate::dirstate::extract_dirstate; | |
19 | use hg::{DirsIterable, DirsMultiset, DirstateMapError}; |
|
19 | use hg::{DirsIterable, DirsMultiset, DirstateMapError}; | |
20 |
|
20 | |||
21 | py_class!(pub class Dirs |py| { |
|
21 | py_class!(pub class Dirs |py| { | |
@@ -32,12 +32,10 b' py_class!(pub class Dirs |py| {' | |||||
32 | if let Some(skip) = skip { |
|
32 | if let Some(skip) = skip { | |
33 | skip_state = Some(skip.extract::<PyBytes>(py)?.data(py)[0] as i8); |
|
33 | skip_state = Some(skip.extract::<PyBytes>(py)?.data(py)[0] as i8); | |
34 | } |
|
34 | } | |
35 | let dirs_map; |
|
35 | let inner = if let Ok(map) = map.cast_as::<PyDict>(py) { | |
36 |
|
36 | let dirstate = extract_dirstate(py, &map)?; | ||
37 | if let Ok(map) = map.cast_as::<PyDict>(py) { |
|
37 | DirsMultiset::new( | |
38 | let dirstate_vec = extract_dirstate_vec(py, &map)?; |
|
38 | DirsIterable::Dirstate(&dirstate), | |
39 | dirs_map = DirsMultiset::new( |
|
|||
40 | DirsIterable::Dirstate(dirstate_vec), |
|
|||
41 | skip_state, |
|
39 | skip_state, | |
42 | ) |
|
40 | ) | |
43 | } else { |
|
41 | } else { | |
@@ -45,13 +43,13 b' py_class!(pub class Dirs |py| {' | |||||
45 | .iter(py)? |
|
43 | .iter(py)? | |
46 | .map(|o| Ok(o?.extract::<PyBytes>(py)?.data(py).to_owned())) |
|
44 | .map(|o| Ok(o?.extract::<PyBytes>(py)?.data(py).to_owned())) | |
47 | .collect(); |
|
45 | .collect(); | |
48 |
|
|
46 | DirsMultiset::new( | |
49 | DirsIterable::Manifest(map?), |
|
47 | DirsIterable::Manifest(&map?), | |
50 | skip_state, |
|
48 | skip_state, | |
51 | ) |
|
49 | ) | |
52 | } |
|
50 | }; | |
53 |
|
51 | |||
54 |
Self::create_instance(py, RefCell::new( |
|
52 | Self::create_instance(py, RefCell::new(inner)) | |
55 | } |
|
53 | } | |
56 |
|
54 | |||
57 | def addpath(&self, path: PyObject) -> PyResult<PyObject> { |
|
55 | def addpath(&self, path: PyObject) -> PyResult<PyObject> { |
@@ -12,17 +12,18 b'' | |||||
12 | //! |
|
12 | //! | |
13 | use cpython::{ |
|
13 | use cpython::{ | |
14 | exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyResult, PyTuple, Python, |
|
14 | exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyResult, PyTuple, Python, | |
15 |
|
|
15 | ToPyObject, | |
16 | }; |
|
16 | }; | |
17 | use hg::{ |
|
17 | use hg::{ | |
18 |
pack_dirstate, parse_dirstate, |
|
18 | pack_dirstate, parse_dirstate, utils::copy_into_array, DirstateEntry, | |
19 | DirstatePackError, DirstateParents, DirstateParseError, |
|
19 | DirstatePackError, DirstateParents, DirstateParseError, PARENT_SIZE, | |
20 | }; |
|
20 | }; | |
21 | use std::collections::HashMap; |
|
21 | use std::collections::HashMap; | |
22 |
|
22 | |||
23 | use libc::c_char; |
|
23 | use libc::c_char; | |
24 |
|
24 | |||
25 |
use crate::dirstate::{decapsule_make_dirstate_tuple, extract_dirstate |
|
25 | use crate::dirstate::{decapsule_make_dirstate_tuple, extract_dirstate}; | |
|
26 | use std::time::Duration; | |||
26 |
|
27 | |||
27 | fn parse_dirstate_wrapper( |
|
28 | fn parse_dirstate_wrapper( | |
28 | py: Python, |
|
29 | py: Python, | |
@@ -30,12 +31,15 b' fn parse_dirstate_wrapper(' | |||||
30 | copymap: PyDict, |
|
31 | copymap: PyDict, | |
31 | st: PyBytes, |
|
32 | st: PyBytes, | |
32 | ) -> PyResult<PyTuple> { |
|
33 | ) -> PyResult<PyTuple> { | |
33 | match parse_dirstate(st.data(py)) { |
|
34 | let mut dirstate_map = HashMap::new(); | |
34 | Ok((parents, dirstate_vec, copies)) => { |
|
35 | let mut copies = HashMap::new(); | |
35 | for (filename, entry) in dirstate_vec { |
|
36 | ||
|
37 | match parse_dirstate(&mut dirstate_map, &mut copies, st.data(py)) { | |||
|
38 | Ok(parents) => { | |||
|
39 | for (filename, entry) in dirstate_map { | |||
36 | dmap.set_item( |
|
40 | dmap.set_item( | |
37 | py, |
|
41 | py, | |
38 |
PyBytes::new(py, &filename |
|
42 | PyBytes::new(py, &filename), | |
39 | decapsule_make_dirstate_tuple(py)?( |
|
43 | decapsule_make_dirstate_tuple(py)?( | |
40 | entry.state as c_char, |
|
44 | entry.state as c_char, | |
41 | entry.mode, |
|
45 | entry.mode, | |
@@ -44,15 +48,17 b' fn parse_dirstate_wrapper(' | |||||
44 | ), |
|
48 | ), | |
45 | )?; |
|
49 | )?; | |
46 | } |
|
50 | } | |
47 |
for |
|
51 | for (path, copy_path) in copies { | |
48 | copymap.set_item( |
|
52 | copymap.set_item( | |
49 | py, |
|
53 | py, | |
50 | PyBytes::new(py, path), |
|
54 | PyBytes::new(py, &path), | |
51 | PyBytes::new(py, copy_path), |
|
55 | PyBytes::new(py, ©_path), | |
52 | )?; |
|
56 | )?; | |
53 | } |
|
57 | } | |
54 | Ok((PyBytes::new(py, parents.p1), PyBytes::new(py, parents.p2)) |
|
58 | Ok( | |
55 | .to_py_object(py)) |
|
59 | (PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2)) | |
|
60 | .to_py_object(py), | |||
|
61 | ) | |||
56 | } |
|
62 | } | |
57 | Err(e) => Err(PyErr::new::<exc::ValueError, _>( |
|
63 | Err(e) => Err(PyErr::new::<exc::ValueError, _>( | |
58 | py, |
|
64 | py, | |
@@ -64,6 +70,9 b' fn parse_dirstate_wrapper(' | |||||
64 | "overflow in dirstate".to_string() |
|
70 | "overflow in dirstate".to_string() | |
65 | } |
|
71 | } | |
66 | DirstateParseError::CorruptedEntry(e) => e, |
|
72 | DirstateParseError::CorruptedEntry(e) => e, | |
|
73 | DirstateParseError::Damaged => { | |||
|
74 | "dirstate appears to be damaged".to_string() | |||
|
75 | } | |||
67 | }, |
|
76 | }, | |
68 | )), |
|
77 | )), | |
69 | } |
|
78 | } | |
@@ -81,7 +90,7 b' fn pack_dirstate_wrapper(' | |||||
81 | let p2 = pl.get_item(py, 1).extract::<PyBytes>(py)?; |
|
90 | let p2 = pl.get_item(py, 1).extract::<PyBytes>(py)?; | |
82 | let p2: &[u8] = p2.data(py); |
|
91 | let p2: &[u8] = p2.data(py); | |
83 |
|
92 | |||
84 |
let dirstate_ |
|
93 | let mut dirstate_map = extract_dirstate(py, &dmap)?; | |
85 |
|
94 | |||
86 | let copies: Result<HashMap<Vec<u8>, Vec<u8>>, PyErr> = copymap |
|
95 | let copies: Result<HashMap<Vec<u8>, Vec<u8>>, PyErr> = copymap | |
87 | .items(py) |
|
96 | .items(py) | |
@@ -94,13 +103,23 b' fn pack_dirstate_wrapper(' | |||||
94 | }) |
|
103 | }) | |
95 | .collect(); |
|
104 | .collect(); | |
96 |
|
105 | |||
|
106 | if p1.len() != PARENT_SIZE || p2.len() != PARENT_SIZE { | |||
|
107 | return Err(PyErr::new::<exc::ValueError, _>( | |||
|
108 | py, | |||
|
109 | "expected a 20-byte hash".to_string(), | |||
|
110 | )); | |||
|
111 | } | |||
|
112 | ||||
97 | match pack_dirstate( |
|
113 | match pack_dirstate( | |
98 |
&dirstate_ |
|
114 | &mut dirstate_map, | |
99 | &copies?, |
|
115 | &copies?, | |
100 |
DirstateParents { |
|
116 | DirstateParents { | |
101 | now.as_object().extract::<i32>(py)?, |
|
117 | p1: copy_into_array(&p1), | |
|
118 | p2: copy_into_array(&p2), | |||
|
119 | }, | |||
|
120 | Duration::from_secs(now.value(py) as u64), | |||
102 | ) { |
|
121 | ) { | |
103 |
Ok( |
|
122 | Ok(packed) => { | |
104 | for ( |
|
123 | for ( | |
105 | filename, |
|
124 | filename, | |
106 | DirstateEntry { |
|
125 | DirstateEntry { | |
@@ -109,7 +128,7 b' fn pack_dirstate_wrapper(' | |||||
109 | size, |
|
128 | size, | |
110 | mtime, |
|
129 | mtime, | |
111 | }, |
|
130 | }, | |
112 |
) in |
|
131 | ) in dirstate_map | |
113 | { |
|
132 | { | |
114 | dmap.set_item( |
|
133 | dmap.set_item( | |
115 | py, |
|
134 | py, |
General Comments 0
You need to be logged in to leave comments.
Login now