mirror of
https://github.com/rustic-rs/rustic.git
synced 2025-10-26 11:18:51 +00:00
cat: Add tree subcommand
This commit is contained in:
parent
b72f798ba5
commit
fbb27c4cef
@ -1,56 +1,119 @@
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use clap::Parser;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
use crate::backend::{DecryptReadBackend, FileType, ReadBackend};
|
||||
use crate::blob::Tree;
|
||||
use crate::id::Id;
|
||||
use crate::index::{IndexBackend, ReadIndex};
|
||||
use crate::repo::SnapshotFile;
|
||||
|
||||
#[derive(Parser)]
|
||||
pub(super) struct Opts {
|
||||
/// file type to list
|
||||
tpe: String,
|
||||
#[clap(subcommand)]
|
||||
command: Command,
|
||||
}
|
||||
|
||||
/// file type to list
|
||||
#[derive(Subcommand)]
|
||||
enum Command {
|
||||
Blob(IdOpt),
|
||||
Config(IdOpt),
|
||||
Index(IdOpt),
|
||||
Snapshot(IdOpt),
|
||||
Key(IdOpt),
|
||||
/// display a tree within a snapshot
|
||||
Tree(TreeOpts),
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct IdOpt {
|
||||
/// id to cat
|
||||
id: String,
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct TreeOpts {
|
||||
/// snapshot id
|
||||
id: String,
|
||||
|
||||
/// path within snapshot
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
pub(super) fn execute(
|
||||
be: &impl ReadBackend,
|
||||
dbe: &impl DecryptReadBackend,
|
||||
opts: Opts,
|
||||
) -> Result<()> {
|
||||
let tpe = match opts.tpe.as_str() {
|
||||
match opts.command {
|
||||
Command::Config(opt) => cat_file(dbe, FileType::Config, opt),
|
||||
Command::Index(opt) => cat_file(dbe, FileType::Index, opt),
|
||||
Command::Snapshot(opt) => cat_file(dbe, FileType::Snapshot, opt),
|
||||
// special treatment for catting key files: those need no decryption
|
||||
Command::Key(opt) => cat_file(be, FileType::Key, opt),
|
||||
// special treatment for catingg blobs: read the index and use it to locate the blob
|
||||
"blob" => {
|
||||
let id = Id::from_hex(&opts.id)?;
|
||||
println!("reading index files..");
|
||||
let index = IndexBackend::new(dbe)?;
|
||||
let dec = index
|
||||
.get_id(&id)
|
||||
.ok_or(anyhow!("blob not found in index"))?
|
||||
.read_data(dbe)?;
|
||||
print!("{}", String::from_utf8_lossy(&dec));
|
||||
return Ok(());
|
||||
}
|
||||
"config" => FileType::Config,
|
||||
"index" => FileType::Index,
|
||||
"snapshot" => FileType::Snapshot,
|
||||
"key" => FileType::Key,
|
||||
t => bail!("invalid type: {}", t),
|
||||
};
|
||||
Command::Blob(opt) => cat_blob(dbe, opt),
|
||||
// special treatment for cating a tree within a snapshot
|
||||
Command::Tree(opts) => cat_tree(dbe, opts),
|
||||
}
|
||||
}
|
||||
|
||||
let id = Id::from_hex(&opts.id).or_else(|_| {
|
||||
fn cat_file(be: &impl ReadBackend, tpe: FileType, opt: IdOpt) -> Result<()> {
|
||||
let id = Id::from_hex(&opt.id).or_else(|_| {
|
||||
// if the given id param is not a full Id, search for a suitable one
|
||||
be.find_starts_with(tpe, &[&opts.id])?.remove(0)
|
||||
be.find_starts_with(tpe, &[&opt.id])?.remove(0)
|
||||
})?;
|
||||
|
||||
let dec = match tpe {
|
||||
// special treatment for catting key files: those need no decryption
|
||||
FileType::Key => be.read_full(tpe, &id)?,
|
||||
_ => dbe.read_full(tpe, &id)?,
|
||||
};
|
||||
let dec = be.read_full(tpe, &id)?;
|
||||
|
||||
print!("{}", String::from_utf8_lossy(&dec));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cat_blob(be: &impl DecryptReadBackend, opt: IdOpt) -> Result<()> {
|
||||
let id = Id::from_hex(&opt.id)?;
|
||||
eprintln!("reading index files..");
|
||||
let index = IndexBackend::new(be)?;
|
||||
let dec = index
|
||||
.get_id(&id)
|
||||
.ok_or(anyhow!("blob not found in index"))?
|
||||
.read_data(be)?;
|
||||
print!("{}", String::from_utf8_lossy(&dec));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn cat_tree(be: &impl DecryptReadBackend, opts: TreeOpts) -> Result<()> {
|
||||
let snap = SnapshotFile::from_str(be, &opts.id, |_| true)?;
|
||||
|
||||
eprintln!("reading index files..");
|
||||
let index = IndexBackend::new(be)?;
|
||||
|
||||
let mut id = snap.tree;
|
||||
|
||||
for p in opts.path.iter() {
|
||||
let p = p.to_str().unwrap();
|
||||
// TODO: check for root instead
|
||||
if p == "/" {
|
||||
continue;
|
||||
}
|
||||
let tree = Tree::from_backend(&index, &id)?;
|
||||
|
||||
id = tree
|
||||
.nodes()
|
||||
.iter()
|
||||
.find(|node| node.name() == p)
|
||||
.unwrap()
|
||||
.subtree()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let dec = index
|
||||
.get_id(&id)
|
||||
.ok_or(anyhow!("blob not found in index"))?
|
||||
.read_data(be)?;
|
||||
print!("{}", String::from_utf8_lossy(&dec));
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user