aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cli.c17
-rw-r--r--src/files.c52
-rw-r--r--src/pkg.c25
-rw-r--r--src/recipes.c83
4 files changed, 149 insertions, 28 deletions
diff --git a/src/cli.c b/src/cli.c
index d385865..3017a80 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -52,6 +52,10 @@ void cmd_build(int argc, char **argv, int i) {
if (argv[j][0] == '-')
continue;
str arg = mstr(argv[j]);
+ package_t pkg = pkg_create(&arg);
+ if (!pkg_build(&pkg)) log_error(
+ "failed to build '%.*s'", str_fmt(&pkg.name));
+ pkg_free(&pkg);
if (str_is_valid(&arg))
str_free(&arg);
}
@@ -69,9 +73,8 @@ void cmd_install(int argc, char **argv, int i) {
continue;
str arg = mstr(argv[j]);
package_t pkg = pkg_create(&arg);
- if (!pkg_install(&pkg)) {
- log_error("failed to install");
- }
+ if (!pkg_install(&pkg)) log_error(
+ "failed to install '%.*s'", str_fmt(&pkg.name));
pkg_free(&pkg);
if (str_is_valid(&arg))
str_free(&arg);
@@ -87,6 +90,10 @@ void cmd_update(int argc, char **argv, int i) {
if (argv[j][0] == '-')
continue;
str arg = mstr(argv[j]);
+ package_t pkg = pkg_create(&arg);
+ if (!pkg_update(&pkg)) log_error(
+ "failed to update '%.*s'", str_fmt(&pkg.name));
+ pkg_free(&pkg);
if (str_is_valid(&arg))
str_free(&arg);
}
@@ -100,6 +107,10 @@ void cmd_remove(int argc, char **argv, int i) {
if (argv[j][0] == '-')
continue;
str arg = mstr(argv[j]);
+ package_t pkg = pkg_create(&arg);
+ if (!pkg_remove(&pkg)) log_error(
+ "failed to remove '%.*s'", str_fmt(&pkg.name));
+ pkg_free(&pkg);
if (str_is_valid(&arg))
str_free(&arg);
}
diff --git a/src/files.c b/src/files.c
index 5eaa459..67a327a 100644
--- a/src/files.c
+++ b/src/files.c
@@ -4,8 +4,7 @@
Copyright (C) 2026 dacctal
This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
+ it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
@@ -18,9 +17,18 @@
*/
+#define _XOPEN_SOURCE 500
+#include <stdio.h>
+#include <ftw.h>
+#include <unistd.h>
+
#include <stdbool.h>
#include <sys/stat.h>
+#include "log.h"
+#include "state.h"
+#include "str.h"
+
bool file_exists(const char *path) {
struct stat buffer;
return (stat(path, &buffer) == 0);
@@ -30,4 +38,42 @@ bool is_directory(const char *path) {
struct stat statbuf;
if (stat(path, &statbuf) != 0) return false;
return S_ISDIR(statbuf.st_mode);
-} \ No newline at end of file
+}
+
+bool file_write(str *content, str *path) {
+ FILE *fileptr = fopen(path->data, "a");
+ str_write_to_file(content, fileptr);
+ fclose(fileptr);
+ if (!file_exists(path->data)) {
+// if (!flags.quiet) log_error(
+// "could not write file: '%.*s'", str_fmt(path));
+ return false;
+ }
+ return true;
+}
+
+str file_read(str *path) {
+ if (!file_exists(path->data)) {
+// if (!flags.quiet) log_error(
+// "could not open file: '%.*s'", str_fmt(path));
+ return str_new();
+ }
+ FILE *fileptr = fopen(path->data, "r");
+ str content = str_read_entire_file(fileptr);
+ fclose(fileptr);
+ return content;
+}
+
+static int unlink_cb(const char *fpath, const struct stat *sb,
+int typeflag, struct FTW *ftwbuf) {
+ (void)sb;
+ (void)typeflag;
+ (void)ftwbuf;
+ int rv = remove(fpath);
+ if (rv) perror(fpath);
+ return rv;
+}
+
+bool rmrf(str *path) {
+ return nftw(path->data, unlink_cb, 64, FTW_DEPTH | FTW_PHYS) == 0;
+}
diff --git a/src/pkg.c b/src/pkg.c
index 97417bc..5e8ecaf 100644
--- a/src/pkg.c
+++ b/src/pkg.c
@@ -31,22 +31,26 @@
static str get_destdir(str *cwd, str *arg) {
str result = {0};
if (str_first(arg) == '.' && arg->len == 1) {
- result = str_format("%.*s/%.*s", str_fmt(&config.inst_dirs.src), str_fmt(cwd));
+ result = str_format("%.*s/%.*s",
+ str_fmt(&config.inst_dirs.src), str_fmt(cwd));
} else { str name = {0};
- if (str_find_char(arg, '/') != 0) name = str_from_after_delim(arg, '/');
+ if (str_find_char(arg, '/') != 0)
+ name = str_from_after_delim(arg, '/');
else str_copy_into(&name, arg);
- result = str_format("%.*s/%.*s", str_fmt(&config.inst_dirs.src), str_fmt(&name));
+ result = str_format("%.*s/%.*s",
+ str_fmt(&config.inst_dirs.src), str_fmt(&name));
str_free(&name);
}
return result;
}
-static str get_pkgsrc(package_t *pkg) {
- if (pkg->is_local == 1)
- return str_format("%.*s/%.*s", str_fmt(&config.inst_dirs.src), str_fmt(&pkg->name));
- else
- return str_format("%.*s/%.*s/%.*s", str_fmt(&config.inst_dirs.src),
- str_fmt(&pkg->name), str_fmt(&pkg->version));
+static void set_pkgsrc(package_t *pkg) {
+ pkg->root = str_format("%.*s/%.*s",
+ str_fmt(&config.inst_dirs.src), str_fmt(&pkg->name));
+ if (pkg->is_local) pkg->src = pkg->root;
+ else pkg->src = str_format("%.*s/%.*s/%.*s",
+ str_fmt(&config.inst_dirs.src), str_fmt(&pkg->name),
+ str_fmt(&pkg->version));
}
static void assign_pkg_version(package_t *pkg, str *new_arg_str) {
@@ -89,7 +93,7 @@ package_t pkg_create(str *arg) {
abort();
}
- pkg.src = get_pkgsrc(&pkg);
+ set_pkgsrc(&pkg);
str_free(&cwd);
str_free(&destdir);
@@ -101,4 +105,5 @@ void pkg_free(package_t *pkg) {
str_free(&pkg->version);
str_free(&pkg->url);
str_free(&pkg->src);
+ str_free(&pkg->root);
}
diff --git a/src/recipes.c b/src/recipes.c
index 5f387b4..b84a026 100644
--- a/src/recipes.c
+++ b/src/recipes.c
@@ -24,14 +24,59 @@
#include "files.h"
#include "log.h"
#include "pkg.h"
+#include "state.h"
+
+#define try_pkg_fn(fn, pkg, operation) \
+ do { \
+ log_info("attempting to %s '%.*s'", operation, str_fmt(&(pkg)->name)); \
+ if (!(fn((pkg)))) { \
+ log_error("%s failed", operation); \
+ return false; \
+ } \
+ } while (0)
+
+static bool pkg_write_status(const char *status, package_t *pkg) {
+ bool success = false;
+ str status_str = mstr(status);
+ str pkgit_status = str_format("%.*s/.pkgit_status", str_fmt(&pkg->src));
+ success = file_write(&status_str, &pkgit_status);
+ str_free(&pkgit_status);
+ str_free(&status_str);
+ return success;
+}
+
+static bool pkg_read_status(const char desired, package_t *pkg) {
+ bool success = false;
+ str pkgit_status = str_format("%.*s/.pkgit_status",
+ str_fmt(&pkg->src));
+ str status = file_read(&pkgit_status);
+ success = str_find_char(&status, desired);
+ str_free(&pkgit_status);
+ str_free(&status);
+ return success;
+}
+
+static bool is_pkg_installed(package_t *pkg) {
+ if (pkg_read_status('i', pkg)) {
+ if (flags.force) log_warn(
+ "%.*s is already installed",
+ str_fmt(&pkg->name));
+ else log_info(
+ "%.*s is already installed",
+ str_fmt(&pkg->name));
+ return true;
+ } else return false;
+}
static bool pkg_fetch_sources(package_t *pkg) {
+ bool success = false;
if (!pkg_hook_fetch_sources(pkg)) {
log_error(GREEN "%.*s" COLOR_RESET " fetch failed",
str_fmt(&pkg->name));
return false;
}
- return true;
+ success = pkg_write_status("f", pkg);
+ return success;
}
static bool pkg_enter(package_t *pkg) {
@@ -41,38 +86,52 @@ static bool pkg_enter(package_t *pkg) {
return false;
}
chdir(pkg->src.data);
+ if (!pkg_write_status("e", pkg)) return false;
return true;
}
bool pkg_setup(package_t *pkg) {
- if (!pkg_enter(pkg)) return false;
- if (!pkg_hook_setup(pkg)) return false;
+ if (pkg_read_status('s', pkg)) return true;
+ try_pkg_fn(pkg_enter, pkg, "enter");
+ try_pkg_fn(pkg_hook_setup, pkg, "setup");
+ if (!pkg_write_status("s", pkg)) return false;
return true;
}
bool pkg_build(package_t *pkg) {
- if (!pkg_enter(pkg)) return false;
- if (!pkg_hook_build(pkg)) return false;
+ if (pkg_read_status('b', pkg)) return true;
+ try_pkg_fn(pkg_enter, pkg, "enter");
+ try_pkg_fn(pkg_hook_build, pkg, "build");
+ if (!pkg_write_status("b", pkg)) return false;
return true;
}
bool pkg_install(package_t *pkg) {
- if (!pkg_fetch_sources(pkg)) return false;
- if (!pkg_enter(pkg)) return false;
- if (!pkg_hook_setup(pkg)) return false;
- if (!pkg_hook_build(pkg)) return false;
+ if (is_pkg_installed(pkg) && !flags.force) return true;
+ log_info("fetching '%.*s'", str_fmt(&pkg->name));
+ if (!pkg_read_status('f', pkg) && !pkg_fetch_sources(pkg)) return false;
+ log_info("entering '%.*s'", str_fmt(&pkg->src));
+ if (!pkg_read_status('e', pkg) && !pkg_enter(pkg)) return false;
+ log_info("setting up '%.*s'", str_fmt(&pkg->name));
+ if (!pkg_read_status('s', pkg) && !pkg_hook_setup(pkg)) return false;
+ log_info("building '%.*s'", str_fmt(&pkg->name));
+ if (!pkg_read_status('b', pkg) && !pkg_hook_build(pkg)) return false;
+ log_info("installing '%.*s'", str_fmt(&pkg->name));
if (!pkg_hook_install(pkg)) return false;
+ if (!pkg_write_status("i", pkg)) return false;
+ log_success("installed '%.*s'", str_fmt(&pkg->name));
return true;
}
bool pkg_remove(package_t *pkg) {
if (!pkg_enter(pkg)) return false;
- if (!pkg_hook_setup(pkg)) return false;
+ if (!pkg_hook_remove(pkg)) return false;
+ if (!rmrf(&pkg->root)) return false;
+ log_success("removed '%.*s'", str_fmt(&pkg->name));
return true;
}
bool pkg_update(package_t *pkg) {
- if (!pkg_enter(pkg)) return false;
- if (!pkg_hook_setup(pkg)) return false;
+ pkg_install(pkg);
return true;
}