aboutsummaryrefslogtreecommitdiff
path: root/src/modules.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-09-01 17:39:20 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-09-01 17:39:20 -0400
commit2538b1b7461f9b06d6a6f43acd5609d916b1addc (patch)
tree061efdfc54351b1c644f1422e4f2c00bfefb1235 /src/modules.c
parentd6d3f5711de85ab1c21f515b9d125d316d853c92 (diff)
parentadc2d81b5683e611c5f3289be6157d4519a60632 (diff)
Merge branch 'main' into formatter
Diffstat (limited to 'src/modules.c')
-rw-r--r--src/modules.c119
1 files changed, 74 insertions, 45 deletions
diff --git a/src/modules.c b/src/modules.c
index 40b3daf3..fafbbf86 100644
--- a/src/modules.c
+++ b/src/modules.c
@@ -5,6 +5,7 @@
#include <string.h>
#include <sys/wait.h>
+#include "config.h"
#include "modules.h"
#include "stdlib/memory.h"
#include "stdlib/paths.h"
@@ -14,6 +15,7 @@
#include "stdlib/tables.h"
#include "stdlib/text.h"
#include "stdlib/types.h"
+#include "stdlib/util.h"
#define xsystem(...) \
({ \
@@ -22,6 +24,33 @@
errx(1, "Failed to run command: %s", String(__VA_ARGS__)); \
})
+bool install_from_modules_ini(Path_t ini_file, bool ask_confirmation) {
+ OptionalClosure_t by_line = Path$by_line(ini_file);
+ if (by_line.fn == NULL) return false;
+ OptionalText_t (*next_line)(void *) = by_line.fn;
+ module_info_t info = {};
+ for (Text_t line; (line = next_line(by_line.userdata)).length >= 0;) {
+ char *line_str = Text$as_c_string(line);
+ const char *next_section = NULL;
+ if (!strparse(line_str, "[", &next_section, "]")) {
+ if (info.name) {
+ if (!try_install_module(info, ask_confirmation)) return false;
+ }
+ print("Checking module ", next_section, "...");
+ info = (module_info_t){.name = next_section};
+ continue;
+ }
+ if (!strparse(line_str, "version=", &info.version) || !strparse(line_str, "url=", &info.url)
+ || !strparse(line_str, "git=", &info.git) || !strparse(line_str, "path=", &info.path)
+ || !strparse(line_str, "revision=", &info.revision))
+ continue;
+ }
+ if (info.name) {
+ if (!try_install_module(info, ask_confirmation)) return false;
+ }
+ return true;
+}
+
static void read_modules_ini(Path_t ini_file, module_info_t *info) {
OptionalClosure_t by_line = Path$by_line(ini_file);
if (by_line.fn == NULL) return;
@@ -50,47 +79,41 @@ module_info_t get_module_info(ast_t *use) {
if (cached) return **cached;
const char *name = Match(use, Use)->path;
module_info_t *info = new (module_info_t, .name = name);
- if (streq(name, "commands")) info->version = "v1.0";
- else if (streq(name, "random")) info->version = "v1.0";
- else if (streq(name, "base64")) info->version = "v1.0";
- else if (streq(name, "core")) info->version = "v1.0";
- else if (streq(name, "patterns")) info->version = "v1.1";
- else if (streq(name, "json")) info->version = "v1.0";
- else if (streq(name, "pthreads")) info->version = "v1.0";
- else if (streq(name, "shell")) info->version = "v1.0";
- else if (streq(name, "time")) info->version = "v1.0";
- else if (streq(name, "uuid")) info->version = "v1.0";
- else {
- read_modules_ini(Path$sibling(Path$from_str(use->file->filename), Text("modules.ini")), info);
- read_modules_ini(Path$with_extension(Path$from_str(use->file->filename), Text(":modules.ini"), false), info);
- }
+ read_modules_ini(Path$sibling(Path$from_str(use->file->filename), Text("modules.ini")), info);
+ read_modules_ini(Path$with_extension(Path$from_str(use->file->filename), Text(":modules.ini"), false), info);
Table$set(&cache, &use, &info, cache_type);
return *info;
}
-bool try_install_module(module_info_t mod) {
+bool try_install_module(module_info_t mod, bool ask_confirmation) {
+ Path_t dest = Path$from_text(Texts(Text$from_str(TOMO_PATH), "/lib/tomo_" TOMO_VERSION "/", Text$from_str(mod.name),
+ "_", Text$from_str(mod.version)));
+ if (Path$exists(dest)) return true;
+
if (mod.git) {
- OptionalText_t answer = ask(Texts(Text("The module \""), Text$from_str(mod.name),
- Text("\" is not installed.\nDo you want to install it from git URL "),
- Text$from_str(mod.git), Text("? [Y/n] ")),
- true, true);
- if (!(answer.length == 0 || Text$equal_values(answer, Text("Y")) || Text$equal_values(answer, Text("y"))))
- return false;
+ if (ask_confirmation) {
+ OptionalText_t answer =
+ ask(Texts("The module \"", Text$from_str(mod.name), "\" ", Text$from_str(mod.version),
+ " is not installed.\nDo you want to install it from git URL ", Text$from_str(mod.git),
+ "? [Y/n] "),
+ true, true);
+ if (!(answer.length == 0 || Text$equal_values(answer, Text("Y")) || Text$equal_values(answer, Text("y"))))
+ return false;
+ }
print("Installing ", mod.name, " from git...");
- Path_t tmpdir = Path$unique_directory(Path("/tmp/tomo-module-XXXXXX"));
- if (mod.revision) xsystem("git clone --depth=1 --revision ", mod.revision, " ", mod.git, " ", tmpdir);
- else xsystem("git clone --depth=1 ", mod.git, " ", tmpdir);
- if (mod.path) xsystem("tomo -IL ", tmpdir, "/", mod.path);
- else xsystem("tomo -IL ", tmpdir);
- Path$remove(tmpdir, true);
+ if (mod.revision) xsystem("git clone --depth=1 --revision ", mod.revision, " ", mod.git, " ", dest);
+ else xsystem("git clone --depth=1 ", mod.git, " ", dest);
+ xsystem("tomo -L ", dest);
return true;
} else if (mod.url) {
- OptionalText_t answer = ask(Texts(Text("The module "), Text$from_str(mod.name),
- Text(" is not installed.\nDo you want to install it from URL "),
- Text$from_str(mod.url), Text("? [Y/n] ")),
- true, true);
- if (!(answer.length == 0 || Text$equal_values(answer, Text("Y")) || Text$equal_values(answer, Text("y"))))
- return false;
+ if (ask_confirmation) {
+ OptionalText_t answer = ask(
+ Texts("The module \"", Text$from_str(mod.name), "\" ", Text$from_str(mod.version),
+ " is not installed.\nDo you want to install it from URL ", Text$from_str(mod.url), "? [Y/n] "),
+ true, true);
+ if (!(answer.length == 0 || Text$equal_values(answer, Text("Y")) || Text$equal_values(answer, Text("y"))))
+ return false;
+ }
print("Installing ", mod.name, " from URL...");
@@ -101,25 +124,31 @@ bool try_install_module(module_info_t mod) {
if (!p) return false;
const char *extension = p + 1;
Path_t tmpdir = Path$unique_directory(Path("/tmp/tomo-module-XXXXXX"));
+ tmpdir = Path$child(tmpdir, Text$from_str(mod.name));
+ Path$create_directory(tmpdir, 0755);
+
xsystem("curl ", mod.url, " -o ", tmpdir);
- if (streq(extension, ".zip")) xsystem("unzip ", tmpdir, "/", filename);
- else if (streq(extension, ".tar.gz") || streq(extension, ".tar")) xsystem("tar xf ", tmpdir, "/", filename);
+ Path$create_directory(dest, 0755);
+ if (streq(extension, ".zip")) xsystem("unzip ", tmpdir, "/", filename, " -d ", dest);
+ else if (streq(extension, ".tar.gz") || streq(extension, ".tar"))
+ xsystem("tar xf ", tmpdir, "/", filename, " -C ", dest);
else return false;
- const char *basename = String(string_slice(filename, strcspn(filename, ".")));
- if (mod.path) xsystem("tomo -IL ", tmpdir, "/", basename, "/", mod.path);
- else xsystem("tomo -IL ", tmpdir, "/", basename);
+ xsystem("tomo -L ", dest);
Path$remove(tmpdir, true);
return true;
} else if (mod.path) {
- OptionalText_t answer = ask(Texts(Text("The module "), Text$from_str(mod.name),
- Text(" is not installed.\nDo you want to install it from path "),
- Text$from_str(mod.path), Text("? [Y/n] ")),
- true, true);
- if (!(answer.length == 0 || Text$equal_values(answer, Text("Y")) || Text$equal_values(answer, Text("y"))))
- return false;
+ if (ask_confirmation) {
+ OptionalText_t answer = ask(
+ Texts("The module \"", Text$from_str(mod.name), "\" ", Text$from_str(mod.version),
+ " is not installed.\nDo you want to install it from path ", Text$from_str(mod.path), "? [Y/n] "),
+ true, true);
+ if (!(answer.length == 0 || Text$equal_values(answer, Text("Y")) || Text$equal_values(answer, Text("y"))))
+ return false;
+ }
print("Installing ", mod.name, " from path...");
- xsystem("tomo -IL ", mod.path);
+ xsystem("ln -s ", mod.path, " ", dest);
+ xsystem("tomo -L ", dest);
return true;
}