Lindenii Project Forge
Login

hare-git

Git library for Hare

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

/git/refs.ha (raw)

use bytes;
use errors;
use fs;
use io;
use strings;

// Resolve a Git ref to its object ID from its fully qualified ref name.
export fn resolve_ref(r: repo, refname: const str) (oid | error) = {
	{
		match (fs::open(r.root, refname)) {
		case let fh: io::handle =>
			defer io::close(fh)!;
			let b = io::drain(fh)?;
			defer free(b);

			let n = if (len(b) > 0 && b[len(b)-1] == '\n') {
				yield len(b) - 1z;
			} else {
				yield len(b);
			};

			let s = strings::fromutf8(b[..n])?;
			return parse_oid(s)?;
		case let fe: fs::error =>
			if (!(fe is errors::noentry)) {
				return fe;
			};
		};
	};

	match (fs::open(r.root, "packed-refs")) {
	case let fh: io::handle =>
		defer io::close(fh)!;

		let pr = io::drain(fh)?;
		defer free(pr);

		let want = strings::toutf8(refname);
		let i = 0z;
		for (i < len(pr)) {
			let e = match (bytes::index(pr[i..], '\n')) {
			case let j: size => yield i + j;
			case void => yield len(pr);
			};
			let line = pr[i..e];

			if (len(line) >= 1 && (line[0] == '#' || line[0] == '^')) {
				void;
			} else if (len(line) >= 66z) {
				let sp = bytes::index(line, ' ');
				if (sp is size) {
					let k = (sp: size);
					if (k == 64z && k + 1z < len(line)) {
						let name_b = line[k + 1z..];
						if (bytes::equal(name_b, want)) {
							let hexs = strings::fromutf8(line[..k])?;
							return parse_oid(hexs)?;
						};
					};
				};
			};

			i = if (e < len(pr) && pr[e] == '\n') {
				yield e + 1z;
			} else {
				yield e;
			};
		};

		return errors::invalid;

	case let fe: fs::error =>
		if (fe is errors::noentry) {
			return errors::invalid;
		};
		return fe;
	};
};

// Reads and resolves the HEAD ref to its object ID.
export fn head_oid(r: repo) (oid | error) = {
	let fh = fs::open(r.root, "HEAD")?;
	defer io::close(fh)!;

	let b = io::drain(fh)?;
	defer free(b);

	let n = if (len(b) > 0 && b[len(b)-1] == '\n') {
		yield len(b) - 1z;
	} else {
		yield len(b);
	};
	let line = b[..n];

	const pfx = strings::toutf8("ref: ");
	if (len(line) >= len(pfx) && bytes::hasprefix(line, pfx)) {
		let rn = strings::fromutf8(line[len(pfx)..])?;
		return resolve_ref(r, rn);
	};

	let s = strings::fromutf8(line)?;
	return parse_oid(s)?;
};