hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mcmd/hare/plan.ha | 13++++++++++++-
Mcmd/hare/schedule.ha | 12+-----------
Mgen-stdlib | 5+++--
Mhare/module/context.ha | 23+++++++++++++++++++++++
Ahare/module/manifest.ha | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mhare/module/types.ha | 1+
Mstdlib.mk | 10++++++----
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 \