1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
#include "modules.h"
#include "stdlib/memory.h"
#include "stdlib/paths.h"
#include "stdlib/simpleparse.h"
#include "stdlib/pointers.h"
#include "stdlib/tables.h"
#include "stdlib/text.h"
#include "stdlib/types.h"
#define xsystem(...) ({ int _status = system(String(__VA_ARGS__)); if (!WIFEXITED(_status) || WEXITSTATUS(_status) != 0) errx(1, "Failed to run command: %s", String(__VA_ARGS__)); })
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;
OptionalText_t (*next_line)(void*) = by_line.fn;
find_section:;
for (Text_t line; (line=next_line(by_line.userdata)).length >= 0; ) {
char *line_str = Textヽas_c_string(line);
if (line_str[0] == '[' && strncmp(line_str+1, info->name, strlen(info->name)) == 0
&& line_str[1+strlen(info->name)] == ']')
break;
}
for (Text_t line; (line=next_line(by_line.userdata)).length >= 0; ) {
char *line_str = Textヽas_c_string(line);
if (line_str[0] == '[') goto find_section;
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;
}
}
module_info_t get_module_info(ast_t *use)
{
static Table_t cache = {};
TypeInfo_t *cache_type = Tableヽinfo(Pointerヽinfo("@", &Memoryヽinfo), Pointerヽinfo("@", &Memoryヽinfo));
module_info_t **cached = Tableヽget(cache, &use, cache_type);
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);
}
Tableヽset(&cache, &use, &info, cache_type);
return *info;
}
bool try_install_module(module_info_t mod)
{
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;
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);
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;
print("Installing ", mod.name, " from URL...");
const char *p = strrchr(mod.url, '/');
if (!p) return false;
const char *filename = p + 1;
p = strchr(filename, '.');
if (!p) return false;
const char *extension = p + 1;
Path_t tmpdir = Pathヽunique_directory(Path("/tmp/tomo-module-XXXXXX"));
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);
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);
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;
print("Installing ", mod.name, " from path...");
xsystem("tomo -IL ", mod.path);
return true;
}
return false;
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
|