Unified · Split
| @@ -1,3 +1,4 @@ | ||
| 1 | +use std::io::Read; | |
| 1 | 2 | use std::{ |
| 2 | 3 | collections::BTreeMap, |
| 3 | 4 | path::{Path, PathBuf}, |
| @@ -186,12 +187,12 @@ fn create_archive_if_not_on_ci(source_dir: &Path, archive: &Path, script_identit · 182 unmodified lines | ||
| 186 | 187 | res |
| 187 | 188 | } |
| 188 | 189 | |
| 189 | −const META_NAME: &str = "__gitoxide_meta__"; | |
| 190 | +const META_DIR_NAME: &str = "__gitoxide_meta__"; | |
| 190 | 191 | const META_IDENTITY: &str = "identity"; |
| 191 | 192 | const META_GIT_VERSION: &str = "git-version"; |
| 192 | 193 | |
| 193 | 194 | fn populate_meta_dir(destination_dir: &Path, script_identity: u32) -> std::io::Result<PathBuf> { |
| 194 | − let meta_dir = destination_dir.join(META_NAME); | |
| 195 | + let meta_dir = destination_dir.join(META_DIR_NAME); | |
| 195 | 196 | std::fs::create_dir_all(&meta_dir)?; |
| 196 | 197 | std::fs::write(meta_dir.join(META_IDENTITY), format!("{}", script_identity).as_bytes())?; |
| 197 | 198 | std::fs::write( |
| @@ -203,10 +204,46 @@ fn populate_meta_dir(destination_dir: &Path, script_identity: u32) -> std::io::R · 5 unmodified lines | ||
| 203 | 204 | |
| 204 | 205 | /// `required_script_identity` is the identity of the script that generated the state that is contained in `archive`. |
| 205 | 206 | /// If this is not the case, the arvhive will be ignored. |
| 206 | −fn extract_archive(_archive: &Path, destination_dir: &Path, _required_script_identity: u32) -> std::io::Result<()> { | |
| 207 | +fn extract_archive(archive: &Path, destination_dir: &Path, required_script_identity: u32) -> std::io::Result<()> { | |
| 207 | 208 | std::fs::create_dir_all(destination_dir)?; |
| 208 | − // TODO | |
| 209 | − Err(std::io::ErrorKind::NotFound.into()) | |
| 209 | + | |
| 210 | + let mut archive_buf = Vec::<u8>::new(); | |
| 211 | + let mut decoder = xz2::bufread::XzDecoder::new(std::io::BufReader::new(std::fs::File::open(archive)?)); | |
| 212 | + std::io::copy(&mut decoder, &mut archive_buf)?; | |
| 213 | + | |
| 214 | + let mut entry_buf = Vec::<u8>::new(); | |
| 215 | + let archive_identity: u32 = tar::Archive::new(std::io::Cursor::new(&mut &*archive_buf)) | |
| 216 | + .entries_with_seek()? | |
| 217 | + .filter_map(|e| e.ok()) | |
| 218 | + .find_map(|mut e: tar::Entry<'_, _>| { | |
| 219 | + let path = e.path().ok()?; | |
| 220 | + if path.parent()?.file_name()? == META_DIR_NAME && path.file_name()? == META_IDENTITY { | |
| 221 | + entry_buf.clear(); | |
| 222 | + e.read_to_end(&mut entry_buf).ok()?; | |
| 223 | + entry_buf.to_str().ok()?.trim().parse().ok() | |
| 224 | + } else { | |
| 225 | + None | |
| 226 | + } | |
| 227 | + }) | |
| 228 | + .ok_or_else(|| { | |
| 229 | + std::io::Error::new( | |
| 230 | + std::io::ErrorKind::Other, | |
| 231 | + "BUG: Could not find meta directory in our own archive", | |
| 232 | + ) | |
| 233 | + })?; | |
| 234 | + if archive_identity != required_script_identity { | |
| 235 | + return Err(std::io::ErrorKind::NotFound.into()); | |
| 236 | + } | |
| 237 | + | |
| 238 | + for entry in tar::Archive::new(&mut &*archive_buf).entries()? { | |
| 239 | + let mut entry = entry?; | |
| 240 | + let path = entry.path()?; | |
| 241 | + if path.to_str() == Some(META_DIR_NAME) || path.parent().and_then(|p| p.to_str()) == Some(META_DIR_NAME) { | |
| 242 | + continue; | |
| 243 | + } | |
| 244 | + entry.unpack_in(&destination_dir)?; | |
| 245 | + } | |
| 246 | + Ok(()) | |
| 210 | 247 | } |
| 211 | 248 | |
| 212 | 249 | pub fn to_bstr_err(err: nom::Err<VerboseError<&[u8]>>) -> VerboseError<&BStr> { |