Skip to content

Commit

Permalink
nydus-image: enhance unpack command to support extracting files to dir
Browse files Browse the repository at this point in the history
When --output is specified as a directory, the nydus-image unpack
command will return an error, which is not convenient for users.

This patch enhances this command to allow --output to be passed into a
dir. In this case, nydus-image will extract all files into this dir.

Signed-off-by: Qinqi Qu <quqinqi@linux.alibaba.com>
  • Loading branch information
adamqqqplay committed Nov 10, 2023
1 parent c9fbce8 commit 573b58b
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/bin/nydus-image/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ fn prepare_cmd_args(bti_string: &'static str) -> App {
.arg(
Arg::new("output")
.long("output")
.help("path for output tar file")
.help("Path for output tar file, If it is a directory, extract all files to there.")
.required(true),
),
)
Expand Down
35 changes: 30 additions & 5 deletions src/bin/nydus-image/unpack/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//
// SPDX-License-Identifier: Apache-2.0
use std::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::fs::{create_dir_all, remove_file, File, OpenOptions};
use std::io::Read;
use std::path::{Path, PathBuf};
use std::rc::Rc;
Expand All @@ -18,7 +18,7 @@ use nydus_rafs::{
};
use nydus_storage::backend::BlobBackend;
use nydus_storage::device::BlobInfo;
use tar::{Builder, Header};
use tar::{Archive, Builder, Header};

use self::pax::{
OCIBlockBuilder, OCICharBuilder, OCIDirBuilder, OCIFifoBuilder, OCILinkBuilder, OCIRegBuilder,
Expand All @@ -32,7 +32,7 @@ pub trait Unpacker {
fn unpack(&self, config: Arc<ConfigV2>) -> Result<()>;
}

/// A unpacker with the ability to convert bootstrap file and blob file to tar
/// A unpacker with the ability to convert bootstrap file and blob file to tar or dir.
pub struct OCIUnpacker {
bootstrap: PathBuf,
blob_backend: Option<Arc<dyn BlobBackend + Send + Sync>>,
Expand Down Expand Up @@ -69,20 +69,45 @@ impl OCIUnpacker {
impl Unpacker for OCIUnpacker {
fn unpack(&self, config: Arc<ConfigV2>) -> Result<()> {
debug!(
"oci unpacker, bootstrap file: {:?}, output file: {:?}",
"oci unpacker, bootstrap file: {:?}, output path: {:?}",
self.bootstrap, self.output
);

let rafs = self.load_rafs(config)?;

// If self.output ends with path separator, then it is a dir.
// Output a tar file first, and untar it later.
let is_dir = self.output.to_string_lossy().ends_with(std::path::MAIN_SEPARATOR);
let mut tar_path = self.output.clone();
if is_dir {
if !self.output.exists() {
create_dir_all(&self.output)?;
}
let mut base_name = self
.bootstrap
.file_name()
.unwrap_or_default()
.to_os_string();
base_name.push(".tar");
tar_path = PathBuf::from(base_name);
}

let mut builder = self
.builder_factory
.create(&rafs, &self.blob_backend, &self.output)?;
.create(&rafs, &self.blob_backend, &tar_path)?;

for (node, path) in RafsIterator::new(&rafs) {
builder.append(node, &path)?;
}

// untar this tar file to self.output dir
if is_dir {
let file = File::open(&tar_path)?;
let mut tar = Archive::new(file);
tar.unpack(&self.output)?;
remove_file(&tar_path)?;
}

Ok(())
}
}
Expand Down

0 comments on commit 573b58b

Please sign in to comment.