Skip to main content

pijul_core/change/
noenc.rs

1use super::{Atom, Change, Hashed, Local};
2#[cfg(feature = "zstd")]
3use super::{ChangeError, LocalChange, Offsets};
4use crate::Hash;
5#[cfg(feature = "zstd")]
6use crate::pristine::Hasher;
7
8#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
9pub enum Hunk<Hash, Local> {
10    FileMove {
11        del: Atom<Hash>,
12        add: Atom<Hash>,
13        path: String,
14    },
15    FileDel {
16        del: Atom<Hash>,
17        contents: Option<Atom<Hash>>,
18        path: String,
19    },
20    FileUndel {
21        undel: Atom<Hash>,
22        contents: Option<Atom<Hash>>,
23        path: String,
24    },
25    FileAdd {
26        add_name: Atom<Hash>,
27        add_inode: Atom<Hash>,
28        contents: Option<Atom<Hash>>,
29        path: String,
30    },
31    SolveNameConflict {
32        name: Atom<Hash>,
33        path: String,
34    },
35    UnsolveNameConflict {
36        name: Atom<Hash>,
37        path: String,
38    },
39    Edit {
40        change: Atom<Hash>,
41        local: Local,
42    },
43    Replacement {
44        change: Atom<Hash>,
45        replacement: Atom<Hash>,
46        local: Local,
47    },
48    SolveOrderConflict {
49        change: Atom<Hash>,
50        local: Local,
51    },
52    UnsolveOrderConflict {
53        change: Atom<Hash>,
54        local: Local,
55    },
56    ResurrectZombies {
57        change: Atom<Hash>,
58        local: Local,
59    },
60}
61
62impl<H, L> From<Hunk<H, L>> for super::Hunk<H, L> {
63    fn from(h: Hunk<H, L>) -> Self {
64        let encoding = Some(crate::text_encoding::Encoding(encoding_rs::UTF_8));
65        match h {
66            Hunk::FileMove { del, add, path } => super::Hunk::FileMove { del, add, path },
67            Hunk::FileDel {
68                del,
69                contents,
70                path,
71            } => super::Hunk::FileDel {
72                del,
73                contents,
74                path,
75                encoding,
76            },
77            Hunk::FileUndel {
78                undel,
79                contents,
80                path,
81            } => super::Hunk::FileUndel {
82                undel,
83                contents,
84                path,
85                encoding,
86            },
87            Hunk::FileAdd {
88                add_name,
89                add_inode,
90                contents,
91                path,
92            } => super::Hunk::FileAdd {
93                add_name,
94                add_inode,
95                contents,
96                path,
97                encoding,
98            },
99            Hunk::SolveNameConflict { name, path } => super::Hunk::SolveNameConflict { name, path },
100            Hunk::UnsolveNameConflict { name, path } => {
101                super::Hunk::UnsolveNameConflict { name, path }
102            }
103            Hunk::Edit { change, local } => super::Hunk::Edit {
104                change,
105                local,
106                encoding,
107            },
108            Hunk::Replacement {
109                change,
110                replacement,
111                local,
112            } => super::Hunk::Replacement {
113                change,
114                replacement,
115                local,
116                encoding,
117            },
118            Hunk::SolveOrderConflict { change, local } => {
119                super::Hunk::SolveOrderConflict { change, local }
120            }
121            Hunk::UnsolveOrderConflict { change, local } => {
122                super::Hunk::UnsolveOrderConflict { change, local }
123            }
124            Hunk::ResurrectZombies { change, local } => super::Hunk::ResurrectZombies {
125                change,
126                local,
127                encoding,
128            },
129        }
130    }
131}
132
133impl Change {
134    /// Deserialise a change from the file given as input `file`.
135    #[cfg(feature = "zstd")]
136    pub(super) fn deserialize_noenc(
137        offsets: Offsets,
138        mut r: std::fs::File,
139        hash: Option<&Hash>,
140    ) -> Result<Self, ChangeError> {
141        use std::io::Read;
142        let mut buf = vec![0u8; (offsets.unhashed_off - Self::OFFSETS_SIZE) as usize];
143        r.read_exact(&mut buf)?;
144
145        let hashed: Hashed<Hunk<Option<Hash>, Local>, Author> = {
146            let mut s = zstd_seekable::Seekable::init_buf(&buf[..])?;
147            let mut out = vec![0u8; offsets.hashed_len as usize];
148            s.decompress(&mut out[..], 0)?;
149            let mut hasher = Hasher::default();
150            hasher.update(&out);
151            let computed_hash = hasher.finish();
152            if let Some(hash) = hash
153                && &computed_hash != hash
154            {
155                return Err(super::ChangeError::ChangeHashMismatch {
156                    claimed: *hash,
157                    computed: computed_hash,
158                });
159            }
160            bincode::deserialize_from(&out[..])?
161        };
162        buf.clear();
163        buf.resize((offsets.contents_off - offsets.unhashed_off) as usize, 0);
164        let unhashed = if buf.is_empty() {
165            None
166        } else {
167            r.read_exact(&mut buf)?;
168            let mut s = zstd_seekable::Seekable::init_buf(&buf[..])?;
169            let mut out = vec![0u8; offsets.unhashed_len as usize];
170            s.decompress(&mut out[..], 0)?;
171            serde_json::from_slice(&out).ok()
172        };
173        trace!("unhashed = {:?}", unhashed);
174
175        buf.clear();
176        buf.resize((offsets.total - offsets.contents_off) as usize, 0);
177        let contents = if r.read_exact(&mut buf).is_ok() {
178            let mut s = zstd_seekable::Seekable::init_buf(&buf[..])?;
179            let mut contents = vec![0u8; offsets.contents_len as usize];
180            s.decompress(&mut contents[..], 0)?;
181            contents
182        } else {
183            Vec::new()
184        };
185        trace!("contents = {:?}", contents);
186
187        Ok(LocalChange {
188            offsets,
189            hashed: hashed.into(),
190            unhashed,
191            contents,
192        })
193    }
194}
195
196impl From<Hashed<Hunk<Option<Hash>, Local>, Author>>
197    for Hashed<super::Hunk<Option<Hash>, Local>, super::Author>
198{
199    fn from(hashed: Hashed<Hunk<Option<Hash>, Local>, Author>) -> Self {
200        Hashed {
201            contents_hash: hashed.contents_hash,
202            dependencies: hashed.dependencies,
203            extra_known: hashed.extra_known,
204            header: hashed.header.into(),
205            metadata: hashed.metadata,
206            version: hashed.version,
207            changes: hashed.changes.into_iter().map(|x| x.into()).collect(),
208        }
209    }
210}
211
212use super::ChangeHeader_;
213
214impl From<ChangeHeader_<Author>> for ChangeHeader_<super::Author> {
215    fn from(c: ChangeHeader_<Author>) -> Self {
216        ChangeHeader_ {
217            message: c.message,
218            description: c.description,
219            timestamp: c.timestamp,
220            authors: c.authors.into_iter().map(|x| x.into()).collect(),
221        }
222    }
223}
224
225#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
226pub struct Author {
227    pub name: String,
228    #[serde(default)]
229    pub full_name: Option<String>,
230    #[serde(default)]
231    pub email: Option<String>,
232}
233
234impl From<String> for Author {
235    fn from(name: String) -> Author {
236        Author {
237            name,
238            ..Author::default()
239        }
240    }
241}
242
243impl From<Author> for super::Author {
244    fn from(c: Author) -> Self {
245        let mut b = std::collections::BTreeMap::new();
246        b.insert("name".to_string(), c.name);
247        if let Some(n) = c.full_name {
248            b.insert("full_name".to_string(), n);
249        }
250        if let Some(n) = c.email {
251            b.insert("email".to_string(), n);
252        }
253        super::Author(b)
254    }
255}