Lindenii Project Forge
Login

hare-git

WIP Git library for Hare

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

/git/object.ha (raw)

use bytes;
use crypto::sha256;
use errors;
use fmt;
use fs;
use hash;
use io;
use strconv;
use strings;

// Any Git object. [[tag]] will be supported in the future.
export type object = (blob | tree | commit);

// TODO: These should be enums instead of u8 constants.

// The tag for a commit object.
export def OBJ_COMMIT: u8    = 1u8;

// The tag for a tree object.
export def OBJ_TREE: u8      = 2u8;

// The tag for a blob object.
export def OBJ_BLOB: u8      = 3u8;

// The tag for a tag object.
export def OBJ_TAG: u8       = 4u8;

// The tag for an offset delta object in packfiles.
export def OBJ_OFS_DELTA: u8 = 6u8;

// The tag for a reference delta object in packfiles.
export def OBJ_REF_DELTA: u8 = 7u8;

// Frees resources associated with any Git object.
export fn object_finish(o: object) void = {
	match (o) {
	case let b: blob =>
		blob_finish(b);
	case let t: tree =>
		tree_finish(t);
	case let c: commit =>
		commit_finish(c);
	case =>
		abort("Unknown object type being freed...");
	};
};

// Formats a Git object ID as a hexadecimal string.
export fn verify_oid(buf: []u8, want: oid) bool = {
	let st = sha256::sha256();
	hash::write(&st, buf);
	let got: oid = [0...];
	hash::sum(&st, got);
	hash::close(&st);

	if (bytes::equal(got[..], want[..])) {
		return true;
	} else {
		return false;
	};
};

// Verifies that the given body matches the given object ID.
export fn verify_typed(ty: str, body: []u8, want: oid) bool = {
	let st = sha256::sha256();
	defer hash::close(&st);

	if (ty == "blob") {
		hash::write(&st, strings::toutf8("blob"));
	} else if (ty == "tree") {
		hash::write(&st, strings::toutf8("tree"));
	} else if (ty == "commit") {
		hash::write(&st, strings::toutf8("commit"));
	} else {
		return false;
	};

	hash::write(&st, strings::toutf8(" "));
	let szs = strconv::ztos(len(body));
	hash::write(&st, strings::toutf8(szs));
	hash::write(&st, strings::toutf8("\x00"));

	hash::write(&st, body);

	let got: oid = [0...];
	hash::sum(&st, got);

	if (bytes::equal(got[..], want[..])) {
		return true;
	} else {
		return false;
	};
};

// Reads a Git object from the repository by its ID.
export fn read_object(
	r: repo,
	id: oid,
) (object | fs::error | io::error | errors::invalid | strconv::invalid | strconv::overflow | nomem) = {
	match (read_loose(r, id)) {
	case let o: object =>
		return o;
	case let fe: fs::error =>
		if (fe is errors::noentry) {
			void;
		} else {
			return fe;
		};
	case let e: (io::error | errors::invalid | strconv::invalid | strconv::overflow | nomem) =>
		return e;
	};

	match (read_packed(r, id)) {
	case let o: object =>
		return o;
	case let fe: fs::error =>
		if (fe is errors::noentry) {
			return errors::invalid;
		} else {
			return fe;
		};
	case let e: (io::error | errors::invalid | strconv::invalid | strconv::overflow | nomem) =>
		return e;
	};
};