aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxSlendiX <slendi@socopon.com>2022-12-24 18:49:14 +0200
committerxSlendiX <slendi@socopon.com>2022-12-24 18:51:46 +0200
commit6b995e15829801e91b6deb13b4fa026dcffd5fe6 (patch)
tree020241d6032478a145f7ddb52aed001178a0625b
parentf6e8b0f73c2485d2c3766209fa487917e3e5254b (diff)
Add file watching and colour coding.
This patch adds a new option to building: -w. What this option does is it runs the build system on any change detected in either src/ or lib/. This is a really convenient option since you don't need to type "tbuild b" every time. Signed-off-by: xSlendiX <slendi@socopon.com>
-rw-r--r--.gitignore5
-rw-r--r--.gitmodules3
-rw-r--r--Makefile4
-rw-r--r--main.c321
m---------x-watcher0
5 files changed, 218 insertions, 115 deletions
diff --git a/.gitignore b/.gitignore
index 00e0ff7..9bcdd5a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,2 @@
-tbuild
-main.o
-
+build
+out
diff --git a/.gitmodules b/.gitmodules
index f033c8c..1dd901f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "tomlc99"]
path = tomlc99
url = https://github.com/cktan/tomlc99
+[submodule "x-watcher"]
+ path = x-watcher
+ url = https://github.com/nikp123/x-watcher
diff --git a/Makefile b/Makefile
index 33b1ed3..7163ee0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-CC=tcc
-CFLAGS=-O0 -ggdb -Wall
+CC=cc
+CFLAGS=-O0 -ggdb -Wall -lpthread
.PHONY: all clean install
diff --git a/main.c b/main.c
index f8ce688..29ad59b 100644
--- a/main.c
+++ b/main.c
@@ -12,6 +12,33 @@
#include <stdarg.h>
#include "tomlc99/toml.h"
+#include "x-watcher/x-watcher.h"
+
+#if defined(_WIN32)
+// FIXME: Find a way to do ANSI on Windows.
+#define RED ""
+#define GREEN ""
+#define YELLOW ""
+#define BLUE ""
+#define MAGENTA ""
+#define CYAN ""
+
+#define RESET ""
+#else
+#define RED "\e[31m"
+#define GREEN "\e[32m"
+#define YELLOW "\e[33m"
+#define BLUE "\e[34m"
+#define MAGENTA "\e[35m"
+#define CYAN "\e[36m"
+
+#define RESET "\e[0m"
+#endif
+
+typedef struct {
+ bool zeal_build;
+ bool watch;
+} build_options;
// FIXME: This is hardcoded, fix it.
char *python_interpreter_path = "/usr/local/bin/python3";
@@ -241,31 +268,31 @@ project_manifest* load_manifest(char const *path) {
toml_table_t *conf = toml_parse_file(fp, errbuf, sizeof(errbuf));
fclose(fp);
if (!conf) {
- fprintf(stderr, "Error: Cannot load manifest file: Cannot parse file: %s\n", errbuf);
+ fprintf(stderr, RED "Error: Cannot load manifest file: Cannot parse file: %s\n" RESET, errbuf);
return NULL;
}
toml_table_t *general = toml_table_in(conf, "General");
if (!general) {
- fprintf(stderr, "Error: Cannot load manifest file: Cannot find [General] table.\n");
+ fprintf(stderr, RED "Error: Cannot load manifest file: Cannot find [General] table.\n" RESET);
return NULL;
}
toml_datum_t name = toml_string_in(general, "Name");
if (!name.ok) {
- fprintf(stderr, "Error: Cannot load manifest file: Cannot find Name field.\n");
+ fprintf(stderr, RED "Error: Cannot load manifest file: Cannot find Name field.\n" RESET);
return NULL;
}
toml_datum_t author = toml_string_in(general, "Author");
if (!author.ok) {
- fprintf(stderr, "Error: Cannot load manifest file: Cannot find Author field.\n");
+ fprintf(stderr, RED "Error: Cannot load manifest file: Cannot find Author field.\n" RESET);
return NULL;
}
toml_datum_t version = toml_string_in(general, "Version");
if (!version.ok) {
- fprintf(stderr, "Error: Cannot load manifest file: Cannot find Version field.\n");
+ fprintf(stderr, RED "Error: Cannot load manifest file: Cannot find Version field.\n" RESET);
return NULL;
}
@@ -278,7 +305,7 @@ project_manifest* load_manifest(char const *path) {
// FIXME: Add dependencies.
toml_table_t *dependencies = toml_table_in(conf, "Dependencies");
if (!dependencies) {
- fprintf(stderr, "Error: Cannot load manifest file: Cannot find [Dependencies] table.\n");
+ fprintf(stderr, RED "Error: Cannot load manifest file: Cannot find [Dependencies] table.\n" RESET);
return NULL;
}
@@ -383,9 +410,9 @@ void print_help(char **argv) {
printf("Usage: %s [command]\n", argv[0]);
fputs("\nCommands:\n", stderr);
fputs(" * init|i [path=.] - Setup a new project.\n", stderr);
- fputs(" * build|. [--zeal|-z|-Z] - Build project in current working directory.\n", stderr);
+ fputs(" * build|. [--zeal|-z|-Z] [--watch|-w|-W] - Build project in current working directory.\n", stderr);
fputs(" * clean - Clean output code in current working directory.\n", stderr);
- fputs("\nTo see manifest file usage, check out man tbuild(1)\n", stderr);
+ fputs("\nTo read more about the manifest file, check out tbuild_manifest(1).\n", stderr);
}
bool file_exists(char const *path) {
@@ -400,7 +427,7 @@ bool makedir(char const *path) {
if (stat(path, &st) == -1) {
mkdir(path, 0700);
} else {
- fprintf(stderr, "Warning: File already exists. Continuing anyway.");
+ fprintf(stderr, YELLOW "Warning: File already exists. Continuing anyway." RESET);
return false;
}
return true;
@@ -480,7 +507,7 @@ void convert_to_zealos(char const *path) {
if (fpath[len-2] != 'H' || fpath[len-3] != '.')
continue;
- printf("Converting %s\n", entry->d_name);
+ printf(" -> Converting %s\n", entry->d_name);
// Credit: ZealOS ConversionScript.
replace_in_file(fpath, "MemCpy", "MemCopy");
@@ -607,7 +634,7 @@ bool run_scripts(char const *path) {
if (fpath[len-3] != 'p' || fpath[len-2] != 'y' || fpath[len-3] != '.')
continue;
- printf("Running %s\n", entry->d_name);
+ printf(" -> Running %s\n", entry->d_name);
char *argv[] = {
fpath,
NULL
@@ -621,6 +648,133 @@ bool run_scripts(char const *path) {
return true;
}
+int build_project(char *project_path, build_options options) {
+ int i;
+
+ puts("Starting build...");
+
+ project_manifest* manifest = load_manifest(text_format("%s/" MANIFEST_FNAME, project_path));
+ if (!manifest) {
+ fputs(RED "Error: Cannot build project: Failed to open manifest.\n" RESET, stderr);
+ return 1;
+ }
+
+ text_format("%s/lib", project_path);
+ char *lib_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
+ strcpy(lib_dir, buffer_text_format);
+ if (!file_exists(lib_dir)) {
+ bool status = makedir(lib_dir);
+ if (!status) {
+ fputs(RED "Error: Cannot build project: Cannot create lib directory.\n" RESET, stderr);
+ free_manifest(manifest);
+ return 1;
+ }
+ }
+
+ for (i = 0; i < manifest->dependencies_amount; i++) {
+ dependency dep = manifest->dependencies[i];
+ printf("%s -> %s (%i)\n", dep.name, dep.uri, i);
+
+ puts(text_format("%s/%s", lib_dir, dep.name));
+ if (!file_exists(text_format("%s/%s", lib_dir, dep.name)))
+ system(text_format("git clone --depth 1 --recursive --shallow-submodules '%s' '%s/%s'", dep.uri, lib_dir, dep.name));
+ else
+ system(text_format("cd '%s/%s' && git pull", lib_dir, dep.name));
+ }
+
+ // Create build directory
+ text_format("%s/build", project_path);
+ char *build_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
+ strcpy(build_dir, buffer_text_format);
+ if (!file_exists(build_dir)) {
+ bool status = makedir(build_dir);
+ if (!status) {
+ fputs(RED "Error: Cannot build project: Cannot create build directory.\n" RESET, stderr);
+ free_manifest(manifest);
+ return 1;
+ }
+ }
+
+ text_format("%s/src", project_path);
+ char *src_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
+ strcpy(src_dir, buffer_text_format);
+
+ // Clear and populate.
+ puts(" -> Populating build directory...");
+ clear_directory(build_dir);
+ copy_directory(src_dir, build_dir);
+ if (file_exists(lib_dir))
+ copy_directory(lib_dir, build_dir);
+
+ // Run scripts (if any)
+ puts(" -> Running scripts...");
+ // FIXME: This is incredibly hacky.
+ text_format("%s/scripts", project_path);
+ char *scripts_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
+ strcpy(scripts_dir, buffer_text_format);
+ if (file_exists(scripts_dir)) {
+ if (!run_scripts(scripts_dir)) {
+ fputs(RED "Failed running script!\b" RESET, stderr);
+ return 1;
+ }
+ }
+
+ if (options.zeal_build) {
+ puts(" -> Converting to ZealOS...");
+ convert_to_zealos(build_dir);
+ }
+
+ // TODO: Obfuscate code if enabled.
+
+ text_format("%s/output", project_path);
+ char *out_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
+ strcpy(out_dir, buffer_text_format);
+ if (!file_exists(out_dir)) {
+ bool status = makedir(out_dir);
+ if (!status) {
+ fputs(RED "Error: Cannot build project: Cannot create output directory.\n" RESET, stderr);
+ free_manifest(manifest);
+ return 1;
+ }
+ }
+
+ if (options.zeal_build)
+ text_format("%s/output/%s-%s.zeal.ISO.C", project_path, manifest->name, manifest->version);
+ else
+ text_format("%s/output/%s-%s.ISO.C", project_path, manifest->name, manifest->version);
+
+ puts(" -> Generating ISO.C");
+ char *iso_c = malloc((strlen(buffer_text_format)+1)*sizeof(char));
+ strcpy(iso_c, buffer_text_format);
+#if defined(_WIN32)
+ system(text_format("RedSeaGen.exe '%s' '%s'", build_dir, iso_c));
+#else
+ system(text_format("RedSeaGen '%s' '%s'", build_dir, iso_c));
+#endif
+
+ free(build_dir);
+ free(out_dir);
+ free(scripts_dir);
+ free(lib_dir);
+ free_manifest(manifest);
+
+ puts(GREEN "Build finished!" RESET);
+
+ return 0;
+}
+
+void watcher_cb(XWATCHER_FILE_EVENT event, char const *path, int context, void *data) {
+ if (event != XWATCHER_FILE_MODIFIED)
+ return;
+
+ puts(YELLOW "File change detected!" RESET);
+ struct {
+ char *project_path;
+ build_options options;
+ } *dat = data;
+ build_project(dat->project_path, dat->options);
+}
+
int main(int argc, char **argv) {
if (argc < 2) {
puts("No arguments provided.\n");
@@ -650,20 +804,20 @@ int main(int argc, char **argv) {
strcpy(project_path, argv[2]);
}
- fprintf(stderr, "Initializing project in `%s`.\n", project_path);
+ fprintf(stderr, GREEN "Initializing project in `%s`.\n" RESET, project_path);
bool ret = true;
if (!(strlen(project_path) == 1 && project_path[0] == '.'))
ret = makedir_parenting(project_path);
if (!ret) {
- fputs("Error: Cannot create project: Cannot create directories.\n", stderr);
+ fputs(RED "Error: Cannot create project: Cannot create directories.\n" RESET, stderr);
return -1;
}
// Check if manifest file exists.
if (file_exists(text_format("%s/" MANIFEST_FNAME, project_path))) {
- fputs("Error: Cannot create project: Project already exists!\n", stderr);
+ fputs(RED "Error: Cannot create project: Project already exists!\n" RESET, stderr);
return -1;
}
@@ -737,9 +891,7 @@ Del(\"C:/Apps/Main/RunCD.*\");\n\
} else if (cmd == 'b' || cmd == '.') {
int i;
- struct {
- bool zeal_build;
- } options = { 0 };
+ build_options options = { 0 };
for (int i = 2; i < argc; i++) {
if (argv[i][0] != '-')
@@ -748,6 +900,8 @@ Del(\"C:/Apps/Main/RunCD.*\");\n\
if (argv[i][1] == '-') {
if (strcmp(argv[i], "--zeal"))
options.zeal_build = true;
+ if (strcmp(argv[i], "--watch"))
+ options.watch = true;
continue;
}
@@ -758,6 +912,10 @@ Del(\"C:/Apps/Main/RunCD.*\");\n\
case 'Z':
options.zeal_build = true;
break;
+ case 'w':
+ case 'W':
+ options.watch = true;
+ break;
}
}
}
@@ -775,111 +933,54 @@ Del(\"C:/Apps/Main/RunCD.*\");\n\
return 1;
}
- project_manifest* manifest = load_manifest(text_format("%s/" MANIFEST_FNAME, project_path));
- if (!manifest) {
- fputs("Error: Cannot build project: Failed to open manifest.\n", stderr);
- return 1;
- }
- puts(buffer_text_format);
+ int ret = build_project(project_path, options);
+ if (ret != 0)
+ return ret;
- text_format("%s/lib", project_path);
- char *lib_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
- strcpy(lib_dir, buffer_text_format);
- if (!file_exists(lib_dir)) {
- bool status = makedir(lib_dir);
- if (!status) {
- fputs("Error: Cannot build project: Cannot create lib directory.\n", stderr);
- free_manifest(manifest);
- return 1;
- }
- }
+ if (options.watch) {
+ text_format("%s/src", project_path);
+ char *src_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
+ strcpy(src_dir, buffer_text_format);
- for (i = 0; i < manifest->dependencies_amount; i++) {
- dependency dep = manifest->dependencies[i];
- printf("%s -> %s (%i)\n", dep.name, dep.uri, i);
+ text_format("%s/lib", project_path);
+ char *lib_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
+ strcpy(lib_dir, buffer_text_format);
- puts(text_format("%s/%s", lib_dir, dep.name));
- if (!file_exists(text_format("%s/%s", lib_dir, dep.name)))
- system(text_format("git clone --depth 1 --recursive --shallow-submodules '%s' '%s/%s'", dep.uri, lib_dir, dep.name));
- else
- // FIXME: Make this cross platform.
- system(text_format("cd '%s/%s' && git pull", lib_dir, dep.name));
- }
+ x_watcher *watcher = xWatcher_create();
- // Create build directory
- text_format("%s/build", project_path);
- char *build_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
- strcpy(build_dir, buffer_text_format);
- if (!file_exists(build_dir)) {
- bool status = makedir(build_dir);
- if (!status) {
- fputs("Error: Cannot build project: Cannot create build directory.\n", stderr);
- free_manifest(manifest);
- return 1;
- }
- }
+ struct {
+ char *project_path;
+ build_options options;
+ } dat = {
+ project_path,
+ options
+ };
- text_format("%s/src", project_path);
- char *src_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
- strcpy(src_dir, buffer_text_format);
+ xWatcher_reference src;
+ src.path = src_dir;
+ src.callback_func = watcher_cb;
+ src.context = 1;
+ src.additional_data = &dat;
+ xWatcher_appendDir(watcher, &src);
- // Clear and populate.
- puts("Populating build directory...");
- clear_directory(build_dir);
- copy_directory(src_dir, build_dir);
- if (file_exists(lib_dir))
- copy_directory(lib_dir, build_dir);
-
- // Run scripts (if any)
- puts("Running scripts...");
- // FIXME: This is incredibly hacky.
- text_format("%s/scripts", project_path);
- char *scripts_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
- strcpy(scripts_dir, buffer_text_format);
- if (file_exists(scripts_dir)) {
- if (!run_scripts(scripts_dir)) {
- fputs("Failed running script!\b", stderr);
- return -1;
- }
- }
+ xWatcher_reference lib;
+ lib.path = lib_dir;
+ lib.callback_func = watcher_cb;
+ lib.context = 2;
+ lib.additional_data = &dat;
+ xWatcher_appendDir(watcher, &lib);
- if (options.zeal_build) {
- puts("Converting to ZealOS...");
- convert_to_zealos(build_dir);
- }
+ xWatcher_start(watcher);
- // TODO: Obfuscate code if enabled.
+ puts(YELLOW "Listening for file changes..." RESET);
+ getchar();
- text_format("%s/output", project_path);
- char *out_dir = malloc((strlen(buffer_text_format)+1)*sizeof(char));
- strcpy(out_dir, buffer_text_format);
- if (!file_exists(out_dir)) {
- bool status = makedir(out_dir);
- if (!status) {
- fputs("Error: Cannot build project: Cannot create output directory.\n", stderr);
- free_manifest(manifest);
- return 1;
- }
+ xWatcher_destroy(watcher);
+
+ free(src_dir);
}
- if (options.zeal_build)
- text_format("%s/output/%s-%s.zeal.ISO.C", project_path, manifest->name, manifest->version);
- else
- text_format("%s/output/%s-%s.ISO.C", project_path, manifest->name, manifest->version);
- char *iso_c = malloc((strlen(buffer_text_format)+1)*sizeof(char));
- strcpy(iso_c, buffer_text_format);
-#if defined(_WIN32)
- system(text_format("RedSeaGen.exe '%s' '%s'", build_dir, iso_c));
-#else
- system(text_format("RedSeaGen '%s' '%s'", build_dir, iso_c));
-#endif
-//abs_exe_path,
- free(build_dir);
- free(out_dir);
- free(scripts_dir);
- free(lib_dir);
free(project_path);
- free_manifest(manifest);
}
}
diff --git a/x-watcher b/x-watcher
new file mode 160000
+Subproject 01e9a4b6b051f240fc68eb0a0e3085c4a209dd3