/* pkgit - package it! 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 (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include "common.h" #include "files.h" #include "log.h" #include "lua_state.h" #include "pkg.h" #include "state.h" #define try_pkg_fn(fn, pkg, operation, smol) \ do { \ if (pkg_read_status(smol, pkg)) return true; \ if (!flags.quiet) log_info("'%.*s' %s in progress...", \ str_fmt(&(pkg)->name), operation); \ if (!(fn((pkg)))) { \ log_error("%s failed", operation); \ return false; \ } \ char big[2] = "\0"; \ big[0] = smol; \ if (!pkg_write_status(big, pkg)) return false; \ log_info("'%.*s' %s done", str_fmt(&(pkg)->name), operation); \ } 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; } success = pkg_write_status("f", pkg); return success; } static bool pkg_enter(package_t *pkg) { if (!is_directory(pkg->src.data)) { log_error(GREEN "%.*s" COLOR_RESET " is not a directory", str_fmt(&pkg->src)); return false; } chdir(pkg->src.data); if (!pkg_write_status("e", pkg)) return false; return true; } bool pkg_setup(package_t *pkg) { if (pkg_read_status('s', pkg)) return true; if (!pkg_enter(pkg)) return false; try_pkg_fn(pkg_hook_setup, pkg, "setup", 's'); log_success("'%.*s' set up", str_fmt(&pkg->name)); return true; } bool pkg_build(package_t *pkg) { if (pkg_read_status('b', pkg)) return true; if (!pkg_enter(pkg)) return false; try_pkg_fn(pkg_hook_build, pkg, "build", 'b'); log_success("'%.*s' built", str_fmt(&pkg->name)); return true; } bool pkg_install(package_t *pkg) { if (is_pkg_installed(pkg) && !flags.force) return true; try_pkg_fn(pkg_fetch_sources, pkg, "fetch", 'f'); if (!pkg_enter(pkg)) return false; try_pkg_fn(pkg_hook_setup, pkg, "setup", 's'); try_pkg_fn(pkg_hook_build, pkg, "build", 'b'); try_pkg_fn(pkg_hook_install, pkg, "install", 'i'); log_success("'%.*s' installed", str_fmt(&pkg->name)); return true; } bool pkg_remove(package_t *pkg) { if (!pkg_enter(pkg)) return false; if (!pkg_hook_remove(pkg)) return false; if (!rmrf(&pkg->root)) return false; log_success("'%.*s' removed", str_fmt(&pkg->name)); return true; } bool pkg_update(package_t *pkg) { pkg_install(pkg); log_success("'%.*s' is up to date", str_fmt(&pkg->name)); return true; } bool all_update(void) { struct dirent* dirent_ptr; DIR* dir_ptr; if ((dir_ptr = opendir(config.inst_dirs.src.data)) == NULL) { log_error("could not open %s", str_fmt(&config.inst_dirs.src)); } while ((dirent_ptr = readdir(dir_ptr)) != NULL) { if ( strcmp(dirent_ptr->d_name, "..") == 0 || strcmp(dirent_ptr->d_name, ".") == 0 ) continue; str pkg_name = mstr(dirent_ptr->d_name); if (!pkg_exists(&pkg_name)) { str_free(&pkg_name); continue; } package_t pkg = pkg_create(&pkg_name); pkg_update(&pkg); pkg_free(&pkg); if (str_is_valid(&pkg_name)) str_free(&pkg_name); } closedir(dir_ptr); config_hook_on_update(); return true; }