Skip to content

Commit 56b95d7

Browse files
committed
feat(client-cli): implement unpack of Cardano node distribution
1 parent 4851896 commit 56b95d7

File tree

8 files changed

+438
-0
lines changed

8 files changed

+438
-0
lines changed

Cargo.lock

Lines changed: 144 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mithril-client-cli/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ chrono = { workspace = true }
3131
clap = { workspace = true }
3232
cli-table = "0.5.0"
3333
config = { workspace = true }
34+
flate2 = "1.1.1"
3435
fs2 = "0.4.3"
3536
futures = "0.3.31"
3637
human_bytes = { version = "0.4.3", features = ["fast"] }
@@ -48,8 +49,10 @@ slog = { workspace = true, features = [
4849
slog-async = { workspace = true }
4950
slog-bunyan = { workspace = true }
5051
slog-term = { workspace = true }
52+
tar = "0.4.44"
5153
thiserror = { workspace = true }
5254
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
55+
zip = "4.0.0"
5356

5457
[dev-dependencies]
5558
mithril-common = { path = "../mithril-common", features = ["test_tools"] }
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
mod tar_gz_unpacker;
2+
mod zip_unpacker;
3+
4+
pub use tar_gz_unpacker::*;
5+
pub use zip_unpacker::*;
6+
7+
use mithril_client::MithrilResult;
8+
use std::path::Path;
9+
10+
#[cfg_attr(test, mockall::automock)]
11+
pub trait ArchiveUnpacker {
12+
fn unpack(&self, archive_path: &Path, unpack_dir: &Path) -> MithrilResult<()>;
13+
14+
#[cfg(test)]
15+
fn as_any(&self) -> &dyn std::any::Any;
16+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use std::{fs::File, path::Path};
2+
3+
use anyhow::Context;
4+
use flate2::read::GzDecoder;
5+
use tar::Archive;
6+
7+
use mithril_client::MithrilResult;
8+
9+
use super::ArchiveUnpacker;
10+
11+
#[derive(Debug, Eq, PartialEq)]
12+
pub struct TarGzUnpacker;
13+
14+
impl ArchiveUnpacker for TarGzUnpacker {
15+
fn unpack(&self, archive_path: &Path, unpack_dir: &Path) -> MithrilResult<()> {
16+
let archive = File::open(archive_path)
17+
.with_context(|| format!("Could not open archive file '{}'", archive_path.display()))?;
18+
let gzip_decoder = GzDecoder::new(archive);
19+
let mut file_archive = Archive::new(gzip_decoder);
20+
file_archive.unpack(unpack_dir).with_context(|| {
21+
format!(
22+
"Could not unpack '{}' with 'Gzip' to directory '{}'",
23+
archive_path.display(),
24+
unpack_dir.display()
25+
)
26+
})?;
27+
28+
Ok(())
29+
}
30+
31+
#[cfg(test)]
32+
fn as_any(&self) -> &dyn std::any::Any {
33+
self
34+
}
35+
}
36+
37+
#[cfg(test)]
38+
mod tests {
39+
use std::fs::{self, File};
40+
41+
use flate2::{write::GzEncoder, Compression};
42+
use tar::{Builder, Header};
43+
44+
use mithril_common::temp_dir_create;
45+
46+
use super::*;
47+
48+
#[test]
49+
fn unpack_tar_archive_extracts_all_files() {
50+
let temp_dir = temp_dir_create!();
51+
let archive_path = temp_dir.join("archive.tar.gz");
52+
53+
{
54+
let tar_gz_file = File::create(&archive_path).unwrap();
55+
let encoder = GzEncoder::new(tar_gz_file, Compression::default());
56+
let mut tar_builder = Builder::new(encoder);
57+
58+
let content = b"root content";
59+
let mut header = Header::new_gnu();
60+
header.set_size(content.len() as u64);
61+
header.set_cksum();
62+
tar_builder
63+
.append_data(&mut header, "root.txt", &content[..])
64+
.unwrap();
65+
66+
let content = b"nested content";
67+
let mut header = Header::new_gnu();
68+
header.set_size(content.len() as u64);
69+
header.set_cksum();
70+
tar_builder
71+
.append_data(&mut header, "nested/dir/nested-file.txt", &content[..])
72+
.unwrap();
73+
74+
tar_builder.finish().unwrap();
75+
}
76+
77+
TarGzUnpacker.unpack(&archive_path, &temp_dir).unwrap();
78+
79+
let root_file = temp_dir.join("root.txt");
80+
assert!(root_file.exists());
81+
let root_file_content = fs::read_to_string(&root_file).unwrap();
82+
assert_eq!(root_file_content, "root content");
83+
84+
let nested_file = temp_dir.join("nested/dir/nested-file.txt");
85+
assert!(nested_file.exists());
86+
let nested_file_content = fs::read_to_string(&nested_file).unwrap();
87+
assert_eq!(nested_file_content, "nested content");
88+
}
89+
}

0 commit comments

Comments
 (0)