1use std::path::PathBuf;
5
6use archiver_rs::{Archive, Compressed};
7use futures::TryFutureExt;
8
9use crate::pg_errors::{PgEmbedError, PgEmbedErrorType};
10use crate::pg_types::PgResult;
11
12fn unzip_txz(zip_file_path: &PathBuf, cache_dir: &PathBuf) -> Result<PathBuf, PgEmbedError> {
18 let mut zip = archiver_rs::Zip::open(zip_file_path.as_path()).map_err(|e| PgEmbedError {
19 error_type: PgEmbedErrorType::ReadFileError,
20 source: Some(Box::new(e)),
21 message: None,
22 })?;
23 let file_name = zip
24 .files()
25 .map_err(|e| PgEmbedError {
26 error_type: PgEmbedErrorType::UnpackFailure,
27 source: Some(Box::new(e)),
28 message: None,
29 })?
30 .into_iter()
31 .find(|name| name.ends_with(".txz"));
32 match file_name {
33 Some(file_name) => {
34 let mut target_path = cache_dir.clone();
36 target_path.push(&file_name);
37 zip.extract_single(&target_path.as_path(), file_name.clone())
38 .map_err(|e| PgEmbedError {
39 error_type: PgEmbedErrorType::UnpackFailure,
40 source: Some(Box::new(e)),
41 message: None,
42 })?;
43 Ok(target_path)
44 }
45 None => Err(PgEmbedError {
46 error_type: PgEmbedErrorType::InvalidPgPackage,
47 source: None,
48 message: Some(String::from("no postgresql txz in zip")),
49 }),
50 }
51}
52
53fn decompress_xz(file_path: &PathBuf) -> Result<PathBuf, PgEmbedError> {
59 let mut xz = archiver_rs::Xz::open(file_path.as_path()).map_err(|e| PgEmbedError {
60 error_type: PgEmbedErrorType::ReadFileError,
61 source: Some(Box::new(e)),
62 message: None,
63 })?;
64 let target_path = file_path.with_extension(".tar");
66 xz.decompress(&target_path.as_path())
67 .map_err(|e| PgEmbedError {
68 error_type: PgEmbedErrorType::UnpackFailure,
69 source: Some(Box::new(e)),
70 message: None,
71 })?;
72 Ok(target_path)
73}
74
75fn decompress_tar(file_path: &PathBuf, cache_dir: &PathBuf) -> Result<(), PgEmbedError> {
81 let mut tar = archiver_rs::Tar::open(&file_path.as_path()).map_err(|e| PgEmbedError {
82 error_type: PgEmbedErrorType::ReadFileError,
83 source: Some(Box::new(e)),
84 message: None,
85 })?;
86
87 tar.extract(cache_dir.as_path()).map_err(|e| PgEmbedError {
88 error_type: PgEmbedErrorType::UnpackFailure,
89 source: Some(Box::new(e)),
90 message: None,
91 })?;
92
93 Ok(())
94}
95
96pub async fn unpack_postgres(zip_file_path: &PathBuf, cache_dir: &PathBuf) -> PgResult<()> {
102 let txz_file_path = unzip_txz(&zip_file_path, &cache_dir)?;
103 let tar_file_path = decompress_xz(&txz_file_path)?;
104 tokio::fs::remove_file(txz_file_path)
105 .map_err(|e| PgEmbedError {
106 error_type: PgEmbedErrorType::PgCleanUpFailure,
107 source: Some(Box::new(e)),
108 message: None,
109 })
110 .await?;
111 let _ = decompress_tar(&tar_file_path, &cache_dir);
112 tokio::fs::remove_file(tar_file_path)
113 .map_err(|e| PgEmbedError {
114 error_type: PgEmbedErrorType::PgCleanUpFailure,
115 source: Some(Box::new(e)),
116 message: None,
117 })
118 .await?;
119 Ok(())
120}