Skip to content

Commit f9dfa45

Browse files
committed
feat(client-cli): implement directory copy functionality
1 parent 77fec9a commit f9dfa45

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

mithril-client-cli/src/utils/fs.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
use std::{
2+
fs,
3+
path::{Path, PathBuf},
4+
};
5+
6+
use anyhow::{anyhow, Context};
7+
8+
use mithril_client::MithrilResult;
9+
10+
/// Copies a directory and its contents to a new location.
11+
pub fn copy_dir(source_dir: &Path, target_dir: &Path) -> MithrilResult<PathBuf> {
12+
let source_dir_name = source_dir
13+
.file_name()
14+
.ok_or_else(|| anyhow!("Invalid source directory: {}", source_dir.display()))?;
15+
let destination_path = target_dir.join(source_dir_name);
16+
copy_dir_contents(source_dir, &destination_path)?;
17+
18+
Ok(destination_path)
19+
}
20+
21+
fn copy_dir_contents(source_dir: &Path, target_dir: &Path) -> MithrilResult<()> {
22+
fs::create_dir_all(target_dir).with_context(|| {
23+
format!(
24+
"Failed to create target directory: {}",
25+
target_dir.display()
26+
)
27+
})?;
28+
29+
for entry in fs::read_dir(source_dir)? {
30+
let entry = entry?;
31+
let file_type = entry.file_type()?;
32+
let src_path = entry.path();
33+
let dst_path = target_dir.join(entry.file_name());
34+
35+
if file_type.is_dir() {
36+
copy_dir_contents(&src_path, &dst_path)?;
37+
} else {
38+
fs::copy(&src_path, &dst_path).with_context(|| {
39+
format!(
40+
"Failed to copy file '{}' to '{}'",
41+
src_path.display(),
42+
dst_path.display()
43+
)
44+
})?;
45+
}
46+
}
47+
48+
Ok(())
49+
}
50+
51+
#[cfg(test)]
52+
mod tests {
53+
use std::fs::File;
54+
55+
use mithril_common::{assert_dir_eq, temp_dir_create};
56+
57+
use super::*;
58+
59+
#[test]
60+
fn fails_if_source_does_not_exist() {
61+
let temp_dir = temp_dir_create!();
62+
let dir_not_exist = PathBuf::from("dir_not_exist");
63+
64+
copy_dir(&dir_not_exist, &temp_dir)
65+
.expect_err("Expected error when source directory does not exist");
66+
}
67+
68+
#[test]
69+
fn returns_copied_directory_path() {
70+
let temp_dir = temp_dir_create!();
71+
let src = temp_dir.join("dir_to_copy");
72+
fs::create_dir(&src).unwrap();
73+
let dst = temp_dir.join("dst");
74+
75+
let copied_dir_path = copy_dir(&src, &dst).unwrap();
76+
77+
assert_eq!(copied_dir_path, dst.join("dir_to_copy"));
78+
}
79+
80+
#[test]
81+
fn copies_nested_directories_and_files() {
82+
let temp_dir = temp_dir_create!();
83+
let src = temp_dir.join("dir_to_copy");
84+
fs::create_dir(&src).unwrap();
85+
File::create(src.join("root.txt")).unwrap();
86+
87+
let sub_dir1 = src.join("subdir1");
88+
fs::create_dir(&sub_dir1).unwrap();
89+
File::create(sub_dir1.join("subdir1.txt")).unwrap();
90+
91+
let sub_dir2 = src.join("subdir2");
92+
fs::create_dir(&sub_dir2).unwrap();
93+
File::create(sub_dir2.join("subdir2.txt")).unwrap();
94+
95+
let dst = temp_dir.join("dst");
96+
97+
copy_dir(&src, &dst).unwrap();
98+
99+
assert_dir_eq!(
100+
&dst,
101+
"* dir_to_copy/
102+
** subdir1/
103+
*** subdir1.txt
104+
** subdir2/
105+
*** subdir2.txt
106+
** root.txt"
107+
);
108+
}
109+
}

mithril-client-cli/src/utils/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod cardano_db;
66
mod cardano_db_download_checker;
77
mod expander;
88
mod feedback_receiver;
9+
mod fs;
910
mod github_release_retriever;
1011
mod http_downloader;
1112
mod multi_download_progress_reporter;
@@ -16,6 +17,7 @@ pub use cardano_db::*;
1617
pub use cardano_db_download_checker::*;
1718
pub use expander::*;
1819
pub use feedback_receiver::*;
20+
pub use fs::*;
1921
pub use github_release_retriever::*;
2022
pub use http_downloader::*;
2123
pub use multi_download_progress_reporter::*;

0 commit comments

Comments
 (0)