Something went wrong. Try again.
MIRROR: javascript for 🐜's, a tiny runtime with big ambitions ant.themackabu.dev
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825#include <compat.h> // IWYU pragma: keep
#include <pkg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/stat.h>#include <dirent.h>#include <time.h>#include <argtable3.h>#include <yyjson.h>
#include "cli/pkg.h"#include "cli/version.h"
#include "utils.h"#include "progress.h"#include "modules/io.h"
// migrate this file to crprintf for colors
bool pkg_verbose = false;
static void print_bin_callback(const char *name, void *user_data);
static void progress_callback(void *user_data, pkg_phase_t phase, uint32_t current, uint32_t total, const char *message) { progress_t *progress = (progress_t *)user_data; if (!progress || !message || !message[0]) return; const char *icon; switch (phase) { case PKG_PHASE_RESOLVING: icon = "🔍"; break; case PKG_PHASE_FETCHING: icon = "🚚"; break; case PKG_PHASE_EXTRACTING: icon = "📦"; break; case PKG_PHASE_LINKING: icon = "🔗"; break; case PKG_PHASE_CACHING: icon = "💾"; break; case PKG_PHASE_POSTINSTALL: icon = "⚙️ "; break; default: icon = "📦"; break; } char msg[PROGRESS_MSG_SIZE]; if (total > 0) snprintf(msg, sizeof(msg), "%s %s [%u/%u]", icon, message, current, total); else if (current > 0) snprintf(msg, sizeof(msg), "%s %s [%u]", icon, message, current); else snprintf(msg, sizeof(msg), "%s %s", icon, message); progress_update(progress, msg);}
static void print_latest_available_hint(pkg_context_t *ctx, const char *pkg_name, const char *installed_version) { if (!ctx || !pkg_name || !installed_version || !pkg_name[0] || !installed_version[0]) return;
char latest[64]; if (pkg_get_latest_available_version(ctx, pkg_name, installed_version, latest, sizeof(latest)) <= 0) return; printf(" %s(v%s available)%s", C_BLUE, latest, C_RESET);}
static void print_added_packages(pkg_context_t *ctx) { uint32_t count = pkg_get_added_count(ctx); uint32_t printed = 0; if (count > 0) fputc('\n', stdout); for (uint32_t i = 0; i < count; i++) { pkg_added_package_t pkg; if (pkg_get_added_package(ctx, i, &pkg) == PKG_OK && pkg.direct) { printf("%s+%s %s%s%s@%s%s%s", C_GREEN, C_RESET, C_BOLD, pkg.name, C_RESET, C_DIM, pkg.version, C_RESET ); print_latest_available_hint(ctx, pkg.name, pkg.version); fputc('\n', stdout); printed++; } } if (printed > 0) fputc('\n', stdout);}
static uint64_t timespec_diff_ms(struct timespec *start, struct timespec *end) { int64_t sec = end->tv_sec - start->tv_sec; int64_t nsec = end->tv_nsec - start->tv_nsec; if (nsec < 0) { sec--; nsec += 1000000000; } return (uint64_t)sec * 1000 + (uint64_t)nsec / 1000000;}
static void print_elapsed(uint64_t elapsed_ms) { fputs(C_BOLD, stdout); if (elapsed_ms < 1000) { printf("%llums", (unsigned long long)elapsed_ms); } else printf("%.2fs", (double)elapsed_ms / 1000.0); fputs(C_RESET, stdout);}
static void print_install_header(const char *cmd) { const char *version = ant_semver(); printf("%sant %s%s v%s %s(%s)%s\n", C_BOLD, cmd, C_RESET, version, C_DIM, ANT_GIT_HASH, C_RESET );}
static void print_bin_callback(const char *name, void *user_data) { (void)user_data; printf(" %s-%s %s\n", C_DIM, C_RESET, name);}
static void prompt_with_default(const char *prompt, const char *def, char *buf, size_t buf_size) { if (def && def[0]) { printf("%s%s%s %s(%s)%s: ", C_CYAN, prompt, C_RESET, C_DIM, def, C_RESET); } else printf("%s%s%s: ", C_CYAN, prompt, C_RESET); fflush(stdout); if (fgets(buf, (int)buf_size, stdin)) { size_t len = strlen(buf); if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0'; } if (buf[0] == '\0' && def) { strncpy(buf, def, buf_size - 1); buf[buf_size - 1] = '\0'; }}
static void print_direct_installed_packages(pkg_context_t *ctx) { if (!ctx) return;
fputc('\n', stdout);
uint32_t added_count = pkg_get_added_count(ctx); for (uint32_t i = 0; i < added_count; i++) { pkg_added_package_t pkg; if (pkg_get_added_package(ctx, i, &pkg) != PKG_OK || !pkg.direct) continue;
int bin_count = pkg_list_package_bins("node_modules", pkg.name, NULL, NULL); printf("%sinstalled%s %s%s@%s%s", C_GREEN, C_RESET, C_BOLD, pkg.name, pkg.version, C_RESET); print_latest_available_hint(ctx, pkg.name, pkg.version); if (bin_count > 0) { printf(" with binaries:\n"); pkg_list_package_bins("node_modules", pkg.name, print_bin_callback, NULL); } else fputc('\n', stdout); }}
static void print_add_summary(pkg_context_t *ctx, const pkg_install_result_t *result, bool include_done_suffix) { if (!ctx || !result) return;
if (result->packages_installed > 0) { print_direct_installed_packages(ctx);
printf("\n%s%u%s package%s installed %s[%s", C_GREEN, result->packages_installed, C_RESET, result->packages_installed == 1 ? "" : "s", C_DIM, C_RESET); print_elapsed(result->elapsed_ms); printf("%s]%s", C_DIM, C_RESET); if (include_done_suffix) printf(" done"); fputc('\n', stdout); return; }
printf("\n%sChecked%s %s%u%s installs across %s%u%s packages %s(no changes)%s %s[%s", C_DIM, C_RESET, C_GREEN, result->packages_installed + result->packages_skipped, C_RESET, C_GREEN, result->package_count, C_RESET, C_DIM, C_RESET, C_DIM, C_RESET); print_elapsed(result->elapsed_ms); printf("%s]%s\n", C_DIM, C_RESET);}
typedef struct { const char *target; int count;} why_ctx_t;
static void print_why_callback(const char *name, const char *version, const char *constraint, pkg_dep_type_t dep_type, void *user_data) { why_ctx_t *ctx = (why_ctx_t *)user_data; if (strcmp(name, "package.json") == 0) { const char *type_str = dep_type.dev ? "devDependencies" : "dependencies"; printf(" %s└%s %s%s%s %s(%s)%s\n", C_DIM, C_RESET, C_GREEN, name, C_RESET, C_DIM, type_str, C_RESET); } else { const char *type_str = dep_type.peer ? "peer" : (dep_type.dev ? "dev" : (dep_type.optional ? "optional" : "")); if (type_str[0]) { printf(" %s└%s %s %s%s%s@%s%s%s %s\"%s\"%s\n", C_DIM, C_RESET, type_str, C_BOLD, name, C_RESET, C_DIM, version, C_RESET, C_CYAN, constraint, C_RESET); } else { printf(" %s└%s %s%s%s@%s%s%s %s\"%s\"%s\n", C_DIM, C_RESET, C_BOLD, name, C_RESET, C_DIM, version, C_RESET, C_CYAN, constraint, C_RESET); } } ctx->count++;}
static void print_script(const char *name, const char *command, void *ud) { (void)ud; if (strlen(command) > 50) { printf(" %-15s %.47s...\n", name, command); } else { printf(" %-15s %s\n", name, command); }}
static void print_bin_name(const char *name, void *ud) { (void)ud; printf(" %s\n", name);}
static void print_pkg_error(pkg_context_t *ctx) { const char *msg = pkg_error_string(ctx); if (!msg || !msg[0]) { fprintf(stderr, "Error: unknown error\n"); return; } if (strncmp(msg, "error:", 6) == 0) { fprintf(stderr, "%s\n", msg); } else fprintf(stderr, "Error: %s\n", msg);}
static size_t package_name_from_spec(const char *spec, char *out, size_t out_size) { if (!spec || !out || out_size == 0) return 0;
const char *split = NULL; if (spec[0] == '@') { split = strchr(spec + 1, '@'); } else split = strchr(spec, '@');
size_t len = split ? (size_t)(split - spec) : strlen(spec); if (len == 0 || len >= out_size) return 0;
memcpy(out, spec, len); out[len] = '\0'; return len;}
static bool pkg_json_has_dep(yyjson_val *root, const char *section, const char *name) { yyjson_val *deps = yyjson_obj_get(root, section); if (!deps || !yyjson_is_obj(deps)) return false; return yyjson_obj_get(deps, name) != NULL;}
static int classify_update_specs( const char *const *package_specs, int count, const char ***deps_specs_out, int *deps_count_out, const char ***dev_specs_out, int *dev_count_out) { *deps_specs_out = NULL; *deps_count_out = 0; *dev_specs_out = NULL; *dev_count_out = 0;
yyjson_read_err err; yyjson_doc *doc = yyjson_read_file("package.json", 0, NULL, &err); if (!doc) { fprintf(stderr, "Error: No package.json found\n"); return EXIT_FAILURE; }
yyjson_val *root = yyjson_doc_get_root(doc); if (!root || !yyjson_is_obj(root)) { yyjson_doc_free(doc); fprintf(stderr, "Error: Invalid package.json format\n"); return EXIT_FAILURE; }
const char **deps_specs = try_oom((size_t)count * sizeof(char *)); const char **dev_specs = try_oom((size_t)count * sizeof(char *)); if (!deps_specs || !dev_specs) { free((void *)deps_specs); free((void *)dev_specs); yyjson_doc_free(doc); fprintf(stderr, "Error: out of memory\n"); return EXIT_FAILURE; }
int deps_count = 0; int dev_count = 0; for (int i = 0; i < count; i++) { char pkg_name[512]; if (package_name_from_spec(package_specs[i], pkg_name, sizeof(pkg_name)) == 0) { free((void *)deps_specs); free((void *)dev_specs); yyjson_doc_free(doc); fprintf(stderr, "Error: Invalid package spec '%s'\n", package_specs[i]); return EXIT_FAILURE; }
bool in_deps = pkg_json_has_dep(root, "dependencies", pkg_name); bool in_dev = pkg_json_has_dep(root, "devDependencies", pkg_name); if (in_deps) deps_specs[deps_count++] = package_specs[i]; else if (in_dev) dev_specs[dev_count++] = package_specs[i]; else deps_specs[deps_count++] = package_specs[i]; }
yyjson_doc_free(doc); *deps_specs_out = deps_specs; *deps_count_out = deps_count; *dev_specs_out = dev_specs; *dev_count_out = dev_count; return EXIT_SUCCESS;}
bool pkg_script_exists(const char *package_json_path, const char *script_name) { char script_cmd[4096]; return pkg_get_script(package_json_path, script_name, script_cmd, sizeof(script_cmd)) >= 0;}
static const char *get_global_dir(void) { static char global_dir[4096] = {0}; if (global_dir[0] == '\0') ant_xdg_data_path(global_dir, sizeof(global_dir), "pkg/global"); return global_dir;}
static const char *get_global_bin_dir(void) { static char bin_dir[4096] = {0}; if (bin_dir[0] == '\0') ant_user_bin_path(bin_dir, sizeof(bin_dir)); return bin_dir;}
static const char *get_cache_dir(void) { static char cache_dir[4096] = {0}; if (cache_dir[0] == '\0') ant_xdg_cache_path(cache_dir, sizeof(cache_dir), "pkg"); return cache_dir;}
static int cmd_add_global(const char *const *package_specs, int count) { print_install_header("add -g"); char resolve_msg[64]; snprintf(resolve_msg, sizeof(resolve_msg), "🔍 Resolving [%d/%d]", count, count); progress_t progress; if (!pkg_verbose) progress_start(&progress, resolve_msg); pkg_options_t opts = { .progress_callback = pkg_verbose ? NULL : progress_callback, .user_data = pkg_verbose ? NULL : &progress, .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { if (!pkg_verbose) progress_stop(&progress); fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; }
pkg_error_t err = pkg_add_global_many(ctx, package_specs, (uint32_t)count); if (!pkg_verbose) progress_stop(&progress); if (err != PKG_OK) { print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; }
pkg_install_result_t result; if (pkg_get_install_result(ctx, &result) == PKG_OK) { for (int i = 0; i < count; i++) { printf("\n%sinstalled globally%s %s%s%s\n", C_GREEN, C_RESET, C_BOLD, package_specs[i], C_RESET); } printf(" %s(binaries linked to %s)%s\n", C_DIM, get_global_bin_dir(), C_RESET); printf("\n%s[%s", C_DIM, C_RESET); print_elapsed(result.elapsed_ms); printf("%s]%s done\n", C_DIM, C_RESET); }
pkg_free(ctx); return EXIT_SUCCESS;}
static int cmd_remove_global(const char *package_name) { print_install_header("remove -g"); progress_t progress; if (!pkg_verbose) progress_start(&progress, "🔍 Resolving"); pkg_options_t opts = { .progress_callback = pkg_verbose ? NULL : progress_callback, .user_data = pkg_verbose ? NULL : &progress, .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { if (!pkg_verbose) progress_stop(&progress); fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; }
pkg_error_t err = pkg_remove_global(ctx, package_name); if (!pkg_verbose) progress_stop(&progress); if (err == PKG_NOT_FOUND) { printf("\nPackage '%s' not found in global dependencies\n", package_name); pkg_free(ctx); return EXIT_SUCCESS; } if (err != PKG_OK) { print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; }
printf("\n%s-%s Removed globally: %s%s%s\n", C_RED, C_RESET, C_BOLD, package_name, C_RESET);
pkg_free(ctx); return EXIT_SUCCESS;}
static int cmd_install(void) { print_install_header("install"); progress_t progress; if (!pkg_verbose) { progress_start(&progress, "🔍 Resolving [1/1]"); } pkg_options_t opts = { .progress_callback = pkg_verbose ? NULL : progress_callback, .user_data = pkg_verbose ? NULL : &progress, .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; }
struct stat st; bool needs_resolve = (stat("ant.lockb", &st) != 0); if (needs_resolve) { if (stat("package.json", &st) != 0) { if (!pkg_verbose) { progress_stop(&progress); } fprintf(stderr, "Error: No package.json found\n"); pkg_free(ctx); return EXIT_FAILURE; } pkg_error_t err = pkg_resolve_and_install(ctx, "package.json", "ant.lockb", "node_modules"); if (err != PKG_OK) { if (!pkg_verbose) { progress_stop(&progress); } print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; } } else { pkg_error_t err = pkg_install(ctx, "package.json", "ant.lockb", "node_modules"); if (err != PKG_OK) { if (!pkg_verbose) { progress_stop(&progress); } print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; } } if (!pkg_verbose) { progress_stop(&progress); }
pkg_install_result_t result; if (pkg_get_install_result(ctx, &result) == PKG_OK) { if (result.packages_installed > 0) { print_added_packages(ctx); printf("%s%u%s package%s installed", C_GREEN, result.packages_installed, C_RESET, result.packages_installed == 1 ? "" : "s"); if (result.cache_hits > 0) { printf(" %s(%u cached)%s", C_DIM, result.cache_hits, C_RESET); } printf(" %s[%s", C_DIM, C_RESET); print_elapsed(result.elapsed_ms); printf("%s]%s\n", C_DIM, C_RESET); } else { printf("\n%sChecked%s %s%u%s installs across %s%u%s packages %s(no changes)%s %s[%s", C_DIM, C_RESET, C_GREEN, result.packages_installed + result.packages_skipped, C_RESET, C_GREEN, result.package_count, C_RESET, C_DIM, C_RESET, C_DIM, C_RESET); print_elapsed(result.elapsed_ms); printf("%s]%s\n", C_DIM, C_RESET); } }
if (pkg_discover_lifecycle_scripts(ctx, "node_modules") == PKG_OK) { uint32_t script_count = pkg_get_lifecycle_script_count(ctx); if (script_count > 0) { printf("\n%s%u%s package%s need%s to run lifecycle scripts:\n", C_YELLOW, script_count, C_RESET, script_count == 1 ? "" : "s", script_count == 1 ? "s" : ""); for (uint32_t i = 0; i < script_count; i++) { pkg_lifecycle_script_t script; if (pkg_get_lifecycle_script(ctx, i, &script) == PKG_OK) { printf(" %s•%s %s%s%s %s(%s)%s\n", C_DIM, C_RESET, C_CYAN, script.name, C_RESET, C_DIM, script.script, C_RESET); } } printf("\nRun: %sant trust <pkg>%s or %sant trust --all%s\n", C_DIM, C_RESET, C_DIM, C_RESET); } }
pkg_free(ctx); return EXIT_SUCCESS;}
static int cmd_update(void) { print_install_header("update"); progress_t progress; if (!pkg_verbose) { progress_start(&progress, "🔍 Resolving [1/1]"); } pkg_options_t opts = { .progress_callback = pkg_verbose ? NULL : progress_callback, .user_data = pkg_verbose ? NULL : &progress, .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; }
struct stat st; if (stat("package.json", &st) != 0) { if (!pkg_verbose) progress_stop(&progress); fprintf(stderr, "Error: No package.json found\n"); pkg_free(ctx); return EXIT_FAILURE; }
pkg_error_t err = pkg_resolve_and_install(ctx, "package.json", "ant.lockb", "node_modules"); if (err != PKG_OK) { if (!pkg_verbose) progress_stop(&progress); print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; } if (!pkg_verbose) { progress_stop(&progress); }
pkg_install_result_t result; if (pkg_get_install_result(ctx, &result) == PKG_OK) { if (result.packages_installed > 0) { print_added_packages(ctx); printf("%s%u%s package%s installed", C_GREEN, result.packages_installed, C_RESET, result.packages_installed == 1 ? "" : "s"); if (result.cache_hits > 0) { printf(" %s(%u cached)%s", C_DIM, result.cache_hits, C_RESET); } printf(" %s[%s", C_DIM, C_RESET); print_elapsed(result.elapsed_ms); printf("%s]%s\n", C_DIM, C_RESET); } else { printf("\n%sChecked%s %s%u%s installs across %s%u%s packages %s(no changes)%s %s[%s", C_DIM, C_RESET, C_GREEN, result.packages_installed + result.packages_skipped, C_RESET, C_GREEN, result.package_count, C_RESET, C_DIM, C_RESET, C_DIM, C_RESET); print_elapsed(result.elapsed_ms); printf("%s]%s\n", C_DIM, C_RESET); } }
if (pkg_discover_lifecycle_scripts(ctx, "node_modules") == PKG_OK) { uint32_t script_count = pkg_get_lifecycle_script_count(ctx); if (script_count > 0) { printf("\n%s%u%s package%s need%s to run lifecycle scripts:\n", C_YELLOW, script_count, C_RESET, script_count == 1 ? "" : "s", script_count == 1 ? "s" : ""); for (uint32_t i = 0; i < script_count; i++) { pkg_lifecycle_script_t script; if (pkg_get_lifecycle_script(ctx, i, &script) == PKG_OK) { printf(" %s•%s %s%s%s %s(%s)%s\n", C_DIM, C_RESET, C_CYAN, script.name, C_RESET, C_DIM, script.script, C_RESET); } } printf("\nRun: %sant trust <pkg>%s or %sant trust --all%s\n", C_DIM, C_RESET, C_DIM, C_RESET); } }
pkg_free(ctx); return EXIT_SUCCESS;}
static int cmd_update_many(const char *const *package_specs, int count) { print_install_header("update");
const char **deps_specs = NULL; const char **dev_specs = NULL; int deps_count = 0; int dev_count = 0; if (classify_update_specs(package_specs, count, &deps_specs, &deps_count, &dev_specs, &dev_count) != EXIT_SUCCESS) { return EXIT_FAILURE; }
char resolve_msg[64]; snprintf(resolve_msg, sizeof(resolve_msg), "🔍 Resolving [%d/%d]", count, count); progress_t progress; if (!pkg_verbose) { progress_start(&progress, resolve_msg); } pkg_options_t opts = { .progress_callback = pkg_verbose ? NULL : progress_callback, .user_data = pkg_verbose ? NULL : &progress, .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { free((void *)deps_specs); free((void *)dev_specs); if (!pkg_verbose) progress_stop(&progress); fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; }
pkg_error_t err = PKG_OK; if (deps_count > 0) { err = pkg_add_many(ctx, "package.json", deps_specs, (uint32_t)deps_count, false); } if (err == PKG_OK && dev_count > 0) { err = pkg_add_many(ctx, "package.json", dev_specs, (uint32_t)dev_count, true); } free((void *)deps_specs); free((void *)dev_specs);
if (err != PKG_OK) { if (!pkg_verbose) progress_stop(&progress); print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; }
err = pkg_resolve_and_install(ctx, "package.json", "ant.lockb", "node_modules"); if (err != PKG_OK) { if (!pkg_verbose) progress_stop(&progress); print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; } if (!pkg_verbose) progress_stop(&progress);
pkg_install_result_t result; if (pkg_get_install_result(ctx, &result) == PKG_OK) { print_add_summary(ctx, &result, true); }
pkg_free(ctx); return EXIT_SUCCESS;}
static int cmd_add(const char *const *package_specs, int count, bool dev) { print_install_header(dev ? "add -D" : "add"); char resolve_msg[64]; snprintf(resolve_msg, sizeof(resolve_msg), "🔍 Resolving [%d/%d]", count, count); progress_t progress; if (!pkg_verbose) { progress_start(&progress, resolve_msg); } pkg_options_t opts = { .progress_callback = pkg_verbose ? NULL : progress_callback, .user_data = pkg_verbose ? NULL : &progress, .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; }
pkg_error_t err = pkg_add_many(ctx, "package.json", package_specs, (uint32_t)count, dev); if (err != PKG_OK) { if (!pkg_verbose) { progress_stop(&progress); } print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; }
err = pkg_resolve_and_install(ctx, "package.json", "ant.lockb", "node_modules"); if (err != PKG_OK) { if (!pkg_verbose) { progress_stop(&progress); } print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; } if (!pkg_verbose) progress_stop(&progress);
pkg_install_result_t result; if (pkg_get_install_result(ctx, &result) == PKG_OK) { print_add_summary(ctx, &result, false); }
pkg_free(ctx); return EXIT_SUCCESS;}
static int cmd_remove(const char *package_name) { print_install_header("remove"); progress_t progress; if (!pkg_verbose) { progress_start(&progress, "🔍 Resolving"); } pkg_options_t opts = { .progress_callback = pkg_verbose ? NULL : progress_callback, .user_data = pkg_verbose ? NULL : &progress, .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; }
pkg_error_t err = pkg_remove(ctx, "package.json", package_name); if (err != PKG_OK && err != PKG_NOT_FOUND) { if (!pkg_verbose) { progress_stop(&progress); } print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; } if (err == PKG_NOT_FOUND) { if (!pkg_verbose) { progress_stop(&progress); } printf("\n%s[%s", C_DIM, C_RESET); printf("%s0ms%s", C_BOLD, C_RESET); printf("%s]%s done\n", C_DIM, C_RESET); pkg_free(ctx); return EXIT_SUCCESS; }
err = pkg_resolve_and_install(ctx, "package.json", "ant.lockb", "node_modules"); if (err != PKG_OK) { if (!pkg_verbose) { progress_stop(&progress); } print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; }
if (!pkg_verbose) { progress_stop(&progress); }
pkg_install_result_t result; if (pkg_get_install_result(ctx, &result) == PKG_OK) { printf("\n%s%u%s package%s installed %s[%s", C_GREEN, result.packages_installed, C_RESET, result.packages_installed == 1 ? "" : "s", C_DIM, C_RESET); print_elapsed(result.elapsed_ms); printf("%s]%s\n", C_DIM, C_RESET); } printf("%s-%s Removed: %s%s%s\n", C_RED, C_RESET, C_BOLD, package_name, C_RESET); pkg_free(ctx);
return EXIT_SUCCESS;}
static int cmd_trust(const char **pkgs, int count, bool all) { print_install_header("trust"); struct timespec start_time; clock_gettime(CLOCK_MONOTONIC, &start_time); pkg_options_t opts = { .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; }
if (pkg_discover_lifecycle_scripts(ctx, "node_modules") != PKG_OK) { fprintf(stderr, "Error: Failed to scan node_modules\n"); pkg_free(ctx); return EXIT_FAILURE; }
uint32_t script_count = pkg_get_lifecycle_script_count(ctx); if (script_count == 0) { printf("No packages need lifecycle scripts to run.\n"); pkg_free(ctx); return EXIT_SUCCESS; }
const char **to_run = NULL; uint32_t to_run_count = 0;
if (all) { to_run = try_oom(script_count * sizeof(char *)); if (to_run) { for (uint32_t i = 0; i < script_count; i++) { pkg_lifecycle_script_t script; if (pkg_get_lifecycle_script(ctx, i, &script) == PKG_OK) { to_run[to_run_count++] = script.name; } } } } else if (count > 0) { to_run = try_oom(count * sizeof(char *)); if (to_run) { for (int i = 0; i < count; i++) { bool found = false; for (uint32_t j = 0; j < script_count; j++) { pkg_lifecycle_script_t script; if (pkg_get_lifecycle_script(ctx, j, &script) == PKG_OK) { if (strcmp(pkgs[i], script.name) == 0) { to_run[to_run_count++] = script.name; found = true; break; } } } if (!found) fprintf(stderr, "Warning: %s has no pending lifecycle script\n", pkgs[i]); } } } else { printf("%s%u%s package%s with lifecycle scripts:\n", C_YELLOW, script_count, C_RESET, script_count == 1 ? "" : "s"); for (uint32_t i = 0; i < script_count; i++) { pkg_lifecycle_script_t script; if (pkg_get_lifecycle_script(ctx, i, &script) == PKG_OK) { printf(" %s•%s %s%s%s %s(%s)%s\n", C_DIM, C_RESET, C_CYAN, script.name, C_RESET, C_DIM, script.script, C_RESET); } } printf("\nRun: %sant trust <pkg>%s or %sant trust --all%s\n", C_DIM, C_RESET, C_DIM, C_RESET); pkg_free(ctx); return EXIT_SUCCESS; }
if (to_run && to_run_count > 0) { if (pkg_verbose) { printf("[trust] adding %u packages to trustedDependencies\n", to_run_count); for (uint32_t i = 0; i < to_run_count; i++) { printf("[trust] %s\n", to_run[i]); } } pkg_error_t add_err = pkg_add_trusted_dependencies("package.json", to_run, to_run_count); if (add_err == PKG_OK) { printf("Added %s%u%s package%s to %strustedDependencies%s in package.json\n", C_GREEN, to_run_count, C_RESET, to_run_count == 1 ? "" : "s", C_BOLD, C_RESET); } else { if (pkg_verbose) printf("[trust] failed to add trustedDependencies: error %d\n", add_err); } printf("Running lifecycle scripts for %s%u%s package%s...\n", C_GREEN, to_run_count, C_RESET, to_run_count == 1 ? "" : "s"); pkg_run_postinstall(ctx, "node_modules", to_run, to_run_count); struct timespec end_time; clock_gettime(CLOCK_MONOTONIC, &end_time); uint64_t elapsed_ms = timespec_diff_ms(&start_time, &end_time); printf("\n%s%u%s package%s trusted %s[%s", C_GREEN, to_run_count, C_RESET, to_run_count == 1 ? "" : "s", C_DIM, C_RESET); print_elapsed(elapsed_ms); printf("%s]%s\n", C_DIM, C_RESET); free((void *)to_run); }
pkg_free(ctx); return EXIT_SUCCESS;}
static int cmd_init(void) { FILE *fp = fopen("package.json", "r"); if (fp) { fclose(fp); fprintf(stderr, "Error: package.json already exists\n"); return EXIT_FAILURE; }
char cwd[PATH_MAX]; const char *default_name = "my-project"; if (getcwd(cwd, sizeof(cwd))) { char *base = strrchr(cwd, '/'); if (base && base[1]) default_name = base + 1; }
bool interactive = isatty(fileno(stdin)); char name[256] = {0}; char version[64] = {0}; char entry[256] = {0}; if (interactive) { printf("%sant init%s\n\n", C_BOLD, C_RESET); prompt_with_default("package name", default_name, name, sizeof(name)); prompt_with_default("version", "1.0.0", version, sizeof(version)); prompt_with_default("entry point", "index.js", entry, sizeof(entry)); fputc('\n', stdout); } else { strncpy(name, default_name, sizeof(name) - 1); strncpy(version, "1.0.0", sizeof(version) - 1); strncpy(entry, "index.js", sizeof(entry) - 1); }
fp = fopen("package.json", "w"); if (!fp) { fprintf(stderr, "Error: Could not create package.json\n"); return EXIT_FAILURE; }
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); yyjson_mut_val *root = yyjson_mut_obj(doc); yyjson_mut_doc_set_root(doc, root); yyjson_mut_obj_add_str(doc, root, "name", name); yyjson_mut_obj_add_str(doc, root, "version", version); yyjson_mut_obj_add_str(doc, root, "type", "module"); yyjson_mut_obj_add_str(doc, root, "main", entry); yyjson_mut_val *scripts = yyjson_mut_obj_add_obj(doc, root, "scripts"); char start_cmd[300]; snprintf(start_cmd, sizeof(start_cmd), "ant %s", entry); yyjson_mut_obj_add_str(doc, scripts, "start", start_cmd); yyjson_mut_obj_add_obj(doc, root, "dependencies"); yyjson_mut_obj_add_obj(doc, root, "devDependencies"); size_t len; char *json_str = yyjson_mut_write( doc, YYJSON_WRITE_PRETTY_TWO_SPACES | YYJSON_WRITE_ESCAPE_UNICODE, &len ); if (json_str) { fwrite(json_str, 1, len, fp); free(json_str); } yyjson_mut_doc_free(doc); fclose(fp); printf("%s+%s Created %spackage.json%s\n", C_GREEN, C_RESET, C_BOLD, C_RESET); return EXIT_SUCCESS;}
static int cmd_why(const char *package_name) { struct stat st; if (stat("ant.lockb", &st) != 0) { fprintf(stderr, "Error: No lockfile found. Run 'ant install' first.\n"); return EXIT_FAILURE; } pkg_why_info_t info; if (pkg_why_info("ant.lockb", package_name, &info) < 0) { fprintf(stderr, "Error: Failed to read lockfile\n"); return EXIT_FAILURE; } if (!info.found) { printf("\n%s%s%s is not installed\n\n", C_BOLD, package_name, C_RESET); return EXIT_SUCCESS; } const char *type_label = info.is_peer ? " peer" : (info.is_dev ? " dev" : ""); printf("\n%s%s%s@%s%s%s%s%s%s\n", C_BOLD, package_name, C_RESET, C_DIM, info.target_version, C_RESET, C_YELLOW, type_label, C_RESET); why_ctx_t ctx = { .target = package_name, .count = 0 }; int result = pkg_why("ant.lockb", package_name, print_why_callback, &ctx); if (result < 0) { fprintf(stderr, "Error: Failed to read lockfile\n"); return EXIT_FAILURE; } if (ctx.count == 0) { printf(" %s(no dependents)%s\n", C_DIM, C_RESET); } fputc('\n', stdout); return EXIT_SUCCESS;}
int pkg_cmd_init(int argc, char **argv) { struct arg_lit *help = arg_lit0("h", "help", "display help"); struct arg_end *end = arg_end(5); void *argtable[] = { help, end }; int nerrors = arg_parse(argc, argv, argtable); int exitcode = EXIT_SUCCESS; if (help->count > 0) { printf("Usage: ant init\n\n"); printf("Create a new package.json\n"); } else if (nerrors > 0) { arg_print_errors(stdout, end, "ant init"); exitcode = EXIT_FAILURE; } else { exitcode = cmd_init(); } arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); return exitcode;}
int pkg_cmd_install(int argc, char **argv) { struct arg_str *pkgs = arg_strn(NULL, NULL, "<package[@version]>", 0, 100, NULL); struct arg_lit *global = arg_lit0("g", "global", "install globally"); struct arg_lit *dev = arg_lit0("D", "save-dev", "add as devDependency"); struct arg_lit *help = arg_lit0("h", "help", "display help"); struct arg_end *end = arg_end(5); void *argtable[] = { pkgs, global, dev, help, end }; int nerrors = arg_parse(argc, argv, argtable); int exitcode = EXIT_SUCCESS; if (help->count > 0) { printf("Usage: ant install [packages...] [-g] [-D] [--verbose]\n\n"); printf("Install from lockfile, or add packages if specified.\n"); printf("\nOptions:\n -g, --global Install globally to %s\n", get_global_dir()); printf(" -D, --save-dev Add as devDependency\n"); } else if (nerrors > 0) { arg_print_errors(stdout, end, "ant install"); exitcode = EXIT_FAILURE; } else if (pkgs->count == 0) { exitcode = cmd_install(); } else { bool is_dev = dev->count > 0; exitcode = global->count > 0 ? cmd_add_global(pkgs->sval, pkgs->count) : cmd_add(pkgs->sval, pkgs->count, is_dev); } arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); return exitcode;}
int pkg_cmd_update(int argc, char **argv) { struct arg_str *pkgs = arg_strn(NULL, NULL, "<package[@version]>", 0, 100, NULL); struct arg_lit *help = arg_lit0("h", "help", "display help"); struct arg_end *end = arg_end(5); void *argtable[] = { pkgs, help, end }; int nerrors = arg_parse(argc, argv, argtable); int exitcode = EXIT_SUCCESS; if (help->count > 0) { printf("Usage: ant update [packages...] [--verbose]\n\n"); printf("Re-resolve all dependencies, or upgrade specific packages in place.\n"); } else if (nerrors > 0) { arg_print_errors(stdout, end, "ant update"); exitcode = EXIT_FAILURE; } else { exitcode = pkgs->count > 0 ? cmd_update_many(pkgs->sval, pkgs->count) : cmd_update(); } arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); return exitcode;}
int pkg_cmd_add(int argc, char **argv) { struct arg_str *pkgs = arg_strn(NULL, NULL, "<package[@version]>", 1, 100, NULL); struct arg_lit *global = arg_lit0("g", "global", "install globally"); struct arg_lit *dev = arg_lit0("D", "save-dev", "add as devDependency"); struct arg_lit *help = arg_lit0("h", "help", "display help"); struct arg_end *end = arg_end(5); void *argtable[] = { pkgs, global, dev, help, end }; int nerrors = arg_parse(argc, argv, argtable); int exitcode = EXIT_SUCCESS; if (help->count > 0) { printf("Usage: ant add <package[@version]>... [options]\n\n"); printf("Add packages to dependencies.\n"); printf("\nOptions:\n -g, --global Install globally to %s\n", get_global_dir()); printf(" -D, --save-dev Add as devDependency\n"); } else if (nerrors > 0) { arg_print_errors(stdout, end, "ant add"); exitcode = EXIT_FAILURE; } else { bool is_dev = dev->count > 0; exitcode = global->count > 0 ? cmd_add_global(pkgs->sval, pkgs->count) : cmd_add(pkgs->sval, pkgs->count, is_dev); } arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); return exitcode;}
int pkg_cmd_remove(int argc, char **argv) { struct arg_str *pkgs = arg_strn(NULL, NULL, "<package>", 1, 100, NULL); struct arg_lit *global = arg_lit0("g", "global", "remove from global packages"); struct arg_lit *help = arg_lit0("h", "help", "display help"); struct arg_end *end = arg_end(5); void *argtable[] = { pkgs, global, help, end }; int nerrors = arg_parse(argc, argv, argtable); int exitcode = EXIT_SUCCESS; if (help->count > 0) { printf("Usage: ant remove <package>... [-g]\n\n"); printf("Remove packages from dependencies.\n"); printf("\nOptions:\n -g, --global Remove from global packages\n"); } else if (nerrors > 0) { arg_print_errors(stdout, end, "ant remove"); exitcode = EXIT_FAILURE; } else { for (int i = 0; i < pkgs->count && exitcode == EXIT_SUCCESS; i++) { exitcode = global->count > 0 ? cmd_remove_global(pkgs->sval[i]) : cmd_remove(pkgs->sval[i]); } } arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); return exitcode;}
int pkg_cmd_trust(int argc, char **argv) { struct arg_str *pkgs = arg_strn(NULL, NULL, "<package>", 0, 100, NULL); struct arg_lit *all = arg_lit0("a", "all", "trust all packages with lifecycle scripts"); struct arg_lit *help = arg_lit0("h", "help", "display help"); struct arg_end *end = arg_end(5); void *argtable[] = { pkgs, all, help, end }; int nerrors = arg_parse(argc, argv, argtable); int exitcode = EXIT_SUCCESS; if (help->count > 0) { printf("Usage: ant trust [packages...] [--all]\n\n"); printf("Run lifecycle scripts for packages.\n"); printf(" --all, -a Trust and run all pending lifecycle scripts\n"); } else if (nerrors > 0) { arg_print_errors(stdout, end, "ant trust"); exitcode = EXIT_FAILURE; } else { exitcode = cmd_trust(pkgs->sval, pkgs->count, all->count > 0); } arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); return exitcode;}
int pkg_cmd_run(int argc, char **argv) { if (argc < 2) { printf("Usage: ant run <script> [args...]\n\n"); printf("Run a script from package.json\n\n"); printf("Available scripts:\n"); int count = pkg_list_scripts("package.json", NULL, NULL); if (count < 0) { printf(" (no package.json found)\n"); } else if (count == 0) { printf(" (no scripts defined)\n"); } else { pkg_list_scripts("package.json", print_script, NULL); } return EXIT_SUCCESS; } const char *script_name = argv[1]; char script_cmd[4096]; int script_len = pkg_get_script("package.json", script_name, script_cmd, sizeof(script_cmd)); if (script_len < 0) { fprintf(stderr, "Error: script '%s' not found in package.json\n", script_name); fprintf(stderr, "Try 'ant run' to list available scripts.\n"); return EXIT_FAILURE; } char extra_args[4096] = {0}; int extra_args_len = 0; int arg_start = 2; if (arg_start < argc && strcmp(argv[arg_start], "--") == 0) arg_start++;
for (int i = arg_start; i < argc; i++) { if (extra_args_len > 0) extra_args[extra_args_len++] = ' '; size_t arg_len = strlen(argv[i]); if ((size_t)extra_args_len + arg_len < sizeof(extra_args) - 1) { memcpy(extra_args + extra_args_len, argv[i], arg_len); extra_args_len += (int)arg_len; } } extra_args[extra_args_len] = '\0'; printf("%s$%s %s%s%s", C_MAGENTA, C_RESET, C_BOLD, script_cmd, C_RESET); if (extra_args_len > 0) printf(" %s", extra_args); fputc('\n', stdout); pkg_script_result_t result = {0}; pkg_error_t err = pkg_run_script( "package.json", script_name, "node_modules", extra_args_len > 0 ? extra_args : NULL, &result ); if (err != PKG_OK) { if (err == PKG_NOT_FOUND) { fprintf(stderr, "Error: script '%s' not found\n", script_name); } else { fprintf(stderr, "Error: failed to run script '%s'\n", script_name); } return EXIT_FAILURE; } if (result.signal != 0) { fprintf(stderr, "Script '%s' killed by signal %d\n", script_name, result.signal); return 128 + result.signal; } return result.exit_code;}
int pkg_cmd_exec(int argc, char **argv) { if (argc < 2) { printf("Usage: ant x [--ant] <command> [args...]\n\n"); printf("Run a command from node_modules/.bin or download temporarily\n\n"); printf("Options:\n"); printf(" --ant Run with ant instead of node\n\n"); printf("Available commands:\n");
int count = pkg_list_bins("node_modules", NULL, NULL); if (count < 0) printf(" (no binaries found - run 'ant install' first)\n"); else if (count == 0) printf(" (no binaries installed)\n"); else pkg_list_bins("node_modules", print_bin_name, NULL); return EXIT_SUCCESS; }
bool use_ant = false; int cmd_idx = 1;
if (strcmp(argv[1], "--ant") == 0) { use_ant = true; cmd_idx = 2; if (argc < 3) { fprintf(stderr, "Error: missing command after --ant\n"); return EXIT_FAILURE; } }
const char *cmd_name = argv[cmd_idx]; char bin_path[4096]; int path_len = pkg_get_bin_path("node_modules", cmd_name, bin_path, sizeof(bin_path));
if (path_len < 0) { const char *global_dir = get_global_dir(); if (global_dir[0]) { char global_nm[4096]; snprintf(global_nm, sizeof(global_nm), "%s/node_modules", global_dir); path_len = pkg_get_bin_path(global_nm, cmd_name, bin_path, sizeof(bin_path)); } }
if (path_len < 0) { progress_t progress; bool show_progress = !pkg_verbose;
if (show_progress) { char msg[256]; snprintf(msg, sizeof(msg), "🔍 Resolving %s", cmd_name); progress_start(&progress, msg); }
pkg_options_t opts = { .progress_callback = show_progress ? progress_callback : NULL, .user_data = show_progress ? &progress : NULL, .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { if (show_progress) progress_stop(&progress); fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; }
pkg_error_t err = pkg_exec_temp(ctx, cmd_name, bin_path, sizeof(bin_path)); if (show_progress) progress_stop(&progress);
if (err != PKG_OK) { const char *err_msg = pkg_error_string(ctx); if (err_msg && err_msg[0]) { fprintf(stderr, "Error: %s\n", err_msg); } else { fprintf(stderr, "Error: '%s' not found\n", cmd_name); } pkg_free(ctx); return EXIT_FAILURE; } pkg_free(ctx); }
int arg_offset = cmd_idx + 1; int extra = use_ant ? 2 : 1; int new_argc = argc - arg_offset + extra; char **exec_argv = try_oom(sizeof(char*) * (new_argc + 1)); if (!exec_argv) { fprintf(stderr, "Error: out of memory\n"); return EXIT_FAILURE; }
int idx = 0; if (use_ant) exec_argv[idx++] = (char *)"ant"; exec_argv[idx++] = bin_path; for (int i = arg_offset; i < argc; i++) exec_argv[idx++] = argv[i]; exec_argv[idx] = NULL;
const char *cmd = use_ant ? "ant" : bin_path; execvp(cmd, exec_argv); free(exec_argv);
if (use_ant) fprintf(stderr, "Error: failed to execute 'ant %s' - is ant installed?\n", bin_path); else fprintf(stderr, "Error: failed to execute '%s'\n", bin_path);
return EXIT_FAILURE;}
int pkg_cmd_why(int argc, char **argv) { struct arg_str *pkg = arg_str1(NULL, NULL, "<package>", "package name to query"); struct arg_lit *help = arg_lit0("h", "help", "display help"); struct arg_end *end = arg_end(5); void *argtable[] = { pkg, help, end }; int nerrors = arg_parse(argc, argv, argtable); int exitcode = EXIT_SUCCESS; if (help->count > 0) { printf("Usage: ant why <package>\n\n"); printf("Show which packages depend on the given package.\n"); } else if (nerrors > 0) { arg_print_errors(stdout, end, "ant why"); exitcode = EXIT_FAILURE; } else { exitcode = cmd_why(pkg->sval[0]); } arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); return exitcode;}
static const char *format_size(uint64_t bytes, char *buf, size_t buf_size) { if (bytes >= 1024ULL * 1024 * 1024) snprintf(buf, buf_size, "%.2f GB", (double)bytes / (1024.0 * 1024.0 * 1024.0)); else if (bytes >= 1024 * 1024) snprintf(buf, buf_size, "%.2f MB", (double)bytes / (1024.0 * 1024.0)); else if (bytes >= 1024) snprintf(buf, buf_size, "%.2f KB", (double)bytes / 1024.0); else snprintf(buf, buf_size, "%llu B", (unsigned long long)bytes); return buf;}
static int cmd_info(const char *package_spec) { pkg_options_t opts = { .verbose = false }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; }
pkg_info_t info; pkg_error_t err = pkg_info(ctx, package_spec, &info); if (err != PKG_OK) { print_pkg_error(ctx); pkg_free(ctx); return EXIT_FAILURE; }
char size_buf[32]; printf("%s%s%s%s@%s%s%s%s%s", C_BLUE, C_UL, info.name, C_UL_OFF, C_BLUE, C_BOLD, C_UL, info.version, C_RESET); if (info.license[0]) printf(" | %s%s%s", C_CYAN, info.license, C_RESET); printf(" | deps: %u | versions: %u\n", info.dep_count, info.version_count); if (info.description[0]) printf("%s\n", info.description); if (info.homepage[0]) printf("%s%s%s\n", C_BLUE, info.homepage, C_RESET); if (info.keywords[0]) printf("keywords: %s\n", info.keywords); uint32_t dep_count = pkg_info_dependency_count(ctx); if (dep_count > 0) { printf("\n%sdependencies%s (%u):\n", C_BOLD, C_RESET, dep_count); for (uint32_t i = 0; i < dep_count; i++) { pkg_dependency_t dep; if (pkg_info_get_dependency(ctx, i, &dep) == PKG_OK) { printf("- %s%s%s: %s\n", C_CYAN, dep.name, C_RESET, dep.version); } } } printf("\n%sdist%s\n", C_BOLD, C_RESET); if (info.tarball[0]) printf(" %s.tarball:%s %s\n", C_DIM, C_RESET, info.tarball); if (info.shasum[0]) printf(" %s.shasum:%s %s%s%s\n", C_DIM, C_RESET, C_GREEN, info.shasum, C_RESET); if (info.integrity[0]) printf(" %s.integrity:%s %s%s%s\n", C_DIM, C_RESET, C_GREEN, info.integrity, C_RESET); if (info.unpacked_size > 0) printf(" %s.unpackedSize:%s %s%s%s\n", C_DIM, C_RESET, C_BLUE, format_size(info.unpacked_size, size_buf, sizeof(size_buf)), C_RESET); uint32_t tag_count = pkg_info_dist_tag_count(ctx); if (tag_count > 0) { printf("\n%sdist-tags:%s\n", C_BOLD, C_RESET); for (uint32_t i = 0; i < tag_count; i++) { pkg_dist_tag_t tag; if (pkg_info_get_dist_tag(ctx, i, &tag) == PKG_OK) { const char *tag_color = C_MAGENTA; if (strcmp(tag.tag, "beta") == 0) tag_color = C_BLUE; else if (strcmp(tag.tag, "latest") == 0) tag_color = C_CYAN; printf("%s%s%s: %s\n", tag_color, tag.tag, C_RESET, tag.version); } } } uint32_t maint_count = pkg_info_maintainer_count(ctx); if (maint_count > 0) { printf("\n%smaintainers:%s\n", C_BOLD, C_RESET); for (uint32_t i = 0; i < maint_count; i++) { pkg_maintainer_t maint; if (pkg_info_get_maintainer(ctx, i, &maint) == PKG_OK) { printf("- %s", maint.name); if (maint.email[0]) printf(" <%s>", maint.email); fputc('\n', stdout); } } } if (info.published[0]) printf("\n%sPublished:%s %s\n", C_BOLD, C_RESET, info.published); pkg_free(ctx); return EXIT_SUCCESS;}
int pkg_cmd_info(int argc, char **argv) { struct arg_str *pkg = arg_str1(NULL, NULL, "<package[@version]>", "package to look up"); struct arg_lit *help = arg_lit0("h", "help", "display help"); struct arg_end *end = arg_end(5); void *argtable[] = { pkg, help, end }; int nerrors = arg_parse(argc, argv, argtable); int exitcode = EXIT_SUCCESS; if (help->count > 0) { printf("Usage: ant info <package[@version]>\n\n"); printf("Show package information from the npm registry.\n"); } else if (nerrors > 0) { arg_print_errors(stdout, end, "ant info"); exitcode = EXIT_FAILURE; } else { exitcode = cmd_info(pkg->sval[0]); } arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); return exitcode;}
typedef struct { int count; bool show_path; const char *nm_path;} ls_ctx_t;
static void print_ls_package(const char *name, void *user_data) { ls_ctx_t *ctx = (ls_ctx_t *)user_data; char pkg_json_path[4096]; snprintf(pkg_json_path, sizeof(pkg_json_path), "%s/%s/package.json", ctx->nm_path, name); FILE *f = fopen(pkg_json_path, "r"); if (!f) { printf(" %s%s%s\n", C_BOLD, name, C_RESET); ctx->count++; return; } char buf[8192]; size_t len = fread(buf, 1, sizeof(buf) - 1, f); fclose(f); buf[len] = '\0'; const char *version = "?"; char version_buf[64] = {0}; char *ver_key = strstr(buf, "\"version\""); if (ver_key) { char *colon = strchr(ver_key, ':'); if (colon) { char *quote1 = strchr(colon, '"'); if (quote1) { char *quote2 = strchr(quote1 + 1, '"'); if (quote2) { size_t vlen = (size_t)(quote2 - quote1 - 1); if (vlen < sizeof(version_buf)) { memcpy(version_buf, quote1 + 1, vlen); version_buf[vlen] = '\0'; version = version_buf; } } } } } printf(" %s%s%s@%s%s%s\n", C_BOLD, name, C_RESET, C_DIM, version, C_RESET); ctx->count++;}
typedef struct { int count; int total;} pkg_ls_ctx_t;
static void print_pkg_cb(const char *name, const char *version, void *user_data) { pkg_ls_ctx_t *ctx = (pkg_ls_ctx_t *)user_data; ctx->count++; const char *prefix = (ctx->count == ctx->total) ? "└──" : "├──"; printf("%s%s%s %s%s%s@%s\n", C_DIM, prefix, C_RESET, C_BOLD, name, C_RESET, version);}
static int cmd_ls(bool is_global) { pkg_options_t opts = { .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; } char path_buf[PATH_MAX]; const char *base_path; const char *nm_path; char nm_full_path[PATH_MAX]; if (is_global) { base_path = get_global_dir(); snprintf(nm_full_path, sizeof(nm_full_path), "%s/node_modules", base_path); nm_path = nm_full_path; } else { if (!getcwd(path_buf, sizeof(path_buf))) { fprintf(stderr, "Error: Could not get current directory\n"); pkg_free(ctx); return EXIT_FAILURE; } base_path = path_buf; nm_path = "node_modules"; } uint32_t direct = is_global ? pkg_count_global(ctx) : pkg_count_local(ctx); uint32_t total = pkg_count_installed(nm_path); printf("%s%s/node_modules%s", C_DIM, base_path, C_RESET); if (direct == 0) { printf("\n (no package.json)\n"); pkg_free(ctx); return EXIT_SUCCESS; } if (total == 0) { printf("\n (empty)\n"); pkg_free(ctx); return EXIT_SUCCESS; } printf(" %s(%u)%s\n", C_DIM, total, C_RESET); pkg_ls_ctx_t ls_ctx = { .count = 0, .total = (int)direct }; if (is_global) pkg_list_global(ctx, print_pkg_cb, &ls_ctx); else pkg_list_local(ctx, print_pkg_cb, &ls_ctx); pkg_free(ctx); return EXIT_SUCCESS;}
int pkg_cmd_ls(int argc, char **argv) { struct arg_lit *global = arg_lit0("g", "global", "list global packages"); struct arg_lit *help = arg_lit0("h", "help", "display help"); struct arg_end *end = arg_end(5); void *argtable[] = { global, help, end }; int nerrors = arg_parse(argc, argv, argtable); int exitcode = EXIT_SUCCESS; if (help->count > 0) { printf("Usage: ant ls [-g]\n\n"); printf("List installed packages.\n"); printf("\nOptions:\n -g, --global List global packages\n"); } else if (nerrors > 0) { arg_print_errors(stdout, end, "ant ls"); exitcode = EXIT_FAILURE; } else exitcode = cmd_ls(global->count > 0); arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); return exitcode;}
static int cmd_cache_info(void) { pkg_options_t opts = { .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; } pkg_cache_stats_t stats; pkg_error_t err = pkg_cache_stats(ctx, &stats); if (err != PKG_OK) { fprintf(stderr, "Error: Failed to get cache stats\n"); pkg_free(ctx); return EXIT_FAILURE; } char size_buf[64], db_buf[64]; printf("%sCache location:%s %s\n", C_BOLD, C_RESET, get_cache_dir()); printf("%sPackages:%s %u\n", C_BOLD, C_RESET, stats.package_count); printf("%sSize:%s %s\n", C_BOLD, C_RESET, format_size(stats.total_size, size_buf, sizeof(size_buf))); printf("%sDB size:%s %s\n", C_BOLD, C_RESET, format_size(stats.db_size, db_buf, sizeof(db_buf))); pkg_free(ctx); return EXIT_SUCCESS;}
static int cmd_cache_prune(uint32_t max_age_days) { pkg_options_t opts = { .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; } int32_t pruned = pkg_cache_prune(ctx, max_age_days); if (pruned < 0) { fprintf(stderr, "Error: Failed to prune cache\n"); pkg_free(ctx); return EXIT_FAILURE; } if (pruned == 0) { printf("No packages to prune (all packages newer than %u days)\n", max_age_days); } else { printf("%sPruned%s %d package%s older than %u days\n", C_GREEN, C_RESET, pruned, pruned == 1 ? "" : "s", max_age_days); } pkg_free(ctx); return EXIT_SUCCESS;}
static int cmd_cache_sync(void) { pkg_options_t opts = { .verbose = pkg_verbose }; pkg_context_t *ctx = pkg_init(&opts); if (!ctx) { fprintf(stderr, "Error: Failed to initialize package manager\n"); return EXIT_FAILURE; } pkg_cache_sync(ctx); printf("%sCache synced%s\n", C_GREEN, C_RESET); pkg_free(ctx); return EXIT_SUCCESS;}
int pkg_cmd_cache(int argc, char **argv) { if (argc < 2) { printf("Usage: ant cache <command>\n\n"); printf("Manage the package cache.\n\n"); printf("Commands:\n"); printf(" info Show cache statistics\n"); printf(" prune [days] Remove packages older than N days (default: 30)\n"); printf(" sync Sync cache to disk\n"); return EXIT_SUCCESS; } const char *subcmd = argv[1]; if (strcmp(subcmd, "info") == 0) { return cmd_cache_info(); } else if (strcmp(subcmd, "prune") == 0) { uint32_t days = 30; if (argc >= 3) { days = (uint32_t)atoi(argv[2]); if (days == 0) days = 30; } return cmd_cache_prune(days); } else if (strcmp(subcmd, "sync") == 0) { return cmd_cache_sync(); } else { fprintf(stderr, "Unknown cache command: %s\n", subcmd); fprintf(stderr, "Run 'ant cache' for usage.\n"); return EXIT_FAILURE; }}
int pkg_cmd_create(int argc, char **argv) { if (argc < 2) { printf("Usage: ant create <template> [dest] [...flags]\n"); printf(" ant create <github-org/repo> [dest] [...flags]\n\n"); printf("Scaffold a new project from a template.\n\n"); printf("Templates:\n"); printf(" NPM: Runs 'ant x create-<template>' with given arguments\n"); printf(" GitHub: Clones repository contents as template\n\n"); printf("Environment variables:\n"); printf(" GITHUB_TOKEN Supply a token for private repos or higher rate limits\n"); return EXIT_SUCCESS; }
const char *template = argv[1]; bool is_github = (strchr(template, '/') != NULL);
if (is_github) { const char *dest = NULL; for (int i = 2; i < argc; i++) { if (argv[i][0] != '-') { dest = argv[i]; break; } }
if (!dest) { const char *slash = strrchr(template, '/'); dest = slash ? slash + 1 : template; }
struct stat st; if (stat(dest, &st) == 0) { fprintf(stderr, "Error: directory '%s' already exists\n", dest); return EXIT_FAILURE; }
char url[1024]; if (strncmp(template, "https://", 8) == 0 || strncmp(template, "git@", 4) == 0) { snprintf(url, sizeof(url), "%s", template); } else snprintf(url, sizeof(url), "https://github.com/%s.git", template);
printf("%s+%s Creating project from %s%s%s...\n", C_GREEN, C_RESET, C_BOLD, template, C_RESET);
char cmd[2048]; snprintf(cmd, sizeof(cmd), "git clone --depth 1 %s %s", url, dest); int ret = system(cmd); if (ret != 0) { fprintf(stderr, "Error: failed to clone %s\n", url); return EXIT_FAILURE; }
char git_dir[1024]; snprintf(git_dir, sizeof(git_dir), "%s/.git", dest); char rm_cmd[1024]; snprintf(rm_cmd, sizeof(rm_cmd), "rm -rf %s", git_dir); system(rm_cmd);
if (stat(dest, &st) == 0) { char pkg_json[1024]; snprintf(pkg_json, sizeof(pkg_json), "%s/package.json", dest); if (stat(pkg_json, &st) == 0) { printf("\n%sDone!%s Created %s%s%s\n", C_GREEN, C_RESET, C_BOLD, dest, C_RESET); printf("\n cd %s\n ant install\n\n", dest); } else printf("\n%sDone!%s Created %s%s%s\n", C_GREEN, C_RESET, C_BOLD, dest, C_RESET); }
return EXIT_SUCCESS; }
char create_pkg[512]; snprintf(create_pkg, sizeof(create_pkg), "create-%s", template);
int new_argc = argc; char **new_argv = malloc(sizeof(char*) * (new_argc + 1)); if (!new_argv) { fprintf(stderr, "Error: out of memory\n"); return EXIT_FAILURE; }
new_argv[0] = argv[0]; new_argv[1] = create_pkg; for (int i = 2; i < argc; i++) new_argv[i] = argv[i]; new_argv[new_argc] = NULL;
int ret = pkg_cmd_exec(new_argc, new_argv); free(new_argv); return ret;}