Lindenii Project Forge
Login

hare-git

Git library for Hare

Warning: Due to various recent migrations, viewing non-HEAD refs may be broken.

/cmd/show-object/main.ha (raw)

use fmt;
use fs;
use getopt;
use io;
use os;
use strings;

use git;

fn usage(cmd: *getopt::command) void = {
	getopt::printusage(os::stderr, os::args[0], cmd.help)!;
};

fn print_blob(b: git::blob) void = {
	io::write(os::stdout, b.data)!;
};

fn print_tree(t: git::tree) void = {
	for (let i = 0z; i < len(t.entries); i += 1z) {
		const ent = t.entries[i];

		const hex = git::oid_string(ent.oid)!;
		defer free(hex);

		const name = strings::fromutf8_unsafe(ent.name);
		fmt::printfln("{:o} {} {}", ent.mode, hex, name)!;
	};
};

fn print_ident(label: str, id: git::ident) void = {
	const name = strings::fromutf8_unsafe(id.name);
	const email = strings::fromutf8_unsafe(id.email);
	fmt::printfln("{} {} <{}> {} {}", label, name, email, id.when, id.ofs)!;
};

fn print_commit(c: git::commit) void = {
	const treehex = git::oid_string(c.tree)!;
	defer free(treehex);
	fmt::printfln("tree {}", treehex)!;

	for (let i = 0z; i < len(c.parents); i += 1z) {
		const phex = git::oid_string(c.parents[i])!;
		defer free(phex);
		fmt::printfln("parent {}", phex)!;
	};

	print_ident("author", c.author);
	print_ident("committer", c.committer);

	fmt::println("")!;

	const msg = strings::fromutf8_unsafe(c.message);
	fmt::println(msg)!;
};

export fn main() void = {
	let repo_path: (str | void) = void;

	let cmd = getopt::parse(
		os::args,
		"Print a Git object by OID",
		('r', "repo", "PATH to repo or .git"),
		"OID",
	);
	defer getopt::finish(&cmd);

	for (let opt .. cmd.opts) {
		switch (opt.0) {
		case 'r' =>
			repo_path = opt.1;
		case =>
			abort();
		};
	};

	if (len(cmd.args) != 1) {
		usage(&cmd);
		os::exit(2);
	};

	if (repo_path is void) {
		usage(&cmd);
		os::exit(2);
	};

	const rp = repo_path: str;

	let r = match (git::open(rp)) {
	case let rr: git::repo =>
		yield rr;
	case let fe: fs::error =>
		fmt::errorfln("open repo: {}", fs::strerror(fe))!;
		os::exit(1);
	};
	defer git::close(r);

	const oidhex = cmd.args[0];
	let id = match (git::parse_oid(oidhex)) {
	case let o: git::oid =>
		yield o;
	case =>
		fmt::errorfln("invalid oid: {}", oidhex)!;
		os::exit(1);
	};

	let obj = match (git::read_object(r, id)) {
	case let o: git::object =>
		yield o;
	case let fe: fs::error =>
		fmt::errorfln("fs error: {}", fs::strerror(fe))!;
		os::exit(1);
	case let ioe: io::error =>
		fmt::errorfln("io error: {}", io::strerror(ioe))!;
		os::exit(1);
	case =>
		fmt::errorfln("not a valid object: {}", oidhex)!;
		os::exit(1);
	};

	match (obj) {
	case let b: git::blob =>
		print_blob(b);
		git::blob_finish(b);
	case let t: git::tree =>
		print_tree(t);
		git::tree_finish(t);
	case let c: git::commit =>
		print_commit(c);
		git::commit_finish(c);
	};
};