🎉 init
This commit is contained in:
commit
bc6e30fe0c
6 changed files with 609 additions and 0 deletions
40
src/args.rs
Normal file
40
src/args.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use clap::{arg, command};
|
||||
|
||||
pub fn get_args() -> clap::ArgMatches {
|
||||
command!()
|
||||
.about("snapshot utility")
|
||||
.subcommand(
|
||||
command!("ls")
|
||||
.about("List all snapshots")
|
||||
.arg(
|
||||
arg!(-d --depth <DEPTH> "How deep to search for cephfs snapshots")
|
||||
.default_value("5"),
|
||||
)
|
||||
.arg(
|
||||
arg!(<START_DIR> "Starting directory to search")
|
||||
.default_value(".")
|
||||
.required(false),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
command!("create")
|
||||
.about("Create a snapshot")
|
||||
.arg(arg!(-n --name <NAME> "The name of the snapshot"))
|
||||
.arg(
|
||||
arg!(<DIR> "The directory to snapshot")
|
||||
.default_value(".")
|
||||
.required(false),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
command!("remove")
|
||||
.about("Remove a snapshot")
|
||||
.arg(arg!(<NAME> "The name of the snapshot").required(true))
|
||||
.arg(
|
||||
arg!(<DIR> "The directory containing the snapshot")
|
||||
.default_value(".")
|
||||
.required(false),
|
||||
),
|
||||
)
|
||||
.get_matches()
|
||||
}
|
124
src/main.rs
Normal file
124
src/main.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
use args::get_args;
|
||||
|
||||
mod args;
|
||||
|
||||
pub fn cephfs_snapshot(dir: &str, name: &str) {
|
||||
std::fs::create_dir(std::path::Path::new(dir).join(".snap").join(name)).unwrap();
|
||||
}
|
||||
|
||||
pub fn cephfs_snapshot_remove(dir: &str, name: &str) {
|
||||
std::fs::remove_dir(std::path::Path::new(dir).join(".snap").join(name)).unwrap();
|
||||
}
|
||||
|
||||
pub fn cephfs_find_snap(dir: &str, depth: u16) -> Vec<String> {
|
||||
let mut result = Vec::new();
|
||||
let start_path = std::path::Path::new(dir);
|
||||
|
||||
// Call the recursive helper function
|
||||
find_snap_recursive(start_path, depth, 0, &mut result);
|
||||
result
|
||||
}
|
||||
|
||||
fn find_snap_recursive(
|
||||
dir: &std::path::Path,
|
||||
max_depth: u16,
|
||||
current_depth: u16,
|
||||
result: &mut Vec<String>,
|
||||
) {
|
||||
// Stop recursion if we've reached the maximum depth
|
||||
if current_depth >= max_depth {
|
||||
return;
|
||||
}
|
||||
|
||||
let snap_dir = dir.join(".snap");
|
||||
if std::fs::read_dir(&snap_dir)
|
||||
.unwrap()
|
||||
.filter(|x| {
|
||||
!x.as_ref()
|
||||
.unwrap()
|
||||
.file_name()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.starts_with("_")
|
||||
})
|
||||
.count()
|
||||
!= 0
|
||||
{
|
||||
result.push(dir.display().to_string());
|
||||
}
|
||||
|
||||
// Read the directory content
|
||||
if let Ok(entries) = std::fs::read_dir(dir) {
|
||||
for entry in entries.filter_map(Result::ok) {
|
||||
let path = entry.path();
|
||||
|
||||
// If the entry is a directory, check if it contains a ".snap" directory
|
||||
if path.is_dir() {
|
||||
// Recurse into the directory
|
||||
find_snap_recursive(&path, max_depth, current_depth + 1, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cephfs_snap_show(dir: &str) -> std::io::Result<()> {
|
||||
// Create the path to the ".snap" directory
|
||||
let snap_dir = format!("{}/.snap", dir);
|
||||
let snap_path = std::path::Path::new(&snap_dir);
|
||||
|
||||
// Check if the .snap directory exists
|
||||
if !snap_path.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("Snapshots for {dir}:");
|
||||
|
||||
// List the contents of the .snap directory
|
||||
match std::fs::read_dir(snap_path) {
|
||||
Ok(entries) => {
|
||||
for entry in entries {
|
||||
match entry {
|
||||
Ok(entry) => {
|
||||
let entry_name = entry.file_name();
|
||||
println!("- {}", entry_name.to_string_lossy());
|
||||
}
|
||||
Err(_) => eprintln!("Error reading entry in .snap directory."),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => eprintln!("Error reading .snap directory: {}", e),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = get_args();
|
||||
|
||||
match args.subcommand() {
|
||||
Some(("ls", ls_args)) => {
|
||||
let depth: &String = ls_args.get_one("depth").unwrap();
|
||||
let start_dir: &String = ls_args.get_one("START_DIR").unwrap();
|
||||
|
||||
let snap_dirs = cephfs_find_snap(&start_dir, depth.parse().unwrap());
|
||||
snap_dirs.into_iter().for_each(|x| {
|
||||
cephfs_snap_show(&x).unwrap();
|
||||
});
|
||||
}
|
||||
Some(("create", c_args)) => {
|
||||
let name: Option<String> = c_args.get_one("NAME").cloned();
|
||||
let dir: &String = c_args.get_one("DIR").unwrap();
|
||||
let name = name.unwrap_or_else(|| {
|
||||
let now = chrono::Utc::now();
|
||||
now.format("SNAP_%Y_%m_%d-%H_%M").to_string()
|
||||
});
|
||||
cephfs_snapshot(&dir, &name);
|
||||
}
|
||||
Some(("remove", rm_args)) => {
|
||||
let name: &String = rm_args.get_one("NAME").unwrap();
|
||||
let dir: &String = rm_args.get_one("DIR").unwrap();
|
||||
cephfs_snapshot_remove(&dir, &name);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue