From c293d3cc413991e4fb18b963427a6e55afd2b5c0 Mon Sep 17 00:00:00 2001 From: Jack Jamison Date: Wed, 22 Jul 2026 11:14:54 -0400 Subject: organization and url stuff --- snag/configure | 1 - snag/ideas.txt | 5 +- snag/readme.txt | 11 +-- snag/scripts/get_pkg_attrs.sh | 2 + snag/src/main.c | 7 +- snag/src/package.h | 16 +++++ snag/src/package_db.c | 161 ++++++++++++++++++++++++++++++++++++++++++ snag/src/package_db.h | 14 ++++ snag/src/pkg_db.c | 157 ---------------------------------------- snag/src/pkg_db.h | 27 ------- snag/src/util.h | 2 +- 11 files changed, 209 insertions(+), 194 deletions(-) create mode 100644 snag/src/package.h create mode 100644 snag/src/package_db.c create mode 100644 snag/src/package_db.h delete mode 100644 snag/src/pkg_db.c delete mode 100644 snag/src/pkg_db.h (limited to 'snag') diff --git a/snag/configure b/snag/configure index 9b73f97..757df3a 100755 --- a/snag/configure +++ b/snag/configure @@ -37,7 +37,6 @@ for target in $(echo "debug release"); do write ' description = CC $out' write " command = gcc -MD -MF \$out.d \$cflags_$target -c \$in -o \$out" - files="$(find . -name '*.c')" sedstr=$(printf 's,^\./\(.*\)\.c$,%s\/%s\/\\1.o,g' ${builddir} ${target}) ofiles=$(echo "$files" | sed ${sedstr}) diff --git a/snag/ideas.txt b/snag/ideas.txt index 5bfe899..2044da6 100644 --- a/snag/ideas.txt +++ b/snag/ideas.txt @@ -1,4 +1,7 @@ - system that allows multiple different downloads for a package, each with a hash and location. it could also handle submodules somehow - sepration of (program/lib package, app package, admin package) - developer tools for creating and updating packages -- snag shell api +- selectively choose static and dynamic linking for certain libraries. +- allow a package/bin to be recompiled to be totally portable + +- easy bootstrapping and cross compilation diff --git a/snag/readme.txt b/snag/readme.txt index 33938d6..53df374 100644 --- a/snag/readme.txt +++ b/snag/readme.txt @@ -27,16 +27,16 @@ Install Database - the directory containing information on installed packag Install Description - the data stored about a package in the install database Download Database - the directory where package downloads are stored and cached +## Interesting Features +- switch between cli and tui mode mid run +- build packages that aren't in the database + ## Package Description Format Each package has a directory in the package database, named by its `id`. Inside each package directory is the description script named `{id}.sh` The description script should have functions for `configure`, `build`, and `install` The description script should define variables for attributes with the name `pkg_{attr}` -## Interesting Features -- switch between cli and tui mode mid run -- build packages that aren't in the database - Packages have the following attributes: id - the identifier name of the package. everything uses this name - the display name of package @@ -45,6 +45,9 @@ webpage - url to home website license - spdx identifer for package license (https://spdx.org/licenses/) version - software version, in whatever format is needed. commit hashes are allowed +### Snag Shell API +TBD + ## Install Description Format TBD. Will contain at least: - date installed diff --git a/snag/scripts/get_pkg_attrs.sh b/snag/scripts/get_pkg_attrs.sh index 25f9177..932c79c 100755 --- a/snag/scripts/get_pkg_attrs.sh +++ b/snag/scripts/get_pkg_attrs.sh @@ -20,3 +20,5 @@ echoatt d "$pkg_desc" echoatt w "$pkg_webpage" echoatt l "$pkg_license" echoatt v "$pkg_version" +echoatt u "$pkg_source_url" +echoatt h "$pkg_source_hash" diff --git a/snag/src/main.c b/snag/src/main.c index 0429fda..7d5ea58 100644 --- a/snag/src/main.c +++ b/snag/src/main.c @@ -2,7 +2,7 @@ #include "util.h" #include "libargs/args.h" -#include "pkg_db.h" +#include "package_db.h" int cmd_install(char* cmd_name, ArgParser* parser); @@ -37,13 +37,14 @@ int cmd_install(char* cmd_name, ArgParser* parser) { // install each package specified for (int i = 0; i < ap_count_args(parser); i++) { - if (i != 0) printf("\n"); + if (i != 0) print("\n"); // load package description char* pkgid = ap_get_arg_at_index(parser, i); package_info_t info; if (load_package_info(pkgid, &info)) { - printf("Installing %s - %s\n", info.attrs.name, info.attrs.desc); + print("Installing %s - %s\n", info.attrs.name, info.attrs.desc); + print("Downloading '%s'\n", info.attrs.source_url); run_package_install(&info); } } diff --git a/snag/src/package.h b/snag/src/package.h new file mode 100644 index 0000000..3ff58b6 --- /dev/null +++ b/snag/src/package.h @@ -0,0 +1,16 @@ +typedef struct { + char* id; + char* name; + char* desc; + char* webpage; + char* license; + char* version; + char* source_url; + char* source_hash; + char buffer[4069]; +} package_attrs_t; + +typedef struct { + char* script_path; + package_attrs_t attrs; +} package_info_t; diff --git a/snag/src/package_db.c b/snag/src/package_db.c new file mode 100644 index 0000000..0bae257 --- /dev/null +++ b/snag/src/package_db.c @@ -0,0 +1,161 @@ +#include "package_db.h" +#include "util.h" + +#include +#include +#include +#include +#include +#include + +#define PKG_INFO_CMD "./scripts/get_pkg_attrs.sh" +#define PKG_INST_CMD "./scripts/run_pkg_install.sh" + +// note: fixed location of package database for now +const char pkg_db[] = "../packages"; +const size_t pkg_db_len = sizeof(pkg_db) - 1; + +bool load_package_info(char* pkgid, package_info_t* info) { + + memset(info, 0, sizeof(*info)); + size_t pkgid_len = strlen(pkgid); + + // construct package description directory path and ensure it exists + // pkg_dir = "pkg_db/pkgid" + size_t pkg_dir_len = pkg_db_len + pkgid_len + 1; + char* pkg_dir = emalloc(pkg_dir_len + 1, "pkg_dir"); + { + memcpy(pkg_dir, pkg_db, pkg_db_len); + pkg_dir[pkg_db_len] = '/'; + memcpy(pkg_dir + pkg_db_len + 1, pkgid, pkgid_len); + pkg_dir[pkg_dir_len] = '\0'; + if (access(pkg_dir, F_OK) != 0) { + print("Package '%s' not found\n", pkgid); + free(pkg_dir); + return false; + } + } + + // construct package description script path and ensure it exists + // script_path = "pkg_dir/pkgid.sh" + size_t script_path_len = pkg_dir_len + pkgid_len + 4; + info->script_path = emalloc(script_path_len + 1, "info->script_path"); + { + memcpy(info->script_path, pkg_dir, pkg_dir_len); + info->script_path[pkg_dir_len] = '/'; + memcpy(&info->script_path[pkg_dir_len + 1], pkgid, pkgid_len); + memcpy(&info->script_path[script_path_len - 3], ".sh", 3); + info->script_path[script_path_len] = '\0'; + free(pkg_dir); + if (access(info->script_path, F_OK) != 0) { + print("Package '%s' broken, doesn't have description script\n", pkgid); + free(info->script_path); + return false; + } + } + + // PIPE and FORK to run pkg attrs script + int pipefds[2] = {0}; + if (pipe(pipefds) < 0) die("failed to pipe: %s", strerror(errno)); + pid_t pid = fork(); + if (pid < 0) die("failed to fork: %s", strerror(errno)); + + if (pid == 0) { + // child proc + // connect my stdout to the pipe + close(pipefds[0]); + dup2(pipefds[1], STDOUT_FILENO); + close(pipefds[1]); + // exec into get attr script + char* argv[] = { PKG_INFO_CMD, info->script_path, NULL }; + char* envp[] = { NULL }; + execve(PKG_INFO_CMD, argv, envp); + // what are you still doing here? + die("CHILD - execve to %s failed: %s", PKG_INFO_CMD, strerror(errno)); + } else { + // parent proc, close write end of pipe + close(pipefds[1]); + } + + // wait for child to finish + int wstatus; + if (waitpid(pid, &wstatus, 0) < 0) die("waitpid failed: %s", strerror(errno)); + if (WEXITSTATUS(wstatus) != 0) die("the child failed to execute get_pkg_attr script"); + + // read all bytes from pipe into attr buffer + ssize_t bytes_read = read(pipefds[0], info->attrs.buffer, sizeof(info->attrs.buffer)); + if (bytes_read < 0) die("failed to read from pipe: %s", strerror(errno)); + close(pipefds[0]); + + // read attributes from attr buffer + // attribute format: type (char), data value (null terminated str) + // todo(jqj): switch over to dynamically allocated buffer + for (int i = 0; i < bytes_read;) { + char atype = info->attrs.buffer[i]; + i++; + switch (atype) { + case 'i': + info->attrs.id = &info->attrs.buffer[i]; break; + case 'n': + info->attrs.name = &info->attrs.buffer[i]; break; + case 'd': + info->attrs.desc = &info->attrs.buffer[i]; break; + case 'w': + info->attrs.webpage = &info->attrs.buffer[i]; break; + case 'l': + info->attrs.license = &info->attrs.buffer[i]; break; + case 'v': + info->attrs.version = &info->attrs.buffer[i]; break; + case 'u': + info->attrs.source_url = &info->attrs.buffer[i]; break; + case 'h': + info->attrs.source_hash = &info->attrs.buffer[i]; break; + } + for(;info->attrs.buffer[i] && i < bytes_read; i++); + i++; + } + + return true; +} + +void run_package_install(const package_info_t* info) { + + // PIPE and FORK to run install script + int pipefds[2] = {0}; + if (pipe(pipefds) < 0) die("failed to pipe: %s", strerror(errno)); + pid_t pid = fork(); + if (pid < 0) die("failed to fork: %s", strerror(errno)); + + if (pid == 0) { + // child proc + // connect my stdout and stderr to the pipe + close(pipefds[0]); + dup2(pipefds[1], STDOUT_FILENO); + dup2(pipefds[1], STDERR_FILENO); + close(pipefds[1]); + // exec into install script + char* argv[] = { PKG_INST_CMD, info->script_path, NULL }; + char* envp[] = { NULL }; + execve(PKG_INST_CMD, argv, envp); + // what are you still doing here? + die("CHILD - execve to %s failed: %s", PKG_INST_CMD, strerror(errno)); + } else { + // parent proc, close write end of pipe + close(pipefds[1]); + } + + // read from the pipe until EOF + char buf[4096]; + ssize_t bytes_read = 0; + while ((bytes_read = read(pipefds[0], buf, sizeof(buf))) > 0) { + // print build out, can log and stuff in future + printf("%.*s", (int)bytes_read, buf); + } + if (bytes_read < 0) die("failed to read from pipe: %s", strerror(errno)); + close(pipefds[0]); + + // reap the child to finish + int wstatus; + if (waitpid(pid, &wstatus, 0) < 0) die("waitpid failed: %s", strerror(errno)); + if (WEXITSTATUS(wstatus) != 0) die("the child failed to execute install script"); +} diff --git a/snag/src/package_db.h b/snag/src/package_db.h new file mode 100644 index 0000000..bae1cdd --- /dev/null +++ b/snag/src/package_db.h @@ -0,0 +1,14 @@ +#ifndef PKG_DB_H +#define PKG_DB_H + +#include + +#include "package.h" + +// loads and allocates package attributes for the info struct. does not do +// excessive validation, so this should be fine when loading lots of package +// data +bool load_package_info(char* pkgid, package_info_t* info); +void run_package_install(const package_info_t* info); + +#endif diff --git a/snag/src/pkg_db.c b/snag/src/pkg_db.c deleted file mode 100644 index c35e47b..0000000 --- a/snag/src/pkg_db.c +++ /dev/null @@ -1,157 +0,0 @@ -#include "pkg_db.h" -#include "util.h" - -#include -#include -#include -#include -#include -#include - -#define PKG_INFO_CMD "./scripts/get_pkg_attrs.sh" -#define PKG_INST_CMD "./scripts/run_pkg_install.sh" - -// note: fixed location of package database for now -const char pkg_db[] = "../packages"; -const size_t pkg_db_len = sizeof(pkg_db) - 1; - -bool load_package_info(char* pkgid, package_info_t* info) { - - memset(info, 0, sizeof(*info)); - size_t pkgid_len = strlen(pkgid); - - // construct package description directory path and ensure it exists - // pkg_dir = "pkg_db/pkgid" - size_t pkg_dir_len = pkg_db_len + pkgid_len + 1; - char* pkg_dir = emalloc(pkg_dir_len + 1, "pkg_dir"); - { - memcpy(pkg_dir, pkg_db, pkg_db_len); - pkg_dir[pkg_db_len] = '/'; - memcpy(pkg_dir + pkg_db_len + 1, pkgid, pkgid_len); - pkg_dir[pkg_dir_len] = '\0'; - if (access(pkg_dir, F_OK) != 0) { - print("Package '%s' not found\n", pkgid); - free(pkg_dir); - return false; - } - } - - // construct package description script path and ensure it exists - // script_path = "pkg_dir/pkgid.sh" - size_t script_path_len = pkg_dir_len + pkgid_len + 4; - info->script_path = emalloc(script_path_len + 1, "info->script_path"); - { - memcpy(info->script_path, pkg_dir, pkg_dir_len); - info->script_path[pkg_dir_len] = '/'; - memcpy(&info->script_path[pkg_dir_len + 1], pkgid, pkgid_len); - memcpy(&info->script_path[script_path_len - 3], ".sh", 3); - info->script_path[script_path_len] = '\0'; - free(pkg_dir); - if (access(info->script_path, F_OK) != 0) { - print("Package '%s' broken, doesn't have description script\n", pkgid); - free(info->script_path); - return false; - } - } - - // PIPE and FORK to run pkg attrs script - int pipefds[2] = {0}; - if (pipe(pipefds) < 0) die("failed to pipe: %s", strerror(errno)); - pid_t pid = fork(); - if (pid < 0) die("failed to fork: %s", strerror(errno)); - - if (pid == 0) { - // child proc - // connect my stdout to the pipe - close(pipefds[0]); - dup2(pipefds[1], STDOUT_FILENO); - close(pipefds[1]); - // exec into get attr script - char* argv[] = { PKG_INFO_CMD, info->script_path, NULL }; - char* envp[] = { NULL }; - execve(PKG_INFO_CMD, argv, envp); - // what are you still doing here? - die("CHILD - execve to %s failed: %s", PKG_INFO_CMD, strerror(errno)); - } else { - // parent proc, close write end of pipe - close(pipefds[1]); - } - - // wait for child to finish - int wstatus; - if (waitpid(pid, &wstatus, 0) < 0) die("waitpid failed: %s", strerror(errno)); - if (WEXITSTATUS(wstatus) != 0) die("the child failed to execute get_pkg_attr script"); - - // read all bytes from pipe into attr buffer - ssize_t bytes_read = read(pipefds[0], info->attrs.buffer, sizeof(info->attrs.buffer)); - if (bytes_read < 0) die("failed to read from pipe: %s", strerror(errno)); - close(pipefds[0]); - - // read attributes from attr buffer - // attribute format: type (char), data value (null terminated str) - // todo(jqj): switch over to dynamically allocated buffer - for (int i = 0; i < bytes_read;) { - char atype = info->attrs.buffer[i]; - i++; - switch (atype) { - case 'i': - info->attrs.id = &info->attrs.buffer[i]; break; - case 'n': - info->attrs.name = &info->attrs.buffer[i]; break; - case 'd': - info->attrs.desc = &info->attrs.buffer[i]; break; - case 'w': - info->attrs.webpage = &info->attrs.buffer[i]; break; - case 'l': - info->attrs.license = &info->attrs.buffer[i]; break; - case 'v': - info->attrs.version = &info->attrs.buffer[i]; break; - } - for(;info->attrs.buffer[i] && i < bytes_read; i++); - i++; - } - - return true; -} - -void run_package_install(const package_info_t* info) { - - // PIPE and FORK to run install script - int pipefds[2] = {0}; - if (pipe(pipefds) < 0) die("failed to pipe: %s", strerror(errno)); - pid_t pid = fork(); - if (pid < 0) die("failed to fork: %s", strerror(errno)); - - if (pid == 0) { - // child proc - // connect my stdout and stderr to the pipe - close(pipefds[0]); - dup2(pipefds[1], STDOUT_FILENO); - dup2(pipefds[1], STDERR_FILENO); - close(pipefds[1]); - // exec into install script - char* argv[] = { PKG_INST_CMD, info->script_path, NULL }; - char* envp[] = { NULL }; - execve(PKG_INST_CMD, argv, envp); - // what are you still doing here? - die("CHILD - execve to %s failed: %s", PKG_INST_CMD, strerror(errno)); - } else { - // parent proc, close write end of pipe - close(pipefds[1]); - } - - // read from the pipe until EOF - char buf[4096]; - ssize_t bytes_read = 0; - while ((bytes_read = read(pipefds[0], buf, sizeof(buf))) > 0) { - // print build out, can log and stuff in future - printf("%.*s", (int)bytes_read, buf); - } - if (bytes_read < 0) die("failed to read from pipe: %s", strerror(errno)); - close(pipefds[0]); - - // reap the child to finish - int wstatus; - if (waitpid(pid, &wstatus, 0) < 0) die("waitpid failed: %s", strerror(errno)); - if (WEXITSTATUS(wstatus) != 0) die("the child failed to execute install script"); -} diff --git a/snag/src/pkg_db.h b/snag/src/pkg_db.h deleted file mode 100644 index 0d34a61..0000000 --- a/snag/src/pkg_db.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef PKG_DB_H -#define PKG_DB_H - -#include - -// loads and allocates package attributes for the info struct. does not do -// excessive validation, so this should be fine when loading lots of package -// data -typedef struct { - char* id; - char* name; - char* desc; - char* webpage; - char* license; - char* version; - char buffer[4069]; -} package_attrs_t; - -typedef struct { - char* script_path; - package_attrs_t attrs; -} package_info_t; - -bool load_package_info(char* pkgid, package_info_t* info); -void run_package_install(const package_info_t* info); - -#endif diff --git a/snag/src/util.h b/snag/src/util.h index 3813903..eca4e4d 100644 --- a/snag/src/util.h +++ b/snag/src/util.h @@ -25,7 +25,7 @@ #define print(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) // string functions -char* vastrcat_(int dummy, ...); #define vastrcat(...) vastrcat_(0, __VA_ARGS__, NULL) +char* vastrcat_(int dummy, ...); #endif -- cgit v1.2.3