Files
sausage/userland/git/src/inspect.rs
T

93 lines
2.8 KiB
Rust

//! Read Git object types, sizes, contents, and tree entries without changing repository state.
use crate::{Result, repo::error};
use std::io::Write;
pub(crate) fn cat_file(
repo: &gix::Repository,
revision: &str,
kind: bool,
size: bool,
exists: bool,
) -> Result<()> {
let object = repo
.rev_parse_single(revision)
.map_err(|e| error("cat-file", e))?
.object()
.map_err(|e| error("cat-file", e))?;
if exists {
return Ok(());
}
if kind {
println!("{}", object.kind);
} else if size {
println!("{}", object.data.len());
} else if object.kind == gix::objs::Kind::Tree {
ls_tree(repo, revision, false, false, None)?;
} else {
std::io::stdout()
.write_all(&object.data)
.map_err(|e| error("cat-file", e))?;
}
Ok(())
}
pub(crate) fn ls_tree(
repo: &gix::Repository,
revision: &str,
recursive: bool,
names: bool,
path: Option<&str>,
) -> Result<()> {
let id = crate::local::tree(repo, revision)?;
fn walk(
repo: &gix::Repository,
id: gix::ObjectId,
prefix: &str,
recursive: bool,
names: bool,
filter: Option<&str>,
) -> Result<()> {
let tree = repo.find_tree(id).map_err(|e| error("ls-tree", e))?;
for entry in tree.iter() {
let entry = entry.map_err(|e| error("ls-tree", e))?;
let filename = format!("{prefix}{}", entry.filename());
let directory = entry.mode().is_tree();
let descend = directory
&& (recursive
|| filter.is_some_and(|path| path.starts_with(&format!("{filename}/"))));
if descend {
walk(
repo,
entry.oid().to_owned(),
&format!("{filename}/"),
recursive,
names,
filter,
)?;
} else if filter.is_none_or(|path| {
filename == path
|| filename.starts_with(&format!("{}/", path.trim_end_matches('/')))
}) {
if names {
println!("{filename}");
} else {
let kind = if directory {
"tree"
} else if entry.mode().is_commit() {
"commit"
} else {
"blob"
};
println!(
"{:06o} {kind} {}\t{filename}",
entry.mode().kind() as u32,
entry.oid()
);
}
}
}
Ok(())
}
walk(repo, id, "", recursive, names, path)
}