use std::io;
use std::io::prelude::*;
use anyhow::{Context, Result, anyhow};
use clap::Parser;
use tracing::*;
use crate::backend;
use crate::blob;
use crate::config::Configuration;
use crate::hashing::ObjectId;
use crate::index;
use crate::pack;
use crate::snapshot;
use crate::tree;
#[derive(Debug, Parser)]
pub struct Args {
#[clap(subcommand)]
subcommand: Subcommand,
}
#[derive(Debug, Parser)]
pub enum Subcommand {
#[clap(verbatim_doc_comment)]
Blob { id: ObjectId },
#[clap(verbatim_doc_comment)]
Pack { id: ObjectId },
#[clap(verbatim_doc_comment)]
Index { id: ObjectId },
#[clap(verbatim_doc_comment)]
Snapshot { id_prefix: String },
}
pub fn run(config: &Configuration, repository: &camino::Utf8Path, args: Args) -> Result<()> {
unsafe {
crate::prettify::prettify_serialize();
}
let (_cfg, cached_backend) = backend::open(
repository,
config.cache_size,
backend::CacheBehavior::Normal,
)?;
match args.subcommand {
Subcommand::Blob { id } => {
let index = index::build_master_index(&cached_backend)?;
let blob_map = index::blob_to_pack_map(&index)?;
let containing_pack_id = blob_map
.get(&id)
.ok_or_else(|| anyhow!("Can't find blob {} in the index", id))?;
info!("Blob {} found in pack {}", id, containing_pack_id);
let index_manifest = index.packs.get(containing_pack_id).unwrap();
let mut reader = cached_backend.read_pack(containing_pack_id)?;
let (manifest_entry, blob) = pack::extract_blob(&mut reader, &id, index_manifest)?;
debug_assert!(manifest_entry.id == id);
assert!(!blob.is_empty());
match manifest_entry.blob_type {
blob::Type::Chunk => io::stdout().write_all(&blob)?,
blob::Type::Tree => {
let tree: tree::Tree = ciborium::from_reader(&*blob)
.with_context(|| format!("CBOR decoding of tree {} failed", id))?;
serde_json::to_writer(io::stdout(), &tree)?;
}
}
}
Subcommand::Pack { id } => {
let manifest = pack::load_manifest(&id, &cached_backend)?;
serde_json::to_writer(io::stdout(), &manifest)?;
}
Subcommand::Index { id } => {
let index = index::load(&id, &cached_backend)?;
serde_json::to_writer(io::stdout(), &index)?;
}
Subcommand::Snapshot { id_prefix } => {
let chrono_list = snapshot::load_chronologically(&cached_backend)?;
let (snapshot, _id) = snapshot::find(&chrono_list, &id_prefix)?;
serde_json::to_writer(io::stdout(), &snapshot)?;
}
}
Ok(())
}