commit 519f2f5303984a58d487b0a22e70f477efa5f2ab
parent 60b5c5cadb73ef563b76b0f381ffa37325563498
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 14 Mar 2021 10:54:41 -0400
hare::module: initial manifest riggings
Diffstat:
7 files changed, 104 insertions(+), 18 deletions(-)
diff --git a/cmd/hare/plan.ha b/cmd/hare/plan.ha
@@ -131,7 +131,18 @@ fn plan_execute(plan: *plan, verbose: bool) void = {
};
fn update_cache(plan: *plan, mod: modcache) void = {
- void; // TODO: Add module to cache manifest
+ let manifest = module::manifest {
+ ident = mod.ident,
+ inputs = mod.version.inputs,
+ versions = [mod.version],
+ };
+ fmt::errorfln("Updating module {}", ast::ident_unparse_s(mod.ident));
+ match (module::manifest_write(plan.context, &manifest)) {
+ err: module::error => fmt::fatal(
+ "Error updating module cache: {}",
+ module::errstr(err)),
+ void => void,
+ };
};
fn update_modcache(plan: *plan) void = {
diff --git a/cmd/hare/schedule.ha b/cmd/hare/schedule.ha
@@ -123,16 +123,6 @@ fn sched_qbe(plan: *plan, output: str, depend: *task) *task = {
return task;
};
-export fn ident_to_env(ident: ast::ident) str = {
- let buf = strio::dynamic();
- for (let i = 0z; i < len(ident); i += 1) {
- fmt::fprintf(buf, "{}{}", ident[i],
- if (i + 1 < len(ident)) "_"
- else "") as size;
- };
- return strio::finish(buf);
-};
-
// Schedules tasks which compiles a Hare module into an object or archive.
fn sched_hare_object(
plan: *plan,
@@ -162,7 +152,7 @@ fn sched_hare_object(
// TODO: consult/update cache manifest
let version = hex::encode(ver.hash);
let ns = ast::ident_unparse_s(namespace);
- let env = ident_to_env(namespace);
+ let env = module::ident_underscore(namespace);
defer free(env);
append(harec.cmd, "-N", ns);
diff --git a/gen-stdlib b/gen-stdlib
@@ -259,10 +259,11 @@ hare_module() {
gen_srcs hare::module \
types.ha \
context.ha \
- scan.ha
+ scan.ha \
+ manifest.ha
gen_ssa hare::module \
hare::ast hare::lex hare::parse strio fs io strings hash \
- crypto::sha256 dirs bytes encoding::utf8 ascii
+ crypto::sha256 dirs bytes encoding::utf8 ascii fmt time
}
gensrcs_hare_parse() {
diff --git a/hare/module/context.ha b/hare/module/context.ha
@@ -1,9 +1,11 @@
use dirs;
+use fmt;
use fs;
use hare::ast;
use os;
use path;
use strings;
+use strio;
// TODO: Specify this at build time once harec supports -D
def DEFAULT_HAREPATH: str = "/usr/src/hare";
@@ -82,3 +84,24 @@ export fn ident_path(name: ast::ident) str = {
defer free(p);
assert(p == "foo/bar/baz");
};
+
+// Joins an ident string with underscores instead of double colons. The return
+// value must be freed by the caller.
+//
+// This is used for module names in environment variables and some file names.
+export fn ident_underscore(ident: ast::ident) str = {
+ let buf = strio::dynamic();
+ for (let i = 0z; i < len(ident); i += 1) {
+ fmt::fprintf(buf, "{}{}", ident[i],
+ if (i + 1 < len(ident)) "_"
+ else "") as size;
+ };
+ return strio::finish(buf);
+};
+
+@test fn ident_underscore() void = {
+ let ident: ast::ident = ["foo", "bar", "baz"];
+ let p = ident_underscore(ident);
+ defer free(p);
+ assert(p == "foo_bar_baz");
+};
diff --git a/hare/module/manifest.ha b/hare/module/manifest.ha
@@ -0,0 +1,58 @@
+use fmt;
+use fs;
+use io;
+use path;
+use time;
+
+// Writes a module manifest to the build cache.
+export fn manifest_write(ctx: *context, manifest: *manifest) (void | error) = {
+ let ipath = ident_path(manifest.ident);
+ defer free(ipath);
+ let cachedir = path::join(ctx.cache, ipath);
+ defer free(cachedir);
+
+ let mpath = path::join(cachedir, "manifest");
+ defer free(mpath);
+
+ let l = lock(ctx.fs, cachedir)?;
+ defer unlock(ctx.fs, cachedir, l);
+
+ let fd = fs::create(ctx.fs, mpath, 0o644)?;
+ defer io::close(fd);
+
+ for (let i = 0z; i < len(manifest.inputs); i += 1) {
+ void; // TODO: Write manifest
+ };
+};
+
+fn lock(fs: *fs::fs, cachedir: str) (*io::stream | error) = {
+ // XXX: I wonder if this should be some generic function in fs or
+ // something
+ let lockpath = path::join(cachedir, "manifest.lock");
+ defer free(lockpath);
+
+ let logged = false;
+ for (true) {
+ match (fs::create(fs, lockpath, 0o644, fs::flags::EXCL)) {
+ fd: *io::stream => return fd,
+ (fs::busy | fs::exists) => void,
+ err: fs::error => return err,
+ };
+ if (!logged) {
+ fmt::errorfln("Waiting for lock on {}...", lockpath);
+ logged = true;
+ };
+ time::sleep(1 * time::SECOND);
+ };
+
+ abort("Unreachable");
+};
+
+fn unlock(fs: *fs::fs, cachedir: str, s: *io::stream) void = {
+ let lockpath = path::join(cachedir, "manifest.lock");
+ defer free(lockpath);
+ match (fs::remove(fs, lockpath)) {
+ void => void,
+ err: fs::error => abort("Error removing module lock"),
+ };
+};
diff --git a/hare/module/types.ha b/hare/module/types.ha
@@ -18,6 +18,7 @@ export type tag = struct {
// The manifest for a particular module, with some number of inputs, and
// versions.
export type manifest = struct {
+ ident: ast::ident,
inputs: []input,
versions: []version,
};
diff --git a/stdlib.mk b/stdlib.mk
@@ -349,9 +349,10 @@ $(HARECACHE)/hare/lex/hare_lex.ssa: $(stdlib_hare_lex_srcs) $(stdlib_rt) $(stdli
stdlib_hare_module_srcs= \
$(STDLIB)/hare/module/types.ha \
$(STDLIB)/hare/module/context.ha \
- $(STDLIB)/hare/module/scan.ha
+ $(STDLIB)/hare/module/scan.ha \
+ $(STDLIB)/hare/module/manifest.ha
-$(HARECACHE)/hare/module/hare_module.ssa: $(stdlib_hare_module_srcs) $(stdlib_rt) $(stdlib_hare_ast) $(stdlib_hare_lex) $(stdlib_hare_parse) $(stdlib_strio) $(stdlib_fs) $(stdlib_io) $(stdlib_strings) $(stdlib_hash) $(stdlib_crypto_sha256) $(stdlib_dirs) $(stdlib_bytes) $(stdlib_encoding_utf8) $(stdlib_ascii)
+$(HARECACHE)/hare/module/hare_module.ssa: $(stdlib_hare_module_srcs) $(stdlib_rt) $(stdlib_hare_ast) $(stdlib_hare_lex) $(stdlib_hare_parse) $(stdlib_strio) $(stdlib_fs) $(stdlib_io) $(stdlib_strings) $(stdlib_hash) $(stdlib_crypto_sha256) $(stdlib_dirs) $(stdlib_bytes) $(stdlib_encoding_utf8) $(stdlib_ascii) $(stdlib_fmt) $(stdlib_time)
@printf 'HAREC \t$@\n'
@mkdir -p $(HARECACHE)/hare/module
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::module \
@@ -915,9 +916,10 @@ $(TESTCACHE)/hare/lex/hare_lex.ssa: $(testlib_hare_lex_srcs) $(testlib_rt) $(tes
testlib_hare_module_srcs= \
$(STDLIB)/hare/module/types.ha \
$(STDLIB)/hare/module/context.ha \
- $(STDLIB)/hare/module/scan.ha
+ $(STDLIB)/hare/module/scan.ha \
+ $(STDLIB)/hare/module/manifest.ha
-$(TESTCACHE)/hare/module/hare_module.ssa: $(testlib_hare_module_srcs) $(testlib_rt) $(testlib_hare_ast) $(testlib_hare_lex) $(testlib_hare_parse) $(testlib_strio) $(testlib_fs) $(testlib_io) $(testlib_strings) $(testlib_hash) $(testlib_crypto_sha256) $(testlib_dirs) $(testlib_bytes) $(testlib_encoding_utf8) $(testlib_ascii)
+$(TESTCACHE)/hare/module/hare_module.ssa: $(testlib_hare_module_srcs) $(testlib_rt) $(testlib_hare_ast) $(testlib_hare_lex) $(testlib_hare_parse) $(testlib_strio) $(testlib_fs) $(testlib_io) $(testlib_strings) $(testlib_hash) $(testlib_crypto_sha256) $(testlib_dirs) $(testlib_bytes) $(testlib_encoding_utf8) $(testlib_ascii) $(testlib_fmt) $(testlib_time)
@printf 'HAREC \t$@\n'
@mkdir -p $(TESTCACHE)/hare/module
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::module \