Skip to content

Commit

Permalink
Use tmpdir for files
Browse files Browse the repository at this point in the history
  • Loading branch information
brumhard committed May 3, 2023
1 parent ca53e5b commit d23ed41
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 26 deletions.
47 changes: 44 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ futures = "0.3.28"
serde = "1.0.160"
serde_json = "1.0.96"
tar = "0.4.38"
tempfile = "3.5.0"
tokio = { version = "1.28.0", features = ["full"] }
tracing = "0.1.37"
tracing-subscriber = "0.3.17"
7 changes: 4 additions & 3 deletions maskfile.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

## test-run

> builds the test docker image and runs
> builds the test docker image and runs dump
```sh
image_name="reinlinsen-test"
rm -rf "$image_name"*
out_dir="$image_name-fs"
rm -rf "$out_dir"
docker build -f test.Dockerfile -t "$image_name" .
cargo run -- --image "$image_name" dump
cargo run -- --image "$image_name" dump -o "$out_dir"
```
52 changes: 32 additions & 20 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::sync::Arc;
use tar::Archive;
use tempfile::tempfile;
use tokio::fs::OpenOptions;
use tokio::io::AsyncWriteExt;
use tokio::sync::Mutex;
Expand All @@ -35,13 +36,16 @@ enum Commands {
/// subcommands that operatate on single layers
Layer {
#[arg(long, short)]
layer: u8,
layer: usize,

#[command(subcommand)]
command: LayerCommands,
},
/// full dump of all layers
Dump {},
Dump {
#[arg(long, short)]
output: PathBuf,
},
/// extract a file from the full dump
Extract {},
}
Expand All @@ -65,36 +69,44 @@ enum LayerCommands {
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt().init();
let cli = Cli::parse();

if !matches!(cli.command, Commands::Dump {}) {
todo!()
}
let cli = Cli::try_parse()?;

let tmp_dir = tempfile::tempdir()?;
let base_name = name_from_image(&cli.image);
let tar_file = format!("{base_name}.tar");
save_image(&cli.image, &tar_file).await?;
extract_tar(&tar_file, &base_name)?;

let manifest = read_manifest(&format!("{base_name}/manifest.json"))?;
let config = read_config(&format! {"{}/{}", base_name, manifest.config})?;
extract_layers(&manifest.layers, &base_name, &format!("{base_name}-fs"))?;
let archive_path = tmp_dir.path().join(format!("{base_name}.tar"));
save_image(&cli.image, &archive_path).await?;

let unpack_path = tmp_dir.path().join(&base_name);
extract_tar(&archive_path, &unpack_path)?;

let manifest_path = unpack_path.join("manifest.json");
let manifest = read_manifest(&manifest_path)?;

let config_path = unpack_path.join(manifest.config);
let config = read_config(&config_path)?;

if let Commands::Dump { output } = cli.command {
extract_layers(&manifest.layers, &unpack_path, &output)?;
} else {
todo!()
}

Ok(())
}

#[instrument(skip(layers))]
fn extract_layers<P: AsRef<Path> + Debug + Display>(
fn extract_layers<P: AsRef<Path> + Debug>(
layers: &[String],
tar_dir: P,
unpack_path: P,
out_dir: P,
) -> Result<()> {
_ = fs::remove_dir_all(&out_dir);
fs::create_dir(&out_dir)?;

for layer in layers {
tracing::info!(layer, "unpacking layer");
let file = File::open(format!("{tar_dir}/{layer}"))?;
let file = File::open(unpack_path.as_ref().join(&layer))?;
let mut archive = Archive::new(file);
for file in archive.entries()? {
let mut f = file?;
Expand Down Expand Up @@ -151,13 +163,13 @@ struct HistoryEntry {
comment: String,
}

fn read_config(path: &str) -> Result<Config> {
fn read_config<P: AsRef<Path> + Debug>(path: P) -> Result<Config> {
let config_str = fs::read_to_string(path)?;
let config: Config = serde_json::from_str(&config_str)?;
Ok(config)
}

fn read_manifest(path: &str) -> Result<Manifest> {
fn read_manifest<P: AsRef<Path> + Debug>(path: P) -> Result<Manifest> {
let manifest_str = fs::read_to_string(path)?;
let mut manifests: Vec<Manifest> = serde_json::from_str(&manifest_str)?;

Expand All @@ -169,9 +181,9 @@ fn read_manifest(path: &str) -> Result<Manifest> {
}

#[instrument]
fn extract_tar<P: AsRef<Path> + Debug>(path: P, out_dir: P) -> Result<()> {
fn extract_tar<P: AsRef<Path> + Debug>(archive_path: P, out_dir: P) -> Result<()> {
tracing::info!("recreating output dir");
let file = File::open(path)?;
let file = File::open(archive_path)?;
_ = fs::remove_dir_all(&out_dir);
fs::create_dir(&out_dir)?;

Expand Down

0 comments on commit d23ed41

Please sign in to comment.