cat: Add tree subcommand

This commit is contained in:
Alexander Weiss 2022-03-03 16:46:06 +01:00
parent b72f798ba5
commit fbb27c4cef

View File

@ -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(());
}