diff options
| author | dacctal <donotcontactmevia@email.invalid> | 2026-07-21 21:32:27 +0000 |
|---|---|---|
| committer | dacctal <donotcontactmevia@email.invalid> | 2026-07-21 21:32:27 +0000 |
| commit | 184bd50e2ea12b4bf40f4ae1b0d685f0bfa1c995 (patch) | |
| tree | bfe4f0a8fb39def302bdc807308c30b60dd18a92 | |
| parent | c251d37c98efba534766e914f7392cc7a0470351 (diff) | |
started 2.0 refactor. Co-authored-by: ezntek <eason@ezntek.com>
| -rw-r--r-- | Makefile.orig | 84 | ||||
| -rw-r--r-- | config/init.lua | 307 | ||||
| -rw-r--r-- | config/types.lua | 35 | ||||
| -rw-r--r-- | include/add_repo.h | 28 | ||||
| -rw-r--r-- | include/banned.h | 67 | ||||
| -rw-r--r-- | include/build.h | 28 | ||||
| -rw-r--r-- | include/cli.h (renamed from include/debug.h) | 11 | ||||
| -rw-r--r-- | include/common.h (renamed from include/globs.h) | 39 | ||||
| -rw-r--r-- | include/fetch.h | 28 | ||||
| -rw-r--r-- | include/files.h | 34 | ||||
| -rw-r--r-- | include/help.h | 8 | ||||
| -rw-r--r-- | include/is_updated.h | 28 | ||||
| -rw-r--r-- | include/lua_state.h | 16 | ||||
| -rw-r--r-- | include/parse_args.h | 26 | ||||
| -rw-r--r-- | include/pkg.h | 37 | ||||
| -rw-r--r-- | include/pkgit_lua.h | 77 | ||||
| -rw-r--r-- | include/search.h | 27 | ||||
| -rw-r--r-- | include/state.h | 45 | ||||
| -rw-r--r-- | include/str.h | 14 | ||||
| -rw-r--r-- | src/add_repo.c | 56 | ||||
| -rw-r--r-- | src/build.c | 170 | ||||
| -rw-r--r-- | src/check.c | 43 | ||||
| -rw-r--r-- | src/cli.c | 246 | ||||
| -rw-r--r-- | src/debug.c | 35 | ||||
| -rw-r--r-- | src/fetch.c | 95 | ||||
| -rw-r--r-- | src/files.c | 246 | ||||
| -rw-r--r-- | src/globs.c | 64 | ||||
| -rw-r--r-- | src/help.c | 7 | ||||
| -rw-r--r-- | src/is_updated.c | 48 | ||||
| -rw-r--r-- | src/log.c | 2 | ||||
| -rw-r--r-- | src/lua_globs.c | 213 | ||||
| -rw-r--r-- | src/lua_state.c | 146 | ||||
| -rw-r--r-- | src/lua_vars.c | 66 | ||||
| -rw-r--r-- | src/main.c | 28 | ||||
| -rw-r--r-- | src/parse_args.c | 206 | ||||
| -rw-r--r-- | src/pkg_create.c | 140 | ||||
| -rw-r--r-- | src/pkg_exists.c | 56 | ||||
| -rw-r--r-- | src/pkg_free.c | 10 | ||||
| -rw-r--r-- | src/pkg_install.c | 213 | ||||
| -rw-r--r-- | src/pkg_remove.c | 189 | ||||
| -rw-r--r-- | src/pkg_update.c | 174 | ||||
| -rw-r--r-- | src/search.c | 70 | ||||
| -rw-r--r-- | src/state.c (renamed from include/check.h) | 19 | ||||
| -rw-r--r-- | src/str.c | 34 |
44 files changed, 668 insertions, 2847 deletions
diff --git a/Makefile.orig b/Makefile.orig deleted file mode 100644 index adacc56..0000000 --- a/Makefile.orig +++ /dev/null @@ -1,84 +0,0 @@ -# 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 <https://www.gnu.org/licenses/>. - -.PHONY: default debug install defconfig clean - -CC ?= clang -RM = rm -f -PREFIX ?= /usr/local -OBJDIR = obj -SRCS = $(wildcard src/*.c) -OBJS = $(SRCS:src/%.c=$(OBJDIR)/%.o) -CFLAGS += $(shell pkg-config --cflags luajit) -I./include -Wno-format-truncation -std=c99 - -# pretty print for compilation. To enable verbose (show commands), run with -# `make V=1` -ifeq ($(strip $(V)),) - E = @echo - Q = @ -else - E = @\# - Q = -endif - -default: pkgit - -pkgit: $(OBJS) - $(E) " LINK " $@ - $(Q) ${CC} -o $@ $^ $(shell pkg-config --libs luajit) $(shell pkg-config --libs libgit2) $(LDFLAGS) -g - -$(OBJDIR): - @mkdir -p $(OBJDIR) - -$(OBJDIR)/%.o: src/%.c | $(OBJDIR) - $(E) " CC " $@ - $(Q) ${CC} $(CFLAGS) -c -o $@ $< - -gdb: CFLAGS += -g -O0 -Wall -Wextra -Werror -Wvla -pedantic -gdb: pkgit - -debug: CFLAGS += -g -O0 -Wall -Wextra -Werror -Wvla -pedantic -fsanitize=address -debug: LDFLAGS += -fsanitize=address -debug: pkgit - -install: pkgit - $(E) " INSTALL" ${DESTDIR}${PREFIX} - $(Q) install -d ${DESTDIR}${PREFIX}/bin - $(Q) install -m 755 pkgit ${DESTDIR}${PREFIX}/bin/pkgit - $(Q) install -d ${DESTDIR}${PREFIX}/share/man/man1 - $(Q) install -m 644 docs/pkgit.1 ${DESTDIR}${PREFIX}/share/man/man1/pkgit.1 - -uninstall: ${DESTDIR}${PREFIX}/bin/pkgit - $(E) " UNINSTALL" ${DESTDIR}${PREFIX} - $(Q) ${RM} ${DESTDIR}${PREFIX}/bin/pkgit - $(Q) ${RM} ${DESTDIR}${PREFIX}/share/man/man1/pkgit.1 - -defconfig: - $(Q) @if [ "$$(id -u)" -eq 0 ]; then dir=/etc/pkgit; else dir=~/.config/pkgit; fi; \ - $(Q) echo "installing default config to $$dir ..."; \ - $(Q) mkdir -p $$dir; \ - $(Q) cp -r ./config/* $$dir/; \ - $(Q) echo "default config installed" - -rmconfig: - $(Q) @if [ "$$(id -u)" -eq 0 ]; then dir=/etc/pkgit; else dir=~/.config/pkgit; fi; \ - $(Q) echo "removing config from $$dir ..."; \ - $(Q) rm -rf $$dir; \ - $(Q) echo "config successfully removed" - -clean: - $(E) " CLEAN" - $(Q) ${RM} -r $(OBJDIR) pkgit diff --git a/config/init.lua b/config/init.lua index 0557a89..2a9dce2 100644 --- a/config/init.lua +++ b/config/init.lua @@ -1,247 +1,70 @@ ---[[ introduction - - this is the pkgit configuration template. - every configuration file is written in lua, - the embeddable high-level programming language. - - for info on how to write lua, check out - this website for documentation: - https://www.lua.org/pil/contents.html - - all variables that are - set by default are designed to - work out of the box. be sure to - keep the global variables global, - as they need to be global in - order for them to work with - each other effectively. - - `local install_directories`, for - example, will not work well in - most cases. - -]] - ---[[ prefix - - the prefix variable is necessary - for custom install paths, which - bldit maintainers should be - respecting with their recipes. - - if you want to install packages - without root, it's easist to - create a home variable and - append that to your prefix. - -]] -local home = os.getenv("HOME") -prefix = home.."/.local" - ---[[ install_directories - - install_directories is an essential - table that pkgit needs in order to - function. this is how it determines - where you install your packages to. - - it's most convenient when combined - with `prefix` which allows for a - more dynamic definition of your - install directories. - -]] -install_directories = { - bin = prefix.."/bin", -- binaries (executables) - -- the value of `bin` should also be set in your shell's $PATH - include = prefix.."/include", -- C headers - lib = prefix.."/lib", -- libraries (shared objects) - src = prefix.."/share/pkgit", -- source code +local pkgit = require("pkgit") +local cfg = {} + +local prefix = os.getenv("HOME") .. "/.local" +cfg.dirs = { + prefix = prefix, + src = prefix .. "/share/pkgit", + bin = prefix .. "/bin", + lib = prefix .. "/lib", + include = prefix .. "/include", } ---[[ repositories - - this is where all your repos need to - end up. every repo has a name, which - can be written out normally - (`name = {...}`), or for some repos, - it might be necessary to wrap it in - quotes (`["name"] = {...}`). - that name can be used in a pkgit - command to be installed. - ( `pkgit --install [repo]` ) - - each of these repos must be structured - as a lua table. the structure is - demonstrated below. - -]] -repositories = { - pkgit = { - url = "https://git.symlinx.net/pkgit", - --[[ repo example - - no targets table or dependencies are actually needed in - this specific case, pkgit has a bldit.lua which guarantees - that it will compile & install (as long as `install_directories` - and `prefix` are set up). - - if you do make a targets table here, it will take priority - over the bldit.lua in the repo, and your build system - autodetection config ( `build_systems = {...}` ) - - more about `targets` in the global `build_systems` table. - - ]] - --dependencies = { - -- name = { - -- url = {...}, - -- version = "...", - -- target = "...", - -- }, - --}, - --targets = { - -- default = { - -- build = function() - -- return os.execute("make") - -- - -- -- ^ make sure to return the exit code of os.execute ^ -- - -- - -- end, - -- install = function() - -- return os.execute("make install PREFIX="..prefix) - -- end, - -- uninstall = function() - -- return os.execute("make uninstall PREFIX="..prefix) - -- end, - -- } - --} - }, +cfg.pkgs = { + ["gmp"] = {}, + ["mpfr"] = {}, + ["mpc"] = {}, + ["gcc"] = { + url = "https://ftp.gnu.org/gnu/gcc/gcc-16.1.0/gcc-16.1.0.tar.xz", + version = "16.1.0", + fetcher = cfg.fetchers.tarball, + dependencies = { + "gmp", "mpfr", "mpc" + } + }, + ["luajit"] = { + url = "https://luajit.org/git/luajit.git", + version = "v2.1", + fetcher = cfg.fetchers.git, + dependencies = { + "gcc" + }, + }, + ["pkgit"] = { + url = "https://git.symlinx.net/pkgit", + version = "HEAD", + fetcher = cfg.fetchers.git, + dependencies = { + "luajit", + }, + opts = {}, + recipe = cfg.recipes.make, + } } ---[[ build_systems - - this table contains all of the automatic - build system detection necessary for pkgit - to work without bldit.lua or `repositories = {...}`. - - this works by creating a table named after the - filename associated with the build system that - is found in the root directory of a package. - - by associating a filename with a build system, - pkgit can dynamically compile and install any - package, given that they use the build system - according to the standard (or otherwise - generally popular) usage guidelines. - -]] -build_systems = { - ["Makefile"] = { - --[[ targets - - briefly mentioned above in `repositories`, - the `targets` subtable is a standard that's - consistent across all the different methods - to build a package using pkgit; meaning - you can write the same `targets` subtable - in `repositories.<pkg>`, `bldit.lua`, and - right here in `build_systems`. - - this table comes with two templates; - `default` and `quiet`. the first is pretty - self-explanatory; this is what you'd define - as the default intended behavior of the - build system. - - `quiet` is similar to `default`, in the sense - that it inherits the default intended behavior, - except that it does so while printing nothing - to the terminal. instead, ideally, it would - output its logs to a temporary file accessible - by the user running the command. - - this is why the default logs in this example - are located in `/tmp` and not `/var/log`, - because the user typically has full access to - `/tmp`, and normally not `/var/log`. - - ]] - targets = { - default = { - build = function() - return os.execute("make") - end, - install = function() - return os.execute("make install PREFIX="..prefix) - end, - uninstall = function() - return os.execute("make uninstall PREFIX="..prefix) - end, - }, - quiet = { - build = function() - return os.execute("make &>/tmp/pkgit_build.log") - end, - install = function() - return os.execute("make install PREFIX="..prefix.." &>/tmp/pkgit_build.log") - end, - uninstall = function() - return os.execute("make uninstall PREFIX="..prefix.." &>/tmp/pkgit_build.log") - end, - }, - } - }, - ["meson.build"] = { - targets = { - default = { - build = function() - return os.execute("meson setup build --prefix "..prefix.." && meson compile -C build") - end, - install = function() - return os.execute("cd build && meson install") - end, - uninstall = function() - return os.execute("cd build && ninja uninstall") - end, - }, - quiet = { - build = function() - return os.execute("meson setup build --prefix "..prefix.." &>/tmp/pkgit_build.log && meson compile -C build &>/tmp/pkgit_build.log") - end, - install = function() - return os.execute("cd build && meson install &>/tmp/pkgit_build.log") - end, - uninstall = function() - return os.execute("cd build && ninja uninstall &>/tmp/pkgit_build.log") - end, - }, - } - }, - ["CMakeLists.txt"] = { - targets = { - default = { - build = function() - return os.execute("cmake -B build && cmake --build build") - end, - install = function() - return os.execute("cmake --build . --target install") - end, - uninstall = function() - return os.execute("xargs rm < install_manifest.txt") - end, - }, - quiet = { - build = function() - return os.execute("cmake -B build &>/tmp/pkgit_build.log && cmake --build build &>/tmp/pkgit_build.log") - end, - install = function() - return os.execute("cmake --build . --target install &>/tmp/pkgit_build.log") - end, - uninstall = function() - return os.execute("xargs rm < install_manifest.txt &>/tmp/pkgit_build.log") - end, - }, - } - }, +cfg.fetchers = { + git = { + get_source = function(url, version, target_dir) return 0 end, + get_version = function(url, target_dir) return "HEAD" end, + }, + tarball = { + get_source = function(url, version, target_dir) return 0 end, + get_version = function(url, target_dir) return "" end, + } +} +cfg.fetchers.default = cfg.fetchers.git + +cfg.recipes = {} +cfg.recipes.make = { + build = function(bldit_build) + return pkgit.run({ "make" }) + end, + install = function(bldit_install) + return pkgit.run({ "make install PREFIX=" .. prefix }) + end, + remove = function(bldit_remove) + return pkgit.run({ "make uninstall PREFIX=" .. prefix }) + end, } + +return cfg diff --git a/config/types.lua b/config/types.lua new file mode 100644 index 0000000..10a444d --- /dev/null +++ b/config/types.lua @@ -0,0 +1,35 @@ +---@class (exact) Dirs +---@field prefix string +---@field bin string +---@field include string +---@field lib string +---@field src string + +---@class (exact) Recipe +---@field setup (fun(bldit_setup: fun()): number)? +---@field build fun(bldit_build: fun()): number +---@field install fun(bldit_install: fun()): number +---@field remove fun(bldit_remove: fun()): number +---@field on_update (fun(bldit_on_update: fun()): number)? + +---@type Recipe +---@alias GetSourcesFn fun(url: string, version: string, target_dir: string): number +---@alias GetVersionFn fun(url: string, target_dir: string): string + +---@class (exact) Fetcher +---@field get_sources GetSourcesFn +---@field get_version GetVersionFn + +---@class (exact) Package +---@field url string +---@field version string? +---@field fetcher Fetcher | nil +---@field dependencies { [string]: Package } | "bldit" | nil +---@field opts table? +---@field recipe Recipe | "bldit" | nil + +---@class (exact) Config +---@field dirs Dirs +---@field fetchers { [string]: Fetcher } +---@field recipes { [string]: Recipe } +---@field pkgs { [string]: Package } diff --git a/include/add_repo.h b/include/add_repo.h deleted file mode 100644 index 48a73fa..0000000 --- a/include/add_repo.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#ifndef PKGIT_ADD_H -#define PKGIT_ADD_H - -#include "pkg.h" - -void add_repo(package_t *pkg); - -#endif diff --git a/include/banned.h b/include/banned.h deleted file mode 100644 index 3ea7dd4..0000000 --- a/include/banned.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#ifndef PKGIT_BANNED_H -#define PKGIT_BANNED_H - -/* - * This header lists functions that have been banned from our code base, - * because they're too easy to misuse (and even if used correctly, - * complicate audits). Including this header turns them into compile-time - * errors. - */ - -#define BANNED(func) sorry_##func##_is_a_banned_function - -#undef strcpy -#define strcpy(x,y) BANNED(strcpy) -#undef strcat -#define strcat(x,y) BANNED(strcat) -#undef strncpy -#define strncpy(x,y,n) BANNED(strncpy) -#undef strncat -#define strncat(x,y,n) BANNED(strncat) -#undef strtok -#define strtok(x,y) BANNED(strtok) -#undef strtok_r -#define strtok_r(x,y,z) BANNED(strtok_r) - -#undef sprintf -#undef vsprintf -#define sprintf(...) BANNED(sprintf) -#define vsprintf(...) BANNED(vsprintf) - -#undef gmtime -#define gmtime(t) BANNED(gmtime) -#undef localtime -#define localtime(t) BANNED(localtime) -#undef ctime -#define ctime(t) BANNED(ctime) -#undef ctime_r -#define ctime_r(t, buf) BANNED(ctime_r) -#undef asctime -#define asctime(t) BANNED(asctime) -#undef asctime_r -#define asctime_r(t, buf) BANNED(asctime_r) - -#undef mktemp -#define mktemp(x) BANNED(mktemp) - -#endif /* BANNED_H */ diff --git a/include/build.h b/include/build.h deleted file mode 100644 index 7dcb53a..0000000 --- a/include/build.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#ifndef PKGIT_BUILD_H -#define PKGIT_BUILD_H - -#include "pkg.h" - -bool build(package_t *pkg); - -#endif diff --git a/include/debug.h b/include/cli.h index e74a099..602fa6d 100644 --- a/include/debug.h +++ b/include/cli.h @@ -18,10 +18,15 @@ */ +#ifndef PKGIT_CLI_H +#define PKGIT_CLI_H -#ifndef PKGIT_DEBUG_H -#define PKGIT_DEBUG_H +typedef enum { + CLI_FAIL = 0, + CLI_SUCCESS = 1, + CLI_HELP_CALLED = 2, +} cli_result_t; -void debug_print_inst_dirs(void); +cli_result_t cli(int argc, char **argv); #endif diff --git a/include/globs.h b/include/common.h index 20c10f5..a77718b 100644 --- a/include/globs.h +++ b/include/common.h @@ -1,28 +1,24 @@ /* 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 <https://www.gnu.org/licenses/>. */ -#ifndef PKGIT_GLOBALS_H -#define PKGIT_GLOBALS_H - -#include <stdlib.h> - -#include "str.h" +#ifndef PKGIT_COMMON_H +#define PKGIT_COMMON_H #define VERSION "1.2.0" #define RED "\x1b[0;31m" @@ -68,7 +64,7 @@ panic("allocation of `%s` failed", #ptr); \ } while (0) -#define panic(...) \ +#define panic(...) \ do { \ char *tmp = strrchr(__FILE__, '/'); \ eprintf(BOLD RED "panic:" COLOR_RESET " line %d, func \"%s\" in file " \ @@ -106,25 +102,4 @@ #define MAX_DIRS 100 #define MAX_PATH_LEN 1024 -typedef struct { - bool verbose, force; -} cli_flags_t; - -typedef struct { - str dir, name, content, repos; - bool is_root_config; -} config_t; - -typedef struct { - str prefix, bin, lib, include, src; -} install_dirs_t; - -extern cli_flags_t flags; -extern config_t cfg; -extern install_dirs_t inst_dirs; -extern str new_arg_str; - -void init_vars(void); -void free_vars(void); - #endif diff --git a/include/fetch.h b/include/fetch.h deleted file mode 100644 index d392098..0000000 --- a/include/fetch.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#ifndef PKGIT_FETCH_H -#define PKGIT_FETCH_H - -#include "pkg.h" - -bool fetch(package_t *pkg); - -#endif diff --git a/include/files.h b/include/files.h deleted file mode 100644 index 9a17c88..0000000 --- a/include/files.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#ifndef PKGIT_FILES_H -#define PKGIT_FILES_H - -#include <stdbool.h> - -#include "str.h" - -bool file_exists(const char *path); -bool is_directory(const char *path); -str cmd_out(const char *cmd); -void cpdir(const char *src_path, const char *dst_path); -int remove_tree(const char *path); - -#endif diff --git a/include/help.h b/include/help.h index c194be4..28fb539 100644 --- a/include/help.h +++ b/include/help.h @@ -18,9 +18,9 @@ */ -#ifndef HELP_H -#define HELP_H +#ifndef PKGIT_HELP_H +#define PKGIT_HELP_H -void help(void); +void print_help(void); -#endif
\ No newline at end of file +#endif diff --git a/include/is_updated.h b/include/is_updated.h deleted file mode 100644 index 16f998f..0000000 --- a/include/is_updated.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#ifndef PKGIT_IS_UPDATED_H -#define PKGIT_IS_UPDATED_H - -#include <stdbool.h> -#include "str.h" -bool is_updated(str *src); - -#endif diff --git a/include/lua_state.h b/include/lua_state.h new file mode 100644 index 0000000..49f35e4 --- /dev/null +++ b/include/lua_state.h @@ -0,0 +1,16 @@ +#ifndef PKGIT_LUA_STATE_H +#define PKGIT_LUA_STATE_H + +#include <lauxlib.h> +#include <lua.h> +#include <lualib.h> +#include <stdbool.h> + +extern lua_State *L; +extern bool L_is_loaded; + +bool init_lua_state(void); +bool init_lua_config(void); +void free_lua_state(void); + +#endif diff --git a/include/parse_args.h b/include/parse_args.h deleted file mode 100644 index d68c37f..0000000 --- a/include/parse_args.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#ifndef PKGIT_CLA_PARSE_H -#define PKGIT_CLA_PARSE_H - -void parse_args(int argc, char **argv); - -#endif
\ No newline at end of file diff --git a/include/pkg.h b/include/pkg.h index 5ad88b2..47d1918 100644 --- a/include/pkg.h +++ b/include/pkg.h @@ -1,33 +1,24 @@ -/* - 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 <https://www.gnu.org/licenses/>. -*/ - #ifndef PKGIT_PKG_H #define PKGIT_PKG_H #include "str.h" -typedef struct { - str name, url, version, target, src; +struct package_t; +typedef bool (*package_hook_cb_t)(struct package_t *self); +typedef str (*package_version_cb_t)(struct package_t *self); + +typedef struct package_t { + str name, version, url, src; + unsigned int dep_count; bool is_local; + package_hook_cb_t setup, build, install, rem, on_update, fetch_sources; + package_version_cb_t fetch_latest_version; } package_t; -package_t pkg_create(str *arg); -void pkg_free(package_t *pkg); +bool setup(package_t *self), build(package_t *self), + install(package_t *self), rem(package_t *self), + on_update(package_t *self), + fetch_sources(package_t *self); +str fetch_latest_version(package_t *self); #endif diff --git a/include/pkgit_lua.h b/include/pkgit_lua.h deleted file mode 100644 index a9a6adf..0000000 --- a/include/pkgit_lua.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#ifndef PKGIT_LUA_H -#define PKGIT_LUA_H - -#include <lua.h> -#include <lauxlib.h> -#include <lualib.h> -#include <stdbool.h> - -#include "pkg.h" - -extern lua_State *L; -extern lua_State *B; -extern bool config_loaded; -extern bool bldit_loaded; - -// init -void push_lua_path(lua_State *L, const char *new_path); -void init_lua_state(void); -void init_bldit_state(void); -void free_lua_state(void); -void free_bldit_state(void); -lua_State *get_lua_state(void); -lua_State *get_bldit_state(void); - -// gobal vars -void init_install_directories(void); -void init_prefix_directory(void); - -// helpers -void lua_isnt_type(char* variable, char* type); -void bldit_isnt_type(char* variable, char* type); -bool lua_try_function(lua_State *L, char *lua_file, char *fname); -bool lua_try_table(lua_State *L, char *lua_file, char *tname); -bool pkg_exists(str *name); -str pkg_get_url(str *name); -str bldit_getver(void); -str bldit_pkg_getver(void); -bool is_bldit_usable(void); - -// install -void install_dependencies(lua_State *L); -void pkg_install(package_t *pkg); - -// remove -bool repo_uninstall(package_t *pkg); -bool bldit_uninstall(package_t *pkg); -bool config_uninstall(package_t *pkg); -void pkg_remove(package_t *pkg); - -// update -void pkg_update(package_t *pkg); -void all_update(void); - -// declare -void declare(void); - -#endif diff --git a/include/search.h b/include/search.h deleted file mode 100644 index 233537b..0000000 --- a/include/search.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#ifndef PKGIT_SEARCH_H -#define PKGIT_SEARCH_H - -void list_installed(void); -void search(char* arg); - -#endif diff --git a/include/state.h b/include/state.h new file mode 100644 index 0000000..9075270 --- /dev/null +++ b/include/state.h @@ -0,0 +1,45 @@ +/* + + 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 <https://www.gnu.org/licenses/>. + +*/ + +#include <stdbool.h> + +#include "str.h" + +typedef struct { + bool force, quiet; +} cli_flags_t; + +typedef struct inst_dirs_t { + str prefix, src, bin, lib, include; +} inst_dirs_t; + +typedef struct config_t { + inst_dirs_t inst_dirs; + str dir, init_path, autogenerated_path; + bool is_root; +} user_config_t; + +typedef struct { + str prefix, bin, lib, include, src; +} install_dirs_t; + +extern cli_flags_t flags; +extern user_config_t config; +extern install_dirs_t inst_dirs; diff --git a/include/str.h b/include/str.h index 3a4aefb..0e8ae59 100644 --- a/include/str.h +++ b/include/str.h @@ -74,6 +74,12 @@ str str_new_with_capacity(size_t cap); str str_from_cstr(const char *s); /** + * Adopts an existing heap-allocated C string, reusing its buffer in the + * resultant str. + */ +str str_adopt(char *s); + +/** * Equivalent to str_from_cstr */ str mstr(const char *s); @@ -182,6 +188,12 @@ void str_append_cstr(str *src, const char *new_cstr); void str_append_str_slc(str *src, const str_slc new_slc); /** + * Appends a new formatted section of the string, with the same calling + * style as str_append into an existing string buffer. + */ +void str_append_format(str *dest, const char *format, ...); + +/** * Removes the last character from src, returning it. */ char str_pop_last(str *src); @@ -444,7 +456,7 @@ str_slc str_slc_from_cstr(const char *s); /** * Equivalent to str_slc_from_cstr. */ -str_slc mstrslc(const char *s); +str_slc mslc(const char *s); str str_slc_concat(const str_slc lhs, const str_slc rhs); diff --git a/src/add_repo.c b/src/add_repo.c deleted file mode 100644 index 1c41f3b..0000000 --- a/src/add_repo.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#include <stdio.h> -#include <string.h> -#include <stdbool.h> - -#include "add_repo.h" - -#include "files.h" -#include "globs.h" - -void add_repo(package_t *pkg) { - bool is_previous_repos = false; - char rfile_line[1024]; - char rfile_contents[8192] = {0}; - - if (file_exists(cfg.repos.data)) { - FILE *rfile = fopen(cfg.repos.data, "r"); - if (rfile) { - while (fgets(rfile_line, sizeof(rfile_line), rfile)) { - strcat(rfile_contents, rfile_line); - } - fclose(rfile); - is_previous_repos = true; - } - } - - char *previous_repos = is_previous_repos ? rfile_contents : ""; - - FILE *wfile = fopen(cfg.repos.data, "w"); - if (wfile) { - fprintf(wfile, - "%srepositories[\"%s\"] = { url = \"%s\" }\n", - previous_repos, pkg->name.data, pkg->url.data - ); - fclose(wfile); - } -} diff --git a/src/build.c b/src/build.c deleted file mode 100644 index 1974846..0000000 --- a/src/build.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#include <stdio.h> -#include <unistd.h> - -#include "build.h" - -#include "globs.h" -#include "log.h" -#include "lua.h" -#include "pkg.h" -#include "pkgit_lua.h" - -bool target_build(lua_State *L, char *lua_file, str *target) { - if (!lua_try_table(L, lua_file, target->data)) - return false; - if (lua_try_table(L, lua_file, "dependencies")) { - lua_pushnil(L); - install_dependencies(L); - } - lua_pop(L, 1); - if (!lua_try_function(L, lua_file, "build")) - return false; - lua_pop(L, 1); - return true; -} - -bool repo_build(package_t *pkg) { - lua_getglobal(L, "repositories"); - if (!lua_try_table(L, "init.lua", pkg->name.data)) { - lua_pop(L, 2); - return false; - } - if (lua_try_table(L, "init.lua", "dependencies")) { - lua_pushnil(L); - install_dependencies(L); - } - lua_pop(L, 1); - if (!lua_try_table(L, "init.lua", "targets")) { - lua_pop(L, 3); - return false; - } - bool target_success = target_build(L, "init.lua", &pkg->target); - lua_pop(L, 4); - return target_success; -} - -bool bldit(package_t *pkg) { - init_bldit_state(); - if (!bldit_loaded) - return false; - lua_getglobal(B, "dependencies"); - if (!lua_istable(B, -1)) { - bldit_isnt_type("dependencies", "table"); - lua_pop(B, 1); - } else { - lua_pushnil(B); - install_dependencies(B); - lua_pop(B, 1); - } - lua_getglobal(B, "targets"); - if (!lua_istable(B, -1)) { - bldit_isnt_type("targets", "table"); - lua_pop(B, 1); - lua_close(B); - B = NULL; - bldit_loaded = false; - return false; - } - bool target_success = target_build(B, "bldit.lua", &pkg->target); - lua_pop(B, 1); - return target_success; -} - -bool config_build(package_t *pkg) { - lua_getglobal(L, "build_systems"); - if (!lua_istable(L, -1)) { - lua_isnt_type("build_systems", "table"); - lua_pop(L, 1); - return false; - } - bool target_success = false; - lua_pushnil(L); - while (lua_next(L, -2) != 0) { - str key = mstr(lua_tostring(L, -2)); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - str_free(&key); - continue; - } - str file_path = str_format("%.*s/%s", str_fmt(&pkg->src), key.data); - if (access(file_path.data, F_OK) != 0) { - lua_pop(L, 1); - str_free(&file_path); - str_free(&key); - continue; - } - str_free(&file_path); - str_free(&key); - if (!lua_try_table(L, "init.lua", "targets")) - continue; - target_success = target_build(L, "init.lua", &pkg->target); - if (target_success) - break; - lua_pop(L, 1); - } - lua_pop(L, 1); - return target_success; -} - -bool build_loop(package_t *pkg) { - if (flags.verbose) - log_info("attempting init.lua: 'repositories.%.*s.build'", - str_fmt(&pkg->name)); - if (repo_build(pkg)) { - return true; - } - if (flags.verbose) - log_warn("failed init.lua: 'repositories.%.*s.build'", - str_fmt(&pkg->name)); - - if (flags.verbose) - log_info("attempting bldit.lua"); - if (bldit(pkg)) { - return true; - } - if (flags.verbose) - log_warn("failed bldit.lua"); - - if (flags.verbose) - log_info("attempting init.lua: 'build_systems'"); - if (config_build(pkg)) { - return true; - } - if (flags.verbose) - log_warn("failed init.lua: 'build_systems'"); - return false; -} - -bool build(package_t *pkg) { - char cwd[MAX_PATH_LEN]; - if (getcwd(cwd, sizeof(cwd)) == NULL) { - log_error("getcwd failed"); - return false; - } - if (!str_equal_cstr(&pkg->src, cwd) && !pkg->is_local) - chdir(pkg->src.data); - - if (build_loop(pkg)) - return true; - log_error("no usable build system was found for %.*s", str_fmt(&pkg->name)); - return false; -} diff --git a/src/check.c b/src/check.c deleted file mode 100644 index 366f8a7..0000000 --- a/src/check.c +++ /dev/null @@ -1,43 +0,0 @@ -/* -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 <https://www.gnu.org/licenses/>. - -*/ - -#include <stdio.h> -#include <unistd.h> - -#include "check.h" - -void check(void) { - const char *frame_top = " (c _c)"; - const char *frame1_bot = "_/ \\-"; - const char *frame2_bot = "-/ \\_"; - - printf("\033[2J\033[H"); - printf("Unfortunately due to budget issues, we could not afford a progress bar. Enjoy this instead:\n\n"); - - for (int i = 0; i < 16; i++) { - printf("%s\n%s\n", frame_top, i % 2 == 0 ? frame1_bot : frame2_bot); - for (int j = 0; j <= i; j++) printf("."); - printf("\n"); - fflush(stdout); - sleep(1); - if (i < 15) printf("\033[3A"); - } - printf("\n"); - printf("Dependencies resolved! (this does nothing)\n"); -} diff --git a/src/cli.c b/src/cli.c new file mode 100644 index 0000000..c4499ff --- /dev/null +++ b/src/cli.c @@ -0,0 +1,246 @@ +/* + + 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 <https://www.gnu.org/licenses/>. + +*/ + +#include <stdio.h> +#include <string.h> + +#include "cli.h" +#include "common.h" +#include "help.h" +#include "log.h" +#include "state.h" +#include "str.h" + +#define COMMAND(large, small) \ + (!strcmp(argv[i], large) || !strcmp(argv[i], small)) + +#define NOT_ENOUGH_ARGS(arg, next) \ + log_error("Not enough arguments! Try: pkgit %s [%s]", (arg), (next)) + +void cmd_add(char **argv, int i) { + if (argv[i + 1]) { + str arg = mstr(argv[i + 1]); + if (str_is_valid(&arg)) + str_free(&arg); + } else { + NOT_ENOUGH_ARGS(argv[i], "url"); + } +} + +void cmd_build(int argc, char **argv, int i) { + if (argv[i + 1]) { + for (int j = i + 1; j < argc; j++) { + if (argv[j][0] == '-') + continue; + str arg = mstr(argv[j]); + if (str_is_valid(&arg)) + str_free(&arg); + } + } else { + str arg = mstr("."); + if (str_is_valid(&arg)) + str_free(&arg); + } +} + +void cmd_install(int argc, char **argv, int i) { + if (argv[i + 1]) { + for (int j = i + 1; j < argc; j++) { + if (argv[j][0] == '-') + continue; + str arg = mstr(argv[j]); + if (str_is_valid(&arg)) + str_free(&arg); + } + } else { + NOT_ENOUGH_ARGS(argv[i], "url/pkg"); + } +} + +void cmd_update(int argc, char **argv, int i) { + if (argv[i + 1]) { + for (int j = i + 1; j < argc; j++) { + if (argv[j][0] == '-') + continue; + str arg = mstr(argv[j]); + if (str_is_valid(&arg)) + str_free(&arg); + } + } else { + } +} + +void cmd_remove(int argc, char **argv, int i) { + if (argv[i + 1]) { + for (int j = i + 1; j < argc; j++) { + if (argv[j][0] == '-') + continue; + str arg = mstr(argv[j]); + if (str_is_valid(&arg)) + str_free(&arg); + } + } else { + NOT_ENOUGH_ARGS(argv[i], "url/pkg"); + } +} + +void cmd_search(int argc, char **argv, int i) { + if (argv[i + 1]) { + for (int j = i + 1; j < argc; j++) { + if (argv[j][0] == '-') + continue; + } + } else { + } +} + +void flags_mod(char **argv, int i) { + for (size_t j = 1; j < strlen(argv[i]); j++) { + switch (argv[i][j]) { + case 'q': + flags.quiet = true; + break; + case 'f': + flags.force = true; + break; + default: + break; + } + } +} + +cli_result_t flags_cmd(int argc, char **argv, int i) { + for (size_t j = 1; j < strlen(argv[i]); j++) { + switch (argv[i][j]) { + case 'a': + cmd_add(argv, i); + break; + case 'b': + cmd_build(argc, argv, i); + break; + case 'c': + // check(); + break; + case 'd': + // declare(); + break; + case 'i': + cmd_install(argc, argv, i); + break; + case 'r': + cmd_remove(argc, argv, i); + break; + case 'u': + cmd_update(argc, argv, i); + break; + case 'l': + // list_installed(); + break; + case 's': + cmd_search(argc, argv, i); + break; + case 'v': + printf("%s\n", VERSION); + break; + case 'h': + print_help(); + return CLI_HELP_CALLED; + break; + default: + break; + } + } + return CLI_SUCCESS; +} + +cli_result_t parse_flags(int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (argv[i][0] != '-') + continue; + if (argv[i][1] == '-') { + if (COMMAND("--quiet", "-q")) + flags.quiet = true; + if (COMMAND("--force", "-f")) + flags.force = true; + } else { + flags_mod(argv, i); + cli_result_t status = flags_cmd(argc, argv, i); + if (status != CLI_SUCCESS) + return status; + } + } + return CLI_SUCCESS; +} + +cli_result_t parse_cmds(int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (COMMAND("--add", "a")) { + cmd_add(argv, i); + } + if (COMMAND("--build", "b")) { + cmd_build(argc, argv, i); + } + if (COMMAND("--install", "i")) { + cmd_install(argc, argv, i); + } + if (COMMAND("--remove", "r")) { + cmd_remove(argc, argv, i); + } + if (COMMAND("--update", "u")) { + cmd_update(argc, argv, i); + } + if (COMMAND("--declare", "d")) { + // declare(); + } + if (COMMAND("--list", "l")) { + // list_installed(); + } + if (COMMAND("--search", "s")) { + cmd_search(argc, argv, i); + } + if (COMMAND("--version", "v")) { + printf(VERSION "\n"); + } + if (COMMAND("--help", "h")) { + print_help(); + return CLI_HELP_CALLED; + } + if (COMMAND("--check", "c")) { + // check(); + } + } + return CLI_SUCCESS; +} + +cli_result_t cli(int argc, char **argv) { + flags.force = false; + flags.quiet = false; + if (argc == 1) { + print_help(); + return CLI_HELP_CALLED; + } + if (!parse_flags(argc, argv)) + return CLI_FAIL; + + if (!parse_cmds(argc, argv)) + return CLI_FAIL; + + return CLI_SUCCESS; +} diff --git a/src/debug.c b/src/debug.c deleted file mode 100644 index 0a580df..0000000 --- a/src/debug.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - - -#include "globs.h" - -void debug_print_inst_dirs(void) { - printf("PREFIX:\t"); - str_println(&inst_dirs.prefix); - printf("ID_BIN:\t"); - str_println(&inst_dirs.bin); - printf("ID_LIB:\t"); - str_println(&inst_dirs.lib); - printf("ID_INCLUDE:\t"); - str_println(&inst_dirs.include); - printf("ID_SRC:\t"); - str_println(&inst_dirs.src); -} diff --git a/src/fetch.c b/src/fetch.c deleted file mode 100644 index 2666f78..0000000 --- a/src/fetch.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#include <fcntl.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "fetch.h" -#include "files.h" -#include "globs.h" -#include "log.h" -#include "str.h" - -bool fetch(package_t *pkg) { - if (pkg->url.data == NULL || pkg->src.data == NULL) { - if (flags.verbose) - log_warn("invalid pkg: url or src is NULL"); - return false; - } - - str s = str_dupe(&pkg->src); - s.len -= pkg->version.len + 1; - s.data[s.len] = 0; - - if (is_directory(s.data) && flags.force) { - if (remove_tree(s.data)) { - log_error("could not remove %.*s", str_fmt(&s)); - return false; - } - } - - str_free(&s); - - pid_t pid = fork(); - if (pid < 0) { - log_error("fork failed"); - return false; - } - - if (pid == 0) { - if (!flags.verbose) { - int nullfd = open("/dev/null", O_WRONLY); - if (nullfd >= 0) { - dup2(nullfd, STDOUT_FILENO); - dup2(nullfd, STDERR_FILENO); - close(nullfd); - } - } - - const char *argv[12]; - int i = 0; - argv[i++] = "git"; - argv[i++] = "-c"; - argv[i++] = "advice.detachedHead=false"; - argv[i++] = "clone"; - if (pkg->version.data != NULL && - !str_equal_cstr(&pkg->version, "HEAD")) { - argv[i++] = "--branch"; - argv[i++] = pkg->version.data; - } - - argv[i++] = "--recursive"; - argv[i++] = pkg->url.data; - argv[i++] = pkg->src.data; - argv[i] = NULL; - execvp("git", (char *const *)argv); - _exit(127); - } - int status; - waitpid(pid, &status, 0); - - bool result = (WEXITSTATUS(status) == 0); - if (!result) { - log_error("git clone failed"); - } - - return result; -} diff --git a/src/files.c b/src/files.c deleted file mode 100644 index 0ce64b4..0000000 --- a/src/files.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#define _XOPEN_SOURCE 700 - -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <ftw.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <unistd.h> - -#include "files.h" -#include "log.h" -#include "str.h" - -bool file_exists(const char *path) { - struct stat buffer; - return (stat(path, &buffer) == 0); -} - -bool is_directory(const char *path) { - struct stat statbuf; - if (stat(path, &statbuf) != 0) { - return false; - } - return S_ISDIR(statbuf.st_mode); -} - -FILE *popen(const char *command, const char *type); -int pclose(FILE *stream); - -str cmd_out(const char *cmd) { - FILE *pipe = popen(cmd, "r"); - if (!pipe) - return mstr(""); - - char buffer[128]; - size_t total_size = 0; - size_t capacity = 256; - char *result = malloc(capacity); - if (!result) { - pclose(pipe); - return mstr(""); - } - result[0] = '\0'; - - while (fgets(buffer, sizeof(buffer), pipe) != NULL) { - size_t len = strlen(buffer); - // Ensure enough space for the new chunk + 1 byte for '\0' - if (total_size + len + 1 > capacity) { - capacity *= 2; - char *new_result = realloc(result, capacity); - if (!new_result) { - free(result); - pclose(pipe); - return mstr(""); - } - result = new_result; - } - - snprintf(result + total_size, capacity - total_size, "%s", buffer); - total_size += len; - } - - pclose(pipe); - str str_result = mstr(result); - free(result); - return str_result; -} - -const char *get_filename_ext(const char *filename) { - const char *dot = strrchr(filename, '.'); - if (!dot || dot == filename) - return ""; - return dot + 1; -} - -static int write_all(int fd, const void *buf, size_t size) { - while (size) { - ssize_t written = write(fd, buf, size); - if (written < 0) { - return -1; - } - - size -= written; - buf = (const char *)buf + written; - } - - return 0; -} - -static int copy_file_content(int src_fd, int dst_fd) { - char buf[4096]; - ssize_t readed; - while ((readed = read(src_fd, buf, sizeof(buf))) > 0) { - if (write_all(dst_fd, buf, readed) < 0) { - perror("write_all"); - return -1; - } - } - - if (readed < 0) { - perror("read"); - return -1; - } - - return 0; -} - -static int copy_at(int src_dir_fd, const char *src_path, int dst_dir_fd, - const char *dst_path); - -static int copy_dir_content(int src_fd, int dst_fd) { - int ret = -1; - // duplicate the descriptor to prevent closedir from closing original one - src_fd = dup(src_fd); - if (src_fd < 0) { - perror("dup"); - goto cleanup0; - } - - DIR *src_dir = fdopendir(src_fd); - if (!src_dir) { - perror("fdopendir"); - close(src_fd); - goto cleanup0; - } - - for (struct dirent *ent; (errno = 0, ent = readdir(src_dir));) { - if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) { - continue; - } - - if (copy_at(src_fd, ent->d_name, dst_fd, ent->d_name) < 0) { - goto cleanup1; - } - } - - if (errno != 0) { - perror("readdir"); - goto cleanup1; - } - - ret = 0; - -cleanup1: - closedir(src_dir); -cleanup0: - return ret; -} - -static int copy_at(int src_dir_fd, const char *src_path, int dst_dir_fd, - const char *dst_path) { - int ret = -1; - int src_fd = openat(src_dir_fd, src_path, O_NOFOLLOW | O_RDONLY); - if (src_fd < 0) { - perror("openat"); - goto cleanup0; - } - - struct stat stat; - if (fstat(src_fd, &stat) < 0) { - perror("fstat"); - goto cleanup1; - } - - int dst_oflag = O_NOFOLLOW; - if (S_ISDIR(stat.st_mode)) { - if (mkdirat(dst_dir_fd, dst_path, stat.st_mode) < 0) { - perror("mkdirat"); - goto cleanup1; - } - - dst_oflag |= O_RDONLY | O_DIRECTORY; - } else { - dst_oflag |= O_WRONLY | O_CREAT | O_EXCL; - } - - int dst_fd = openat(dst_dir_fd, dst_path, dst_oflag, stat.st_mode); - if (dst_fd < 0) { - perror("openat"); - goto cleanup1; - } - - switch (stat.st_mode & S_IFMT) { - case S_IFDIR: - ret = copy_dir_content(src_fd, dst_fd); - break; - case S_IFREG: - ret = copy_file_content(src_fd, dst_fd); - break; - default: - fprintf(stderr, "copy_at: unsupported file inode type\n"); - } - goto cleanup2; - -cleanup2: - close(dst_fd); -cleanup1: - close(src_fd); -cleanup0: - return ret; -} - -void cpdir(const char *src_path, const char *dst_path) { - copy_at(AT_FDCWD, src_path, AT_FDCWD, dst_path); -} - -static int _remove_callback(const char *fpath, const struct stat *sb, - int typeflag, struct FTW *ftwbuf) { - (void)sb; - (void)typeflag; - (void)ftwbuf; - - int res = remove(fpath); - if (res) { - log_warn("could not remove: %s", fpath); - } - return 0; -} - -int remove_tree(const char *path) { - return nftw(path, _remove_callback, 256, FTW_DEPTH | FTW_PHYS); -} diff --git a/src/globs.c b/src/globs.c deleted file mode 100644 index cdb9df8..0000000 --- a/src/globs.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#include <stdlib.h> - -#include "globs.h" - -#include "files.h" -#include "log.h" -#include "pkgit_lua.h" -#include "str.h" - -install_dirs_t inst_dirs = {0}; -cli_flags_t flags = {0}; -config_t cfg = {0}; - -void init_vars(void) { - if (file_exists("/etc/pkgit/repos.lua")) { - cfg.dir = mstr("/etc/pkgit"); - cfg.name = mstr("/etc/pkgit/repos.lua"); - } else { - const char *tmp = getenv("XDG_CONFIG_HOME"); - if (tmp) { - cfg.dir = str_format("%s/pkgit", tmp); - } else { - cfg.dir = str_format("%s/.config/pkgit", getenv("HOME")); - } - cfg.name = str_concat_cstr(&cfg.dir, "/init.lua"); - } - // TODO: read into cfg.content - - cfg.repos = str_format("%.*s/repos.lua", str_fmt(&cfg.dir)); - init_install_directories(); - init_prefix_directory(); -} - -void free_vars(void) { - str_free(&cfg.dir); - str_free(&cfg.name); - str_free(&cfg.content); - str_free(&cfg.repos); - str_free(&inst_dirs.prefix); - str_free(&inst_dirs.bin); - str_free(&inst_dirs.lib); - str_free(&inst_dirs.include); - str_free(&inst_dirs.src); -} @@ -20,10 +20,11 @@ #include <stdio.h> +#include "common.h" #include "help.h" -#include "globs.h" +#include "state.h" -void help(void) { +void print_help(void) { typedef struct { const char *short_flag; const char *long_flag; @@ -50,7 +51,7 @@ void help(void) { {"-f", "--force", "", "build a package"}, }; - if (flags.verbose) { + if (!flags.quiet) { printf(BOLD_MAGENTA " , \n"); printf(BOLD_MAGENTA " / \\ \n"); printf(BOLD_MAGENTA "_.--' '--._ \n"); diff --git a/src/is_updated.c b/src/is_updated.c deleted file mode 100644 index fef759e..0000000 --- a/src/is_updated.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#include <string.h> -#include <stdbool.h> -#include <unistd.h> - -#include "is_updated.h" - -#include "files.h" -#include "str.h" -#include "pkgit_lua.h" - -bool is_updated(str *src) { - bool result = false; - if (str_is_valid(src) && src->len > 0 && chdir(src->data) != 0) return result; - str bldit_pkgver = bldit_pkg_getver(); - str git_tag = cmd_out("git tag | tail -n 1"); - result = (strstr(git_tag.data, bldit_pkgver.data) != NULL && bldit_pkgver.len != 0); - if (result) { - str_free(&bldit_pkgver); - str_free(&git_tag); - return result; - } - str git_pull = cmd_out("git pull"); - result = (strstr(git_pull.data, "Already up to date.") != NULL); - str_free(&git_tag); - str_free(&git_pull); - str_free(&bldit_pkgver); - return result; -} @@ -2,7 +2,7 @@ #include <stdarg.h> #include <stdio.h> -#include "globs.h" +#include "common.h" #include "log.h" #define X(n, N) \ diff --git a/src/lua_globs.c b/src/lua_globs.c deleted file mode 100644 index 3f8ac2a..0000000 --- a/src/lua_globs.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#include <stdlib.h> -#include <string.h> - -#include "lua.h" -#include "pkgit_lua.h" - -#include "files.h" -#include "globs.h" -#include "log.h" -#include "str.h" - -lua_State *L = NULL; -lua_State *B = NULL; -bool config_loaded = false; -bool bldit_loaded = false; - -void push_lua_path(lua_State *L, const char *new_path) { - lua_getglobal(L, "package"); - lua_getfield(L, -1, "path"); - const char *current_path = lua_tostring(L, -1); - if (!current_path) - current_path = ""; - lua_pop(L, 1); - lua_pushfstring(L, "%s;%s", current_path, new_path); - lua_setfield(L, -2, "path"); - lua_pop(L, 1); -} - -void init_lua_state(void) { - if (L != NULL) - return; - L = luaL_newstate(); - luaL_openlibs(L); - str lua_path = str_format("%.*s/?.lua", str_fmt(&cfg.dir)); - push_lua_path(L, lua_path.data); - if (luaL_loadfile(L, cfg.name.data) || lua_pcall(L, 0, 0, 0)) { - log_error("cannot run configuration script: %s", lua_tostring(L, -1)); - log_pkgit("to generate a configuration file, head into the"); - log_pkgit( - "root directory of the pkgit source and run `make defconfig`"); - exit(EXIT_FAILURE); - } - if (file_exists(cfg.repos.data)) { - if (luaL_loadfile(L, cfg.repos.data) || lua_pcall(L, 0, 0, 0)) { - if (flags.verbose) - log_warn("cannot load repository file: %s", - lua_tostring(L, -1)); - lua_pop(L, 1); - } - } - str_free(&lua_path); - config_loaded = true; -} - -void init_bldit_state(void) { - if (B != NULL) - return; - B = luaL_newstate(); - luaL_openlibs(B); - if (luaL_loadfile(B, "bldit.lua") || lua_pcall(B, 0, 0, 0)) { - if (flags.verbose) - log_warn("cannot run bldit: %s", lua_tostring(B, -1)); - return; - } - lua_pushfstring(B, "%s", inst_dirs.prefix.data); - lua_setglobal(B, "prefix"); - bldit_loaded = true; -} - -void free_lua_state(void) { - if (L != NULL) { - lua_close(L); - L = NULL; - } - config_loaded = false; -} - -void free_bldit_state(void) { - if (B != NULL) { - lua_close(B); - B = NULL; - } - bldit_loaded = false; -} - -lua_State *get_lua_state(void) { - return L; -} - -lua_State *get_bldit_state(void) { - return B; -} - -void lua_isnt_type(char *variable, char *type) { - if (flags.verbose) - log_error("init.lua: '%s' is not a %s.", variable, type); -} - -void bldit_isnt_type(char *variable, char *type) { - if (flags.verbose) - log_error("bldit.lua: '%s' is not a %s.", variable, type); -} - -bool lua_try_function(lua_State *L, char *lua_file, char *fname) { - lua_getfield(L, -1, fname); - if (!lua_isfunction(L, -1)) { - if (!strcmp(lua_file, "bldit.lua")) - bldit_isnt_type(fname, "function"); - else - lua_isnt_type(fname, "function"); - lua_pop(L, 1); - return false; - } else if (lua_pcall(L, 0, 1, 0) != LUA_OK) { - if (flags.verbose) - log_warn("%s: '%s' function borked: %s", lua_file, fname, - lua_tostring(L, -1)); - lua_pop(L, 1); - return false; - } - if (!lua_isnumber(L, -1) || lua_tonumber(L, -1) != 0) { - if (flags.verbose) - log_warn("%s: '%s' failed: %s", lua_file, fname, - lua_tostring(L, -1)); - lua_pop(L, 1); - return false; - } - lua_pop(L, 1); - return true; -} - -bool lua_try_table(lua_State *L, char *lua_file, char *tname) { - lua_getfield(L, -1, tname); - if (!lua_istable(L, -1)) { - if (!strcmp(lua_file, "bldit.lua")) - bldit_isnt_type(tname, "table"); - else - lua_isnt_type(tname, "table"); - return false; - } - return true; -} - -str bldit_getver(void) { - init_bldit_state(); - if (!bldit_loaded) { - return mstr(""); - } - lua_getglobal(B, "bldit_version"); - if (!lua_isstring(B, -1)) { - if (flags.verbose) - log_warn("bldit.lua: 'bldit_version' is not a string."); - lua_pop(B, 1); - return mstr(""); - } - str bldit_version = mstr(lua_tostring(B, -1)); - lua_pop(B, 1); - return bldit_version; -} - -str bldit_pkg_getver(void) { - init_bldit_state(); - lua_getglobal(B, "package_version"); - if (!lua_isstring(B, -1)) { - if (flags.verbose) - log_warn("bldit.lua: 'package_version' is not a string."); - lua_pop(B, 1); - return mstr(""); - } - str package_version = mstr(lua_tostring(B, -1)); - lua_pop(B, 1); - return package_version; -} - -bool is_bldit_usable(void) { - str bldit_version = bldit_getver(); - if (bldit_version.len && str_equal_cstr(&bldit_version, VERSION)) - goto done; - bool prev_pass = false; - for (size_t i = 0; i < bldit_version.len; i++) { - if (bldit_version.data[i] == '.') - continue; - if ((bldit_version.data[i] - '0') <= (VERSION[i] - '0')) { - prev_pass = ((bldit_version.data[i] - '0') != (VERSION[i] - '0')); - continue; - } else { - str_free(&bldit_version); - return prev_pass; - } - } -done: - str_free(&bldit_version); - return true; -} diff --git a/src/lua_state.c b/src/lua_state.c new file mode 100644 index 0000000..7e9dd18 --- /dev/null +++ b/src/lua_state.c @@ -0,0 +1,146 @@ +#include <lua.h> +#include <stdlib.h> +#include <unistd.h> + +#include "log.h" +#include "lua_state.h" +#include "state.h" +#include "str.h" + +lua_State *L = NULL; +bool L_is_loaded = false; + +static void lua_path_push(const char *new_path) { + lua_getglobal(L, "package"); + lua_getfield(L, -1, "path"); + + const char *current_path = lua_tostring(L, -1); + if (!current_path) + current_path = ""; + lua_pop(L, 1); + + lua_pushfstring(L, "%s;%s", current_path, new_path); + lua_setfield(L, -2, "path"); + + lua_pop(L, 1); +} + +bool init_lua_state(void) { + if (L_is_loaded) + return true; + + L = luaL_newstate(); + luaL_openlibs(L); + + str lua_path = str_format("%.*s/?.lua", str_fmt(&config.dir)); + lua_path_push(lua_path.data); + + if (luaL_loadfile(L, config.init_path.data) || lua_pcall(L, 0, 1, 0)) { + log_error("cannot run configuration script: %s", lua_tostring(L, -1)); + log_pkgit("to generate a configuration file, head into the"); + log_pkgit( + "root directory of the pkgit source and run `make defconfig`"); + lua_close(L); + return false; + } + + if (!lua_istable(L, -1)) { + log_error("top-level configuration is not a table"); + lua_pop(L, 1); + lua_close(L); + return false; + } + + str_free(&lua_path); + L_is_loaded = true; + return true; +} + +static void setup_base_dirs(void) { + int uid = getuid(), euid = geteuid(); + + config.is_root = false; + + if (uid < 0 || uid != euid) { + config.is_root = true; + config.dir = mstr("/etc/pkgit"); + } else { + char *tmp = getenv("XDG_CONFIG_HOME"); + if (tmp) { + config.dir = str_format("%s/pkgit", tmp); + } else { + config.dir = str_format("%s/.config/pkgit", getenv("HOME")); + } + } + + config.init_path = str_concat_cstr(&config.dir, "/init.lua"); + config.autogenerated_path = + str_concat_cstr(&config.dir, "/autogenerated.lua"); +} + +#define HANDLE_LUA_ERROR \ + do { \ + log_error("lua: %s", lua_tostring(L, -1)); \ + lua_pop(L, 1); \ + return false; \ + } while (0) + +#define lua_get_field_type(name, type, file) \ + do { \ + lua_getfield(L, -1, name); \ + if (!lua_is##type(L, -1)) { \ + log_error("lua: expected type " #type " for " name " in %.*s", \ + str_fmt(file)); \ + lua_pop(L, 1); \ + return false; \ + } \ + } while (0) + +static bool load_init_lua(void) { + if (luaL_loadfile(L, config.init_path.data)) + HANDLE_LUA_ERROR; + + lua_setglobal(L, "__PkgitUserConfig"); + + lua_getglobal(L, "__PkgitUserConfig"); + lua_get_field_type("dirs", table, &config.init_path); + +#define X(field) \ + do { \ + lua_get_field_type(#field, string, &config.init_path); \ + config.inst_dirs.field = str_adopt((char *)lua_tostring(L, -1)); \ + lua_pop(L, -1); \ + } while (0) + + X(prefix); + X(bin); + X(include); + X(lib); + X(src); + +#undef X + + lua_getfield(L, -1, "prefix"); + + return true; +} + +bool init_lua_config(void) { + if (!init_lua_state()) + return false; + + setup_base_dirs(); + + if (!load_init_lua()) + return false; + + return true; +} + +void free_lua_state(void) { + if (L != NULL) { + lua_close(L); + L = NULL; + } + L_is_loaded = false; +} diff --git a/src/lua_vars.c b/src/lua_vars.c deleted file mode 100644 index 7420ae0..0000000 --- a/src/lua_vars.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#include "pkgit_lua.h" - -#include "globs.h" - -void init_install_directories(void) { - init_lua_state(); - if (!lua_istable(L, -1)) { - lua_getglobal(L, "install_directories"); - } - if (!lua_istable(L, -1)) { - lua_isnt_type("install_directories", "table"); - return; - } - -#define SETUP_INST_DIRS \ - X(bin) \ - X(lib) \ - X(include) \ - X(src) - -#define X(dir) \ - do { \ - lua_getfield(L, -1, #dir); \ - if (!lua_isstring(L, -1)) { \ - lua_isnt_type("install_directories." #dir, "string"); \ - } else { \ - str_copy_cstr_into(&inst_dirs.dir, lua_tostring(L, -1)); \ - } \ - lua_pop(L, 1); \ - } while (0); - - SETUP_INST_DIRS -#undef X - - lua_pop(L, 1); -} - -void init_prefix_directory(void) { - lua_getglobal(L, "prefix"); - if (!lua_isstring(L, -1)) { - lua_isnt_type("prefix", "string."); - return; - } - inst_dirs.prefix = mstr(lua_tostring(L, -1)); - lua_pop(L, 1); -} @@ -18,12 +18,28 @@ */ -#include "parse_args.h" -#include "globs.h" +#include "cli.h" +#include "lua_state.h" int main(int argc, char **argv) { - init_vars(); - parse_args(argc, argv); - free_vars(); - return 0; + // if (!init_vars()) + // return 1; + + int retval = 0; + cli_result_t result = cli(argc, argv); + if (!result) { + retval = 1; + goto done; + } + + if (result != CLI_HELP_CALLED) { + init_lua_state(); + // if (!init_vars()) + // return 1; + } + +done: + free_lua_state(); + // free_vars(); + return retval; } diff --git a/src/parse_args.c b/src/parse_args.c deleted file mode 100644 index ff72334..0000000 --- a/src/parse_args.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#include <stdio.h> -#include <string.h> - -#include "parse_args.h" - -#include "build.h" -#include "globs.h" -#include "log.h" -#include "str.h" -#include "check.h" -#include "help.h" -#include "pkg.h" -#include "pkgit_lua.h" -#include "add_repo.h" -#include "search.h" - -#define COMMAND(large, small) \ - (!strcmp(argv[i], large) || !strcmp(argv[i], small)) - -#define NOT_ENOUGH_ARGS(arg, next) \ - log_error("Not enough arguments! Try: pkgit %s [%s]", (arg), (next)) - -void cmd_add(char **argv, int i) { - if (argv[i + 1]) { - str arg = mstr(argv[i + 1]); - package_t pkg = pkg_create(&arg); - add_repo(&pkg); - pkg_free(&pkg); - if (str_is_valid(&arg)) str_free(&arg); - } else { - NOT_ENOUGH_ARGS(argv[i], "url"); - } -} - -void cmd_build(int argc, char **argv, int i) { - if (argv[i + 1]) { - for (int j = i + 1; j < argc; j++) { - if (argv[j][0] == '-') - continue; - str arg = mstr(argv[j]); - package_t pkg = pkg_create(&arg); - build(&pkg); - pkg_free(&pkg); - if (str_is_valid(&arg)) str_free(&arg); - } - } else { - str arg = mstr("."); - package_t pkg = pkg_create(&arg); - build(&pkg); - pkg_free(&pkg); - if (str_is_valid(&arg)) str_free(&arg); - } -} - -void cmd_install(int argc, char **argv, int i) { - if (argv[i + 1]) { - for (int j = i + 1; j < argc; j++) { - if (argv[j][0] == '-') continue; - str arg = mstr(argv[j]); - package_t pkg = pkg_create(&arg); - if (flags.force) pkg_remove(&pkg); - pkg_install(&pkg); - pkg_free(&pkg); - if (str_is_valid(&arg)) str_free(&arg); - } - } else { - NOT_ENOUGH_ARGS(argv[i], "url/pkg"); - } -} - -void cmd_update(int argc, char **argv, int i) { - if (argv[i + 1]) { - for (int j = i + 1; j < argc; j++) { - if (argv[j][0] == '-') continue; - str arg = mstr(argv[j]); - package_t pkg = pkg_create(&arg); - pkg_update(&pkg); - pkg_free(&pkg); - if (str_is_valid(&arg)) str_free(&arg); - } - } else { - all_update(); - } -} - -void cmd_remove(int argc, char **argv, int i) { - if (argv[i + 1]) { - for (int j = i + 1; j < argc; j++) { - if (argv[j][0] == '-') continue; - str arg = mstr(argv[j]); - package_t pkg = pkg_create(&arg); - pkg_remove(&pkg); - pkg_free(&pkg); - if (str_is_valid(&arg)) str_free(&arg); - } - } else { - NOT_ENOUGH_ARGS(argv[i], "url/pkg"); - } -} - -void cmd_search(int argc, char **argv, int i) { - if (argv[i + 1]) { - for (int j = i + 1; j < argc; j++) { - if (argv[j][0] == '-') continue; - search(argv[j]); - } - } else { - search(""); - } -} - -void flags_mod(char **argv, int i) { - for (size_t j = 1; j < strlen(argv[i]); j++) { - switch (argv[i][j]) { - case 'q': - flags.verbose = false; - break; - case 'f': - flags.force = true; - break; - default: - break; - } - } -} - -void flags_cmd(int argc, char **argv, int i) { - for (size_t j = 1; j < strlen(argv[i]); j++) { - switch (argv[i][j]) { - case 'a': cmd_add(argv, i); break; - case 'b': cmd_build(argc, argv, i); break; - case 'c': check(); break; - case 'd': declare(); break; - case 'i': cmd_install(argc, argv, i); break; - case 'r': cmd_remove(argc, argv, i); break; - case 'u': cmd_update(argc, argv, i); break; - case 'l': list_installed(); break; - case 's': cmd_search(argc, argv, i); break; - case 'v': printf("%s\n", VERSION); break; - case 'h': help(); break; - default: break; - } - } -} - -void parse_flags(int argc, char **argv) { - for (int i = 1; i < argc; i++) { - if (argv[i][0] != '-') continue; - if (argv[i][1] == '-') { - if (COMMAND("--quiet", "-q")) flags.verbose = false; - if (COMMAND("--force", "-f")) flags.force = true; - } else { - flags_mod(argv, i); - flags_cmd(argc, argv, i); - } - } - return; -} - -void parse_cmds(int argc, char **argv) { - for (int i = 1; i < argc; i++) { - if (COMMAND("--add", "a")) { cmd_add(argv, i); } - if (COMMAND("--build", "b")) { cmd_build(argc, argv, i); } - if (COMMAND("--install", "i")) { cmd_install(argc, argv, i); } - if (COMMAND("--remove", "r")) { cmd_remove(argc, argv, i); } - if (COMMAND("--update", "u")) { cmd_update(argc, argv, i); } - if (COMMAND("--declare", "d")) { declare(); } - if (COMMAND("--list", "l")) { list_installed(); } - if (COMMAND("--search", "s")) { cmd_search(argc, argv, i); } - if (COMMAND("--version", "v")) { printf(VERSION "\n"); } - if (COMMAND("--help", "h")) { help(); } - if (COMMAND("--check", "c")) { check(); } - } -} - -void parse_args(int argc, char **argv) { - flags.force = false; - flags.verbose = true; - if (argc == 1) { - help(); - return; - } - parse_flags(argc, argv); - parse_cmds(argc, argv); - return; -} diff --git a/src/pkg_create.c b/src/pkg_create.c deleted file mode 100644 index 5afd1b0..0000000 --- a/src/pkg_create.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - - pkgit - package_t 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 <https://www.gnu.org/licenses/>. */ - -#include <string.h> -#include <unistd.h> - -#include "pkg.h" - -#include "files.h" -#include "globs.h" -#include "log.h" -#include "pkgit_lua.h" -#include "str.h" - -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(&inst_dirs.src), str_fmt(cwd)); - } else { - str name = {0}; - 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(&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(&inst_dirs.src), str_fmt(&pkg.name)); - else - return str_format("%.*s/%.*s/%.*s", str_fmt(&inst_dirs.src), - str_fmt(&pkg.name), str_fmt(&pkg.version)); -} - -static void assign_pkg_version(package_t *pkg, str *new_arg_str) { - if (str_find_char(new_arg_str, '@')) { - str tmp_arg = str_from_after_delim(new_arg_str, '@'); - if (str_find_char(new_arg_str, ',')) { - str tmp_trg = str_from_after_delim(&tmp_arg, ','); - pkg->version = str_from_after_delim(new_arg_str, '@'); - pkg->version.len -= tmp_trg.len; - str_free(&tmp_trg); - } else { - pkg->version = str_from_after_delim(new_arg_str, '@'); - } - if (str_find_char(&pkg->version, ',')) pkg->version.len--; - str_free(&tmp_arg); - pkg->name.len -= pkg->version.len + 1; - } else str_copy_cstr_into(&pkg->version, "HEAD");; -} - -static void assign_pkg_target(package_t *pkg, str *new_arg_str) { - if (str_find_char(new_arg_str, ',')) { - str tmp_arg = str_from_after_delim(new_arg_str, ','); - if (str_find_char(new_arg_str, '@')) { - str tmp_ver = str_from_after_delim(&tmp_arg, '@'); - pkg->target = str_from_after_delim(new_arg_str, ','); - pkg->target.len -= tmp_ver.len; - str_free(&tmp_ver); - } else { - pkg->target = str_from_after_delim(new_arg_str, ','); - } - if (str_find_char(&pkg->target, '@')) pkg->target.len--; - str_free(&tmp_arg); - pkg->name.len -= pkg->target.len + 1; - } else if (!flags.verbose) { - str_copy_cstr_into(&pkg->target, "quiet"); - } else str_copy_cstr_into(&pkg->target, "quiet"); -} - -package_t pkg_create(str *arg) { - package_t pkg = { .is_local = false, }; - - assign_pkg_version(&pkg, arg); - assign_pkg_target(&pkg, arg); - if (str_find_char(arg, '@')) { - str tmp = str_from_after_delim(arg, '@'); - arg->len -= tmp.len + 1; - str_free(&tmp); - } if (str_find_char(arg, ',')) { - str tmp = str_from_after_delim(arg, ','); - arg->len -= tmp.len + 1; - str_free(&tmp); - } - - char cwd[MAX_PATH_LEN]; - getcwd(cwd, MAX_PATH_LEN); - str cwd_str = mstr(cwd); - str dest_dir = get_destdir(&cwd_str, arg); - bool is_installed_locally = is_directory(dest_dir.data); - - if (strncmp(arg->data, "http", 4) == 0 || strncmp(arg->data, "ssh", 3) == 0) { - str_copy_into(&pkg.url, arg); - pkg.name = str_from_after_delim(arg, '/'); - } else if (str_equal_cstr(arg, ".")) { - str_copy_cstr_into(&pkg.url, ""); - pkg.name = str_from_after_delim(&cwd_str, '/'); - pkg.is_local = true; - } else if (pkg_exists(arg)) { - str_copy_into(&pkg.name, arg); - pkg.url = pkg_get_url(&pkg.name); - } else if (is_installed_locally) { - str_copy_cstr_into(&pkg.url, ""); - pkg.name = str_from_after_delim(&dest_dir, '/'); - pkg.is_local = true; - } else { - log_error("'%.*s' is not a valid package", str_fmt(arg)); - str_free(&cwd_str); - str_free(&dest_dir); - str_free(arg); - free_vars(); - exit(EXIT_FAILURE); - } - - if (str_find_char(arg, ',') - && str_find_char(arg, '@') - ) pkg.name.len--; - pkg.src = get_pkgsrc(pkg); - - str_free(&cwd_str); - str_free(&dest_dir); - if (pkg.is_local) str_free(arg); - return pkg; -} diff --git a/src/pkg_exists.c b/src/pkg_exists.c deleted file mode 100644 index 3ff761a..0000000 --- a/src/pkg_exists.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#include "pkgit_lua.h" -#include "str.h" - -bool pkg_exists(str *name) { - lua_getglobal(L, "repositories"); - if (!config_loaded || !lua_istable(L, -1)) { - lua_pop(L, 1); - return false; - } - str_slc new_name = {name->data, name->len}; - char* name_cstr = (char*)new_name.data; - name_cstr[new_name.len] = '\0'; - if (!lua_try_table(L, "init.lua", name_cstr)) { - lua_pop(L, 2); - return false; - } - lua_pop(L, 2); - return true; -} - -str pkg_get_url(str *name) { - lua_getglobal(L, "repositories"); - if (!config_loaded || !lua_istable(L, -1)) { - lua_pop(L, 1); - return mstr(""); - } - if (!lua_try_table(L, "init.lua", name->data)) { - lua_pop(L, 2); - return mstr(""); - } - lua_getfield(L, -1, "url"); - if (lua_isstring(L, -1)) { - return mstr(lua_tostring(L, -1)); - } - lua_pop(L, 3); - return mstr(""); -} diff --git a/src/pkg_free.c b/src/pkg_free.c deleted file mode 100644 index 5944c4d..0000000 --- a/src/pkg_free.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "pkg.h" -#include "globs.h" - -void pkg_free(package_t *pkg) { - str_free(&pkg->name); - str_free(&pkg->url); - str_free(&pkg->version); - str_free(&pkg->target); - str_free(&pkg->src); -} diff --git a/src/pkg_install.c b/src/pkg_install.c deleted file mode 100644 index 0a1f427..0000000 --- a/src/pkg_install.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#include <sys/stat.h> -#include <unistd.h> - -#include "lua.h" -#include "pkgit_lua.h" - -#include "add_repo.h" -#include "build.h" -#include "fetch.h" -#include "files.h" -#include "globs.h" -#include "log.h" -#include "pkg.h" - -void install_dependencies(lua_State *L) { - while (lua_next(L, -2) != 0) { - const char *depname = lua_tostring(L, -2); - if (depname && lua_istable(L, -1)) { - lua_getfield(L, -1, "url"); - str dep_url = mstr(lua_tostring(L, -1)); - lua_pop(L, 1); - package_t pkg = pkg_create(&dep_url); - str_free(&dep_url); - lua_getfield(L, -1, "version"); - str_free(&pkg.version); - const char *ver = lua_tostring(L, -1); - pkg.version = ver ? mstr(ver) : mstr("HEAD"); - lua_pop(L, 1); - const int top = lua_gettop(L); - char cwd[MAX_PATH_LEN]; - if (getcwd(cwd, sizeof(cwd)) != NULL) { - pkg_install(&pkg); - chdir(cwd); - } - lua_settop(L, top); - pkg_free(&pkg); - } - lua_pop(L, 1); - } -} - -bool target_install(lua_State *L, char *lua_file, str *target) { - if (!lua_try_table(L, lua_file, target->data)) { - lua_pop(L, 1); - return false; - } - if (!lua_try_function(L, lua_file, "install")) { - lua_pop(L, 1); - return false; - } - lua_pop(L, 1); - return true; -} - -bool repo_install(package_t *pkg) { - lua_getglobal(L, "repositories"); - if (!config_loaded || !lua_istable(L, -1)) { - lua_isnt_type("repositories", "table"); - lua_pop(L, 1); - return false; - } - if (!lua_try_table(L, "init.lua", pkg->name.data)) { - lua_isnt_type(pkg->name.data, "table"); - lua_pop(L, 2); - return false; - } - if (!lua_try_table(L, "init.lua", "targets")) - return false; - bool target_success = target_install(L, "init.lua", &pkg->target); - lua_pop(L, 3); - return target_success; -} - -bool bldit_install(package_t *pkg) { - init_bldit_state(); - if (!bldit_loaded) { - return false; - } - if (!is_bldit_usable()) { - log_error("bldit version is newer than the installed pkgit version"); - log_error("consider updating pkgit"); - if (!flags.force) - return false; - } - lua_pushfstring(B, "%s", inst_dirs.prefix.data); - lua_setglobal(B, "prefix"); - lua_getglobal(B, "targets"); - if (!lua_istable(B, -1)) { - log_error("targets is not a table in bldit.lua!"); - return false; - } - bool target_success = target_install(B, "bldit.lua", &pkg->target); - lua_pop(B, 1); - return target_success; -} - -bool config_install(package_t *pkg) { - lua_getglobal(L, "build_systems"); - lua_pushnil(L); - bool target_success = false; - while (lua_next(L, -2) != 0) { - const char *key = lua_tostring(L, -2); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - continue; - } - str file_path = str_format("%.*s/%s", str_fmt(&pkg->src), key); - if (access(file_path.data, F_OK) != 0) { - lua_pop(L, 1); - str_free(&file_path); - continue; - } - str_free(&file_path); - if (!lua_try_table(L, "init.lua", "targets")) { - lua_pop(L, 2); - continue; - } - target_success = target_install(L, "init.lua", &pkg->target); - lua_pop(L, 2); - if (target_success) - break; - } - lua_pop(L, 1); - return target_success; -} - -void pkg_install(package_t *pkg) { - if (is_directory(pkg->src.data)) { - if (!flags.force) { - log_info("%.*s is already installed.", str_fmt(&pkg->name)); - return; - } else { - if (flags.verbose) - log_warn("%.*s is already installed. reinstalling...", - str_fmt(&pkg->name)); - } - } else { - mkdir(pkg->src.data, 0755); - chdir(pkg->src.data); - } - char cwd[MAX_PATH_LEN]; - getcwd(cwd, MAX_PATH_LEN); - if (str_equal_cstr(&pkg->src, cwd)) - chdir(pkg->src.data); - - if (pkg->is_local) { - cpdir(cwd, pkg->src.data); - } else { - log_pkgit("fetching " GREEN "%.*s" COLOR_RESET, str_fmt(&pkg->name)); - if (!fetch(pkg)) - return; - if (flags.verbose) - log_pkgit("fetched " GREEN "%.*s" COLOR_RESET, str_fmt(&pkg->name)); - } - - log_pkgit("building " GREEN "%.*s" COLOR_RESET, str_fmt(&pkg->name)); - if (!build(pkg)) - return; - if (flags.verbose) - log_pkgit("built " GREEN "%.*s" COLOR_RESET, str_fmt(&pkg->name)); - - bool install_success = false; - if (flags.verbose) - log_info("attempting init.lua: 'repositories.%.*s.install'", - str_fmt(&pkg->name)); - if (!install_success && repo_install(pkg)) - install_success = true; - if (flags.verbose) - log_info("attempting bldit.lua: 'repositories.%.*s.install'", - str_fmt(&pkg->name)); - if (!install_success && bldit_install(pkg)) - install_success = true; - if (flags.verbose) - log_info("attempting init.lua: 'build_systems'", str_fmt(&pkg->name)); - if (!install_success && config_install(pkg)) - install_success = true; - if (!install_success) { - log_error("no install function availible for package: %.*s", - str_fmt(&pkg->name)); - return; - } - log_success("installed " GREEN "%.*s" COLOR_RESET, str_fmt(&pkg->name)); - - if (!pkg_exists(&pkg->name)) { - log_pkgit("adding " GREEN "%.*s" COLOR_RESET, str_fmt(&pkg->name)); - if (pkg->url.len > 0) { - add_repo(pkg); - log_pkgit("added " GREEN "%.*s" COLOR_RESET, str_fmt(&pkg->name)); - } - } else { - log_info("repo already exists, done"); - } -} diff --git a/src/pkg_remove.c b/src/pkg_remove.c deleted file mode 100644 index 20105c2..0000000 --- a/src/pkg_remove.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ -#define _XOPEN_SOURCE 700 - -#include <ftw.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <unistd.h> - -#include "files.h" -#include "globs.h" -#include "log.h" -#include "pkgit_lua.h" - -bool target_uninstall(lua_State *L, char *lua_file, str *target) { - if (!lua_try_table(L, lua_file, target->data)) { - lua_pop(L, 1); - return false; - } - if (!lua_try_function(L, lua_file, "uninstall")) { - lua_pop(L, 1); - return false; - } - lua_pop(L, 1); - return true; -} - -bool repo_uninstall(package_t *pkg) { - if (!config_loaded || !lua_istable(L, -1)) { - lua_isnt_type("repositories", "table"); - lua_pop(L, 1); - return false; - } - if (!lua_try_table(L, "init.lua", pkg->name.data)) { - lua_isnt_type(pkg->name.data, "table"); - lua_pop(L, 2); - return false; - } - if (!lua_try_table(L, "init.lua", "targets")) - return false; - bool target_success = target_uninstall(L, "init.lua", &pkg->target); - lua_pop(L, 3); - return target_success; -} - -bool bldit_uninstall(package_t *pkg) { - init_bldit_state(); - if (!bldit_loaded) { - lua_close(B); - return false; - } - if (!is_bldit_usable()) { - log_error("bldit version is newer than the installed pkgit version"); - log_error("consider updating pkgit"); - if (!flags.force) - return false; - } - lua_pushfstring(B, "%s", inst_dirs.prefix.data); - lua_setglobal(B, "prefix"); - if (!lua_try_table(B, "bldit.lua", "targets")) - return false; - bool target_success = target_uninstall(B, "bldit.lua", &pkg->target); - lua_pop(B, 1); - return target_success; -} - -bool config_uninstall(package_t *pkg) { - lua_getglobal(L, "build_systems"); - lua_pushnil(L); - bool target_success = false; - while (lua_next(L, -2) != 0) { - const char *key = lua_tostring(L, -2); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - continue; - } - str file_path = str_format("%.*s/%s", str_fmt(&pkg->src), key); - if (access(file_path.data, F_OK) != 0) { - lua_pop(L, 1); - str_free(&file_path); - continue; - } - str_free(&file_path); - if (!lua_try_table(L, "init.lua", "targets")) { - lua_pop(L, 2); - continue; - } - target_success = target_uninstall(L, "init.lua", &pkg->target); - lua_pop(L, 2); - if (target_success) - break; - } - lua_pop(L, 1); - return target_success; -} - -static int remove_installed(const char *src_path, const struct stat *sb, - int typeflag, struct FTW *ftwbuf) { - (void)sb; - (void)ftwbuf; - - if (typeflag == FTW_F) { - const char *filename = src_path + ftwbuf->base; - const char *ext = strrchr(filename, '.'); - if (!ext) - ext = ""; - - if (strncmp(ext, ".so", 3) == 0) { - char dest[MAX_PATH_LEN]; - snprintf(dest, sizeof(dest), "%s/%s", inst_dirs.lib.data, filename); - if (file_exists(dest)) - remove(dest); - } else if (access(src_path, X_OK) == 0) { - if (strcmp(ext, ".sample") != 0 && strcmp(filename, "bldit") != 0 && - strcmp(filename, "build.sh") != 0 && - strcmp(filename, "compile.sh") != 0) { - char dest[MAX_PATH_LEN]; - snprintf(dest, sizeof(dest), "%s/%s", inst_dirs.bin.data, - filename); - if (file_exists(dest)) - remove(dest); - } - } else if (strcmp(ext, ".h") == 0) { - char dest[MAX_PATH_LEN]; - snprintf(dest, sizeof(dest), "%s/%s", inst_dirs.include.data, - filename); - if (file_exists(dest)) - remove(dest); - } - } - return 0; -} - -void pkg_remove(package_t *pkg) { - if (!is_directory(pkg->src.data)) { - log_error("%.*s is not installed!", str_fmt(&pkg->name)); - return; - } - chdir(pkg->src.data); - - bool uninstall_available = false; - if (!uninstall_available) - if (repo_uninstall(pkg)) - uninstall_available = true; - if (!uninstall_available) - if (bldit_uninstall(pkg)) - uninstall_available = true; - if (!uninstall_available) - if (config_uninstall(pkg)) - uninstall_available = true; - - if (!uninstall_available) { - log_error("no uninstall function availible for package: %.*s", - str_fmt(&pkg->name)); - return; - } - - nftw(pkg->src.data, remove_installed, 64, FTW_PHYS); - const char *last_slash = strrchr(pkg->src.data, '/'); - char target[MAX_PATH_LEN]; - if (last_slash && last_slash != pkg->src.data) { - size_t parent_len = last_slash - pkg->src.data; - snprintf(target, sizeof(target), "%.*s", (int)parent_len, - pkg->src.data); - } else { - snprintf(target, sizeof(target), "%s", pkg->src.data); - } - remove_tree(pkg->src.data); - log_success("removed %.*s", str_fmt(&pkg->name)); -} diff --git a/src/pkg_update.c b/src/pkg_update.c deleted file mode 100644 index 3441db0..0000000 --- a/src/pkg_update.c +++ /dev/null @@ -1,174 +0,0 @@ -/* -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 <https://www.gnu.org/licenses/>. - -*/ - -#include <dirent.h> -#include <string.h> - -#include "files.h" -#include "globs.h" -#include "is_updated.h" -#include "log.h" -#include "pkgit_lua.h" - -lua_State *U = NULL; - -void init_update_state(void) { - if (U != NULL) - return; - U = luaL_newstate(); - luaL_openlibs(U); - str lua_path = str_format("%.*s/?.lua", str_fmt(&cfg.dir)); - push_lua_path(U, lua_path.data); - if (luaL_loadfile(U, cfg.name.data) || lua_pcall(U, 0, 0, 0)) { - log_error("cannot run configuration script: %s", lua_tostring(U, -1)); - log_pkgit("to generate a configuration file, head into the"); - log_pkgit( - "root directory of the pkgit source and run `make defconfig`"); - exit(EXIT_FAILURE); - } - if (file_exists(cfg.repos.data)) { - if (luaL_loadfile(U, cfg.repos.data) || lua_pcall(U, 0, 0, 0)) { - if (flags.verbose) log_warn("cannot load repository file: %s", lua_tostring(U, -1)); - lua_pop(U, 1); - } - } - str_free(&lua_path); - config_loaded = true; -} - -bool on_pkg_update(lua_State *L, package_t *pkg) { - lua_getglobal(L, "repositories"); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - return false; - } - if (!lua_try_table(L, "init.lua", pkg->name.data)) { - lua_pop(L, 2); - return false; - } - if (!lua_try_table(L, "init.lua", "targets")) { - lua_pop(L, 3); - return false; - } - if (!lua_try_table(L, "init.lua", pkg->target.data)) { - lua_pop(L, 4); - return false; - } - if (!lua_try_function(L, "init.lua", "on_update")) { - lua_pop(L, 4); - return false; - } - lua_pop(L, 4); - return true; -} - -void pkg_update(package_t *pkg) { - if (is_updated(&pkg->src)) { - if (flags.verbose) log_info( - "%.*s is already up to date.", - str_fmt(&pkg->name) - ); - return; - } - flags.force = true; - str_copy_cstr_into(&pkg->version, "HEAD"); - pkg_install(pkg); - if (!on_pkg_update(L, pkg)) log_warn( - "init.lua: 'repositories.%.*s.%.*s.on_update' function failed", - str_fmt(&pkg->name), str_fmt(&pkg->target) - ); - pkg_free(pkg); -} - -bool on_all_update(lua_State *L) { - char* fname = "on_update"; - char* lua_file = "init.lua"; - lua_getglobal(L, fname); - if (!lua_isfunction(L, -1)) { - if (flags.verbose) lua_isnt_type(fname, "function"); - lua_pop(L, 1); - } else if (lua_pcall(L, 0, 1, 0) != LUA_OK) { - if (flags.verbose) log_warn( - "%s: '%s' function borked: %s", - lua_file, fname, lua_tostring(L, -1) - ); - lua_pop(L, 1); - return false; - } - if (!lua_isnumber(L, -1) || lua_tonumber(L, -1) != 0) { - if (flags.verbose) log_warn( - "%s: '%s' failed: %s", - lua_file, fname, lua_tostring(L, -1) - ); - lua_pop(L, 1); - return false; - } - lua_pop(L, 1); - return true; -} - -void all_update(void) { - struct dirent* dirent_ptr; - DIR* dir_ptr; - if ((dir_ptr = opendir(inst_dirs.src.data)) == NULL) { - log_error("could not open %s", str_fmt(&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); - if (!on_all_update(L)) - log_warn("init.lua: 'on_update' function failed"); -} - -void declare(void) { - init_update_state(); - lua_getglobal(U, "repositories"); - if (!lua_istable(U, -1)) { - lua_isnt_type("repositories", "table"); - lua_pop(U, 1); - return; - } - lua_pushnil(U); - while (lua_next(U, -2) != 0) { - str key = mstr(lua_tostring(U, -2)); - if (!lua_istable(U, -1)) { - lua_pop(U, 1); - str_free(&key); - continue; - } - package_t pkg = pkg_create(&key); - pkg_install(&pkg); - pkg_free(&pkg); - if (str_is_valid(&key)) str_free(&key); - lua_pop(U, 1); - } - if (!on_all_update(L)) - log_warn("init.lua: 'on_update' function failed"); - lua_pop(U, 1); -} diff --git a/src/search.c b/src/search.c deleted file mode 100644 index 20d3e8c..0000000 --- a/src/search.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - - 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 <https://www.gnu.org/licenses/>. - -*/ - -#include <dirent.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> - -#include "search.h" - -#include "globs.h" -#include "log.h" -#include "pkgit_lua.h" - -void search(char *arg) { - lua_getglobal(L, "repositories"); - if (!lua_istable(L, -1)) { - lua_isnt_type("repositories", "table"); - lua_pop(L, 1); - return; - } - lua_pushnil(L); - while (lua_next(L, -2) != 0) { - str key = mstr(lua_tostring(L, -2)); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - str_free(&key); - continue; - } - if (key.len <= 1) str_println(&key); - else if (strstr(key.data, arg)) str_println(&key); - if (str_is_valid(&key)) str_free(&key); - lua_pop(L, 1); - } -} - -void list_installed(void) { - struct dirent* dirent_ptr; - DIR* dir_ptr = opendir(inst_dirs.src.data); - - if (dir_ptr == NULL) { - log_error("could not open %.*s", str_fmt(&inst_dirs.src)); - return; - } - - while ((dirent_ptr = readdir(dir_ptr)) != NULL) { - if ( - strcmp(dirent_ptr->d_name, "..") == 0 || - strcmp(dirent_ptr->d_name, ".") == 0 - ) continue; - printf("%s\n", dirent_ptr->d_name); - } -} diff --git a/include/check.h b/src/state.c index c43385b..ec05250 100644 --- a/include/check.h +++ b/src/state.c @@ -1,24 +1,27 @@ /* - + 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 <https://www.gnu.org/licenses/>. */ -#ifndef PKGIT_CHECK_H -#define PKGIT_CHECK_H -void check(void); -#endif +#include <lua.h> + +#include "state.h" + +cli_flags_t flags = {0}; +user_config_t config = {0}; +install_dirs_t inst_dirs = {0}; @@ -27,7 +27,7 @@ along with this program.If not, see <https://www.gnu.org/licenses/>. #include <stdlib.h> #include <string.h> -#include "globs.h" +#include "common.h" #include "str.h" // NOTE: only use this assertion in functions where you don't depend @@ -76,6 +76,15 @@ str mstr(const char *s) { return str_from_str_slc(_cstrslc(s)); } +str str_adopt(char *s) { + str adopted = { + .data = s, + .len = strlen(s), + }; + adopted.cap = adopted.len; + return adopted; +} + str str_from_str_slc(const str_slc s) { str res = str_new_with_capacity(s.len + 1); str_copy_str_slc_into(&res, s); @@ -207,13 +216,32 @@ void str_append_str_slc(str *src, const str_slc new) { size_t len_after_append = src->len + new.len; if (len_after_append + 1 > src->cap) { src->cap = len_after_append + 1; - str_reserve(src, src->cap); + str_reserve_exact(src, src->cap); } memcpy(src->data + src->len, new.data, new.len + 1); src->len = len_after_append; src->data[len_after_append] = 0; } +void str_append_format(str *src, const char *format, ...) { + assert_str_is_valid(dest); + + va_list args, args_copy; + va_start(args, format); + va_copy(args_copy, args); + + size_t len = vsnprintf(NULL, 0, format, args_copy); + if (src->len + len + 1 > src->cap) { + src->cap = 1 + src->len + len; + str_reserve_exact(src, src->cap); + } + + vsnprintf(src->data + src->len, len + 1, format, args); + src->len += len; + + va_end(args); +} + char str_pop_last(str *src) { char c = str_last(src); src->len--; @@ -502,7 +530,7 @@ str_slc str_slc_from_cstr(const char *s) { return _cstrslc(s); } -str_slc mstrslc(const char *s) { +str_slc mslc(const char *s) { return (str_slc){s, strlen(s)}; } |
