Skip to content

Commit 573b58b

Browse files
committed
nydus-image: enhance unpack command to support extracting files to dir
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 <[email protected]>
1 parent c9fbce8 commit 573b58b

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

src/bin/nydus-image/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ fn prepare_cmd_args(bti_string: &'static str) -> App {
720720
.arg(
721721
Arg::new("output")
722722
.long("output")
723-
.help("path for output tar file")
723+
.help("Path for output tar file, If it is a directory, extract all files to there.")
724724
.required(true),
725725
),
726726
)

src/bin/nydus-image/unpack/mod.rs

+30-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// SPDX-License-Identifier: Apache-2.0
55
use std::collections::HashMap;
6-
use std::fs::{File, OpenOptions};
6+
use std::fs::{create_dir_all, remove_file, File, OpenOptions};
77
use std::io::Read;
88
use std::path::{Path, PathBuf};
99
use std::rc::Rc;
@@ -18,7 +18,7 @@ use nydus_rafs::{
1818
};
1919
use nydus_storage::backend::BlobBackend;
2020
use nydus_storage::device::BlobInfo;
21-
use tar::{Builder, Header};
21+
use tar::{Archive, Builder, Header};
2222

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

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

7676
let rafs = self.load_rafs(config)?;
7777

78+
// If self.output ends with path separator, then it is a dir.
79+
// Output a tar file first, and untar it later.
80+
let is_dir = self.output.to_string_lossy().ends_with(std::path::MAIN_SEPARATOR);
81+
let mut tar_path = self.output.clone();
82+
if is_dir {
83+
if !self.output.exists() {
84+
create_dir_all(&self.output)?;
85+
}
86+
let mut base_name = self
87+
.bootstrap
88+
.file_name()
89+
.unwrap_or_default()
90+
.to_os_string();
91+
base_name.push(".tar");
92+
tar_path = PathBuf::from(base_name);
93+
}
94+
7895
let mut builder = self
7996
.builder_factory
80-
.create(&rafs, &self.blob_backend, &self.output)?;
97+
.create(&rafs, &self.blob_backend, &tar_path)?;
8198

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

103+
// untar this tar file to self.output dir
104+
if is_dir {
105+
let file = File::open(&tar_path)?;
106+
let mut tar = Archive::new(file);
107+
tar.unpack(&self.output)?;
108+
remove_file(&tar_path)?;
109+
}
110+
86111
Ok(())
87112
}
88113
}

0 commit comments

Comments
 (0)