MIRROR: javascript for 🐜's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 1824 lines 57 kB view raw
1#include <compat.h> // IWYU pragma: keep 2 3#include <pkg.h> 4#include <stdio.h> 5#include <stdlib.h> 6#include <string.h> 7#include <unistd.h> 8#include <sys/stat.h> 9#include <dirent.h> 10#include <time.h> 11#include <argtable3.h> 12#include <yyjson.h> 13 14#include "cli/pkg.h" 15#include "cli/version.h" 16 17#include "utils.h" 18#include "progress.h" 19#include "modules/io.h" 20 21// migrate this file to crprintf for colors 22 23bool pkg_verbose = false; 24 25static void print_bin_callback(const char *name, void *user_data); 26 27static void progress_callback(void *user_data, pkg_phase_t phase, uint32_t current, uint32_t total, const char *message) { 28 progress_t *progress = (progress_t *)user_data; 29 if (!progress || !message || !message[0]) return; 30 31 const char *icon; 32 switch (phase) { 33 case PKG_PHASE_RESOLVING: icon = "🔍"; break; 34 case PKG_PHASE_FETCHING: icon = "🚚"; break; 35 case PKG_PHASE_EXTRACTING: icon = "📦"; break; 36 case PKG_PHASE_LINKING: icon = "🔗"; break; 37 case PKG_PHASE_CACHING: icon = "💾"; break; 38 case PKG_PHASE_POSTINSTALL: icon = "⚙️ "; break; 39 default: icon = "📦"; break; 40 } 41 42 char msg[PROGRESS_MSG_SIZE]; 43 if (total > 0) snprintf(msg, sizeof(msg), "%s %s [%u/%u]", icon, message, current, total); 44 else if (current > 0) snprintf(msg, sizeof(msg), "%s %s [%u]", icon, message, current); 45 else snprintf(msg, sizeof(msg), "%s %s", icon, message); 46 47 progress_update(progress, msg); 48} 49 50static void print_latest_available_hint(pkg_context_t *ctx, const char *pkg_name, const char *installed_version) { 51 if (!ctx || !pkg_name || !installed_version || !pkg_name[0] || !installed_version[0]) return; 52 53 char latest[64]; 54 if (pkg_get_latest_available_version(ctx, pkg_name, installed_version, latest, sizeof(latest)) <= 0) return; 55 printf(" %s(v%s available)%s", C_BLUE, latest, C_RESET); 56} 57 58static void print_added_packages(pkg_context_t *ctx) { 59 uint32_t count = pkg_get_added_count(ctx); 60 uint32_t printed = 0; 61 if (count > 0) fputc('\n', stdout); 62 63 for (uint32_t i = 0; i < count; i++) { 64 pkg_added_package_t pkg; 65 if (pkg_get_added_package(ctx, i, &pkg) == PKG_OK && pkg.direct) { 66 printf("%s+%s %s%s%s@%s%s%s", 67 C_GREEN, C_RESET, 68 C_BOLD, pkg.name, C_RESET, 69 C_DIM, pkg.version, C_RESET 70 ); 71 print_latest_available_hint(ctx, pkg.name, pkg.version); 72 fputc('\n', stdout); printed++; 73 } 74 } 75 76 if (printed > 0) fputc('\n', stdout); 77} 78 79static uint64_t timespec_diff_ms(struct timespec *start, struct timespec *end) { 80 int64_t sec = end->tv_sec - start->tv_sec; 81 int64_t nsec = end->tv_nsec - start->tv_nsec; 82 if (nsec < 0) { sec--; nsec += 1000000000; } 83 return (uint64_t)sec * 1000 + (uint64_t)nsec / 1000000; 84} 85 86static void print_elapsed(uint64_t elapsed_ms) { 87 fputs(C_BOLD, stdout); 88 if (elapsed_ms < 1000) { 89 printf("%llums", (unsigned long long)elapsed_ms); 90 } else printf("%.2fs", (double)elapsed_ms / 1000.0); 91 fputs(C_RESET, stdout); 92} 93 94static void print_install_header(const char *cmd) { 95 const char *version = ant_semver(); 96 97 printf("%sant %s%s v%s %s(%s)%s\n", 98 C_BOLD, cmd, C_RESET, version, 99 C_DIM, ANT_GIT_HASH, C_RESET 100 ); 101} 102 103static void print_bin_callback(const char *name, void *user_data) { 104 (void)user_data; 105 printf(" %s-%s %s\n", C_DIM, C_RESET, name); 106} 107 108static void prompt_with_default(const char *prompt, const char *def, char *buf, size_t buf_size) { 109 if (def && def[0]) { 110 printf("%s%s%s %s(%s)%s: ", C_CYAN, prompt, C_RESET, C_DIM, def, C_RESET); 111 } else printf("%s%s%s: ", C_CYAN, prompt, C_RESET); 112 fflush(stdout); 113 114 if (fgets(buf, (int)buf_size, stdin)) { 115 size_t len = strlen(buf); 116 if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0'; 117 } 118 119 if (buf[0] == '\0' && def) { 120 strncpy(buf, def, buf_size - 1); 121 buf[buf_size - 1] = '\0'; 122 } 123} 124 125static void print_direct_installed_packages(pkg_context_t *ctx) { 126 if (!ctx) return; 127 128 fputc('\n', stdout); 129 130 uint32_t added_count = pkg_get_added_count(ctx); 131 for (uint32_t i = 0; i < added_count; i++) { 132 pkg_added_package_t pkg; 133 if (pkg_get_added_package(ctx, i, &pkg) != PKG_OK || !pkg.direct) continue; 134 135 int bin_count = pkg_list_package_bins("node_modules", pkg.name, NULL, NULL); 136 printf("%sinstalled%s %s%s@%s%s", 137 C_GREEN, C_RESET, 138 C_BOLD, pkg.name, pkg.version, C_RESET); 139 print_latest_available_hint(ctx, pkg.name, pkg.version); 140 if (bin_count > 0) { 141 printf(" with binaries:\n"); 142 pkg_list_package_bins("node_modules", pkg.name, print_bin_callback, NULL); 143 } else fputc('\n', stdout); 144 } 145} 146 147static void print_add_summary(pkg_context_t *ctx, const pkg_install_result_t *result, bool include_done_suffix) { 148 if (!ctx || !result) return; 149 150 if (result->packages_installed > 0) { 151 print_direct_installed_packages(ctx); 152 153 printf("\n%s%u%s package%s installed %s[%s", 154 C_GREEN, result->packages_installed, C_RESET, 155 result->packages_installed == 1 ? "" : "s", 156 C_DIM, C_RESET); 157 print_elapsed(result->elapsed_ms); 158 printf("%s]%s", C_DIM, C_RESET); 159 if (include_done_suffix) printf(" done"); 160 161 fputc('\n', stdout); 162 return; 163 } 164 165 printf("\n%sChecked%s %s%u%s installs across %s%u%s packages %s(no changes)%s %s[%s", 166 C_DIM, C_RESET, 167 C_GREEN, result->packages_installed + result->packages_skipped, C_RESET, 168 C_GREEN, result->package_count, C_RESET, 169 C_DIM, C_RESET, 170 C_DIM, C_RESET); 171 print_elapsed(result->elapsed_ms); 172 printf("%s]%s\n", C_DIM, C_RESET); 173} 174 175typedef struct { 176 const char *target; 177 int count; 178} why_ctx_t; 179 180static void print_why_callback(const char *name, const char *version, const char *constraint, pkg_dep_type_t dep_type, void *user_data) { 181 why_ctx_t *ctx = (why_ctx_t *)user_data; 182 183 if (strcmp(name, "package.json") == 0) { 184 const char *type_str = dep_type.dev ? "devDependencies" : "dependencies"; 185 printf(" %s└%s %s%s%s %s(%s)%s\n", 186 C_DIM, C_RESET, 187 C_GREEN, name, C_RESET, 188 C_DIM, type_str, C_RESET); 189 } else { 190 const char *type_str = dep_type.peer ? "peer" : (dep_type.dev ? "dev" : (dep_type.optional ? "optional" : "")); 191 if (type_str[0]) { 192 printf(" %s└%s %s %s%s%s@%s%s%s %s\"%s\"%s\n", 193 C_DIM, C_RESET, 194 type_str, 195 C_BOLD, name, C_RESET, 196 C_DIM, version, C_RESET, 197 C_CYAN, constraint, C_RESET); 198 } else { 199 printf(" %s└%s %s%s%s@%s%s%s %s\"%s\"%s\n", 200 C_DIM, C_RESET, 201 C_BOLD, name, C_RESET, 202 C_DIM, version, C_RESET, 203 C_CYAN, constraint, C_RESET); 204 } 205 } 206 207 ctx->count++; 208} 209 210static void print_script(const char *name, const char *command, void *ud) { 211 (void)ud; 212 if (strlen(command) > 50) { 213 printf(" %-15s %.47s...\n", name, command); 214 } else { 215 printf(" %-15s %s\n", name, command); 216 } 217} 218 219static void print_bin_name(const char *name, void *ud) { 220 (void)ud; 221 printf(" %s\n", name); 222} 223 224static void print_pkg_error(pkg_context_t *ctx) { 225 const char *msg = pkg_error_string(ctx); 226 if (!msg || !msg[0]) { 227 fprintf(stderr, "Error: unknown error\n"); 228 return; 229 } 230 if (strncmp(msg, "error:", 6) == 0) { 231 fprintf(stderr, "%s\n", msg); 232 } else fprintf(stderr, "Error: %s\n", msg); 233} 234 235static size_t package_name_from_spec(const char *spec, char *out, size_t out_size) { 236 if (!spec || !out || out_size == 0) return 0; 237 238 const char *split = NULL; 239 if (spec[0] == '@') { 240 split = strchr(spec + 1, '@'); 241 } else split = strchr(spec, '@'); 242 243 size_t len = split ? (size_t)(split - spec) : strlen(spec); 244 if (len == 0 || len >= out_size) return 0; 245 246 memcpy(out, spec, len); 247 out[len] = '\0'; 248 return len; 249} 250 251static bool pkg_json_has_dep(yyjson_val *root, const char *section, const char *name) { 252 yyjson_val *deps = yyjson_obj_get(root, section); 253 if (!deps || !yyjson_is_obj(deps)) return false; 254 return yyjson_obj_get(deps, name) != NULL; 255} 256 257static int classify_update_specs( 258 const char *const *package_specs, 259 int count, 260 const char ***deps_specs_out, 261 int *deps_count_out, 262 const char ***dev_specs_out, 263 int *dev_count_out 264) { 265 *deps_specs_out = NULL; 266 *deps_count_out = 0; 267 *dev_specs_out = NULL; 268 *dev_count_out = 0; 269 270 yyjson_read_err err; 271 yyjson_doc *doc = yyjson_read_file("package.json", 0, NULL, &err); 272 if (!doc) { 273 fprintf(stderr, "Error: No package.json found\n"); 274 return EXIT_FAILURE; 275 } 276 277 yyjson_val *root = yyjson_doc_get_root(doc); 278 if (!root || !yyjson_is_obj(root)) { 279 yyjson_doc_free(doc); 280 fprintf(stderr, "Error: Invalid package.json format\n"); 281 return EXIT_FAILURE; 282 } 283 284 const char **deps_specs = try_oom((size_t)count * sizeof(char *)); 285 const char **dev_specs = try_oom((size_t)count * sizeof(char *)); 286 if (!deps_specs || !dev_specs) { 287 free((void *)deps_specs); 288 free((void *)dev_specs); 289 yyjson_doc_free(doc); 290 fprintf(stderr, "Error: out of memory\n"); 291 return EXIT_FAILURE; 292 } 293 294 int deps_count = 0; 295 int dev_count = 0; 296 for (int i = 0; i < count; i++) { 297 char pkg_name[512]; 298 if (package_name_from_spec(package_specs[i], pkg_name, sizeof(pkg_name)) == 0) { 299 free((void *)deps_specs); 300 free((void *)dev_specs); 301 yyjson_doc_free(doc); 302 fprintf(stderr, "Error: Invalid package spec '%s'\n", package_specs[i]); 303 return EXIT_FAILURE; 304 } 305 306 bool in_deps = pkg_json_has_dep(root, "dependencies", pkg_name); 307 bool in_dev = pkg_json_has_dep(root, "devDependencies", pkg_name); 308 if (in_deps) deps_specs[deps_count++] = package_specs[i]; 309 else if (in_dev) dev_specs[dev_count++] = package_specs[i]; 310 else deps_specs[deps_count++] = package_specs[i]; 311 } 312 313 yyjson_doc_free(doc); 314 *deps_specs_out = deps_specs; 315 *deps_count_out = deps_count; 316 *dev_specs_out = dev_specs; 317 *dev_count_out = dev_count; 318 return EXIT_SUCCESS; 319} 320 321bool pkg_script_exists(const char *package_json_path, const char *script_name) { 322 char script_cmd[4096]; 323 return pkg_get_script(package_json_path, script_name, script_cmd, sizeof(script_cmd)) >= 0; 324} 325 326static const char *get_global_dir(void) { 327 static char global_dir[4096] = {0}; 328 if (global_dir[0] == '\0') ant_xdg_data_path(global_dir, sizeof(global_dir), "pkg/global"); 329 return global_dir; 330} 331 332static const char *get_global_bin_dir(void) { 333 static char bin_dir[4096] = {0}; 334 if (bin_dir[0] == '\0') ant_user_bin_path(bin_dir, sizeof(bin_dir)); 335 return bin_dir; 336} 337 338static const char *get_cache_dir(void) { 339 static char cache_dir[4096] = {0}; 340 if (cache_dir[0] == '\0') ant_xdg_cache_path(cache_dir, sizeof(cache_dir), "pkg"); 341 return cache_dir; 342} 343 344static int cmd_add_global(const char *const *package_specs, int count) { 345 print_install_header("add -g"); 346 347 char resolve_msg[64]; 348 snprintf(resolve_msg, sizeof(resolve_msg), "🔍 Resolving [%d/%d]", count, count); 349 350 progress_t progress; 351 if (!pkg_verbose) progress_start(&progress, resolve_msg); 352 353 pkg_options_t opts = { 354 .progress_callback = pkg_verbose ? NULL : progress_callback, 355 .user_data = pkg_verbose ? NULL : &progress, 356 .verbose = pkg_verbose 357 }; 358 pkg_context_t *ctx = pkg_init(&opts); 359 if (!ctx) { 360 if (!pkg_verbose) progress_stop(&progress); 361 fprintf(stderr, "Error: Failed to initialize package manager\n"); 362 return EXIT_FAILURE; 363 } 364 365 pkg_error_t err = pkg_add_global_many(ctx, package_specs, (uint32_t)count); 366 if (!pkg_verbose) progress_stop(&progress); 367 368 if (err != PKG_OK) { 369 print_pkg_error(ctx); 370 pkg_free(ctx); 371 return EXIT_FAILURE; 372 } 373 374 pkg_install_result_t result; 375 if (pkg_get_install_result(ctx, &result) == PKG_OK) { 376 for (int i = 0; i < count; i++) { 377 printf("\n%sinstalled globally%s %s%s%s\n", 378 C_GREEN, C_RESET, C_BOLD, package_specs[i], C_RESET); 379 } 380 printf(" %s(binaries linked to %s)%s\n", C_DIM, get_global_bin_dir(), C_RESET); 381 printf("\n%s[%s", C_DIM, C_RESET); 382 print_elapsed(result.elapsed_ms); 383 printf("%s]%s done\n", C_DIM, C_RESET); 384 } 385 386 pkg_free(ctx); 387 return EXIT_SUCCESS; 388} 389 390static int cmd_remove_global(const char *package_name) { 391 print_install_header("remove -g"); 392 393 progress_t progress; 394 if (!pkg_verbose) progress_start(&progress, "🔍 Resolving"); 395 396 pkg_options_t opts = { 397 .progress_callback = pkg_verbose ? NULL : progress_callback, 398 .user_data = pkg_verbose ? NULL : &progress, 399 .verbose = pkg_verbose 400 }; 401 pkg_context_t *ctx = pkg_init(&opts); 402 if (!ctx) { 403 if (!pkg_verbose) progress_stop(&progress); 404 fprintf(stderr, "Error: Failed to initialize package manager\n"); 405 return EXIT_FAILURE; 406 } 407 408 pkg_error_t err = pkg_remove_global(ctx, package_name); 409 if (!pkg_verbose) progress_stop(&progress); 410 411 if (err == PKG_NOT_FOUND) { 412 printf("\nPackage '%s' not found in global dependencies\n", package_name); 413 pkg_free(ctx); 414 return EXIT_SUCCESS; 415 } 416 417 if (err != PKG_OK) { 418 print_pkg_error(ctx); 419 pkg_free(ctx); 420 return EXIT_FAILURE; 421 } 422 423 printf("\n%s-%s Removed globally: %s%s%s\n", C_RED, C_RESET, C_BOLD, package_name, C_RESET); 424 425 pkg_free(ctx); 426 return EXIT_SUCCESS; 427} 428 429static int cmd_install(void) { 430 print_install_header("install"); 431 432 progress_t progress; 433 434 if (!pkg_verbose) { 435 progress_start(&progress, "🔍 Resolving [1/1]"); 436 } 437 438 pkg_options_t opts = { 439 .progress_callback = pkg_verbose ? NULL : progress_callback, 440 .user_data = pkg_verbose ? NULL : &progress, 441 .verbose = pkg_verbose 442 }; 443 pkg_context_t *ctx = pkg_init(&opts); 444 if (!ctx) { 445 fprintf(stderr, "Error: Failed to initialize package manager\n"); 446 return EXIT_FAILURE; 447 } 448 449 struct stat st; 450 bool needs_resolve = (stat("ant.lockb", &st) != 0); 451 452 if (needs_resolve) { 453 if (stat("package.json", &st) != 0) { 454 if (!pkg_verbose) { progress_stop(&progress); } 455 fprintf(stderr, "Error: No package.json found\n"); 456 pkg_free(ctx); 457 return EXIT_FAILURE; 458 } 459 460 pkg_error_t err = pkg_resolve_and_install(ctx, "package.json", "ant.lockb", "node_modules"); 461 if (err != PKG_OK) { 462 if (!pkg_verbose) { progress_stop(&progress); } 463 print_pkg_error(ctx); 464 pkg_free(ctx); 465 return EXIT_FAILURE; 466 } 467 } else { 468 pkg_error_t err = pkg_install(ctx, "package.json", "ant.lockb", "node_modules"); 469 if (err != PKG_OK) { 470 if (!pkg_verbose) { progress_stop(&progress); } 471 print_pkg_error(ctx); 472 pkg_free(ctx); 473 return EXIT_FAILURE; 474 } 475 } 476 477 if (!pkg_verbose) { 478 progress_stop(&progress); 479 480 } 481 482 pkg_install_result_t result; 483 if (pkg_get_install_result(ctx, &result) == PKG_OK) { 484 if (result.packages_installed > 0) { 485 print_added_packages(ctx); 486 printf("%s%u%s package%s installed", 487 C_GREEN, result.packages_installed, C_RESET, 488 result.packages_installed == 1 ? "" : "s"); 489 if (result.cache_hits > 0) { 490 printf(" %s(%u cached)%s", C_DIM, result.cache_hits, C_RESET); 491 } 492 printf(" %s[%s", C_DIM, C_RESET); 493 print_elapsed(result.elapsed_ms); 494 printf("%s]%s\n", C_DIM, C_RESET); 495 } else { 496 printf("\n%sChecked%s %s%u%s installs across %s%u%s packages %s(no changes)%s %s[%s", 497 C_DIM, C_RESET, 498 C_GREEN, result.packages_installed + result.packages_skipped, C_RESET, 499 C_GREEN, result.package_count, C_RESET, 500 C_DIM, C_RESET, 501 C_DIM, C_RESET); 502 print_elapsed(result.elapsed_ms); 503 printf("%s]%s\n", C_DIM, C_RESET); 504 } 505 } 506 507 if (pkg_discover_lifecycle_scripts(ctx, "node_modules") == PKG_OK) { 508 uint32_t script_count = pkg_get_lifecycle_script_count(ctx); 509 if (script_count > 0) { 510 printf("\n%s%u%s package%s need%s to run lifecycle scripts:\n", 511 C_YELLOW, script_count, C_RESET, 512 script_count == 1 ? "" : "s", 513 script_count == 1 ? "s" : ""); 514 515 for (uint32_t i = 0; i < script_count; i++) { 516 pkg_lifecycle_script_t script; 517 if (pkg_get_lifecycle_script(ctx, i, &script) == PKG_OK) { 518 printf(" %s•%s %s%s%s %s(%s)%s\n", 519 C_DIM, C_RESET, 520 C_CYAN, script.name, C_RESET, 521 C_DIM, script.script, C_RESET); 522 } 523 } 524 525 printf("\nRun: %sant trust <pkg>%s or %sant trust --all%s\n", C_DIM, C_RESET, C_DIM, C_RESET); 526 } 527 } 528 529 pkg_free(ctx); 530 return EXIT_SUCCESS; 531} 532 533static int cmd_update(void) { 534 print_install_header("update"); 535 536 progress_t progress; 537 538 if (!pkg_verbose) { 539 progress_start(&progress, "🔍 Resolving [1/1]"); 540 } 541 542 pkg_options_t opts = { 543 .progress_callback = pkg_verbose ? NULL : progress_callback, 544 .user_data = pkg_verbose ? NULL : &progress, 545 .verbose = pkg_verbose 546 }; 547 pkg_context_t *ctx = pkg_init(&opts); 548 if (!ctx) { 549 fprintf(stderr, "Error: Failed to initialize package manager\n"); 550 return EXIT_FAILURE; 551 } 552 553 struct stat st; 554 if (stat("package.json", &st) != 0) { 555 if (!pkg_verbose) progress_stop(&progress); 556 fprintf(stderr, "Error: No package.json found\n"); 557 pkg_free(ctx); 558 return EXIT_FAILURE; 559 } 560 561 pkg_error_t err = pkg_resolve_and_install(ctx, "package.json", "ant.lockb", "node_modules"); 562 if (err != PKG_OK) { 563 if (!pkg_verbose) progress_stop(&progress); 564 print_pkg_error(ctx); 565 pkg_free(ctx); 566 return EXIT_FAILURE; 567 } 568 569 if (!pkg_verbose) { 570 progress_stop(&progress); 571 } 572 573 pkg_install_result_t result; 574 if (pkg_get_install_result(ctx, &result) == PKG_OK) { 575 if (result.packages_installed > 0) { 576 print_added_packages(ctx); 577 printf("%s%u%s package%s installed", 578 C_GREEN, result.packages_installed, C_RESET, 579 result.packages_installed == 1 ? "" : "s"); 580 if (result.cache_hits > 0) { 581 printf(" %s(%u cached)%s", C_DIM, result.cache_hits, C_RESET); 582 } 583 printf(" %s[%s", C_DIM, C_RESET); 584 print_elapsed(result.elapsed_ms); 585 printf("%s]%s\n", C_DIM, C_RESET); 586 } else { 587 printf("\n%sChecked%s %s%u%s installs across %s%u%s packages %s(no changes)%s %s[%s", 588 C_DIM, C_RESET, 589 C_GREEN, result.packages_installed + result.packages_skipped, C_RESET, 590 C_GREEN, result.package_count, C_RESET, 591 C_DIM, C_RESET, 592 C_DIM, C_RESET); 593 print_elapsed(result.elapsed_ms); 594 printf("%s]%s\n", C_DIM, C_RESET); 595 } 596 } 597 598 if (pkg_discover_lifecycle_scripts(ctx, "node_modules") == PKG_OK) { 599 uint32_t script_count = pkg_get_lifecycle_script_count(ctx); 600 if (script_count > 0) { 601 printf("\n%s%u%s package%s need%s to run lifecycle scripts:\n", 602 C_YELLOW, script_count, C_RESET, 603 script_count == 1 ? "" : "s", 604 script_count == 1 ? "s" : ""); 605 606 for (uint32_t i = 0; i < script_count; i++) { 607 pkg_lifecycle_script_t script; 608 if (pkg_get_lifecycle_script(ctx, i, &script) == PKG_OK) { 609 printf(" %s•%s %s%s%s %s(%s)%s\n", 610 C_DIM, C_RESET, 611 C_CYAN, script.name, C_RESET, 612 C_DIM, script.script, C_RESET); 613 } 614 } 615 616 printf("\nRun: %sant trust <pkg>%s or %sant trust --all%s\n", C_DIM, C_RESET, C_DIM, C_RESET); 617 } 618 } 619 620 pkg_free(ctx); 621 return EXIT_SUCCESS; 622} 623 624static int cmd_update_many(const char *const *package_specs, int count) { 625 print_install_header("update"); 626 627 const char **deps_specs = NULL; 628 const char **dev_specs = NULL; 629 int deps_count = 0; 630 int dev_count = 0; 631 if (classify_update_specs(package_specs, count, &deps_specs, &deps_count, &dev_specs, &dev_count) != EXIT_SUCCESS) { 632 return EXIT_FAILURE; 633 } 634 635 char resolve_msg[64]; 636 snprintf(resolve_msg, sizeof(resolve_msg), "🔍 Resolving [%d/%d]", count, count); 637 638 progress_t progress; 639 if (!pkg_verbose) { 640 progress_start(&progress, resolve_msg); 641 } 642 643 pkg_options_t opts = { 644 .progress_callback = pkg_verbose ? NULL : progress_callback, 645 .user_data = pkg_verbose ? NULL : &progress, 646 .verbose = pkg_verbose 647 }; 648 pkg_context_t *ctx = pkg_init(&opts); 649 if (!ctx) { 650 free((void *)deps_specs); 651 free((void *)dev_specs); 652 if (!pkg_verbose) progress_stop(&progress); 653 fprintf(stderr, "Error: Failed to initialize package manager\n"); 654 return EXIT_FAILURE; 655 } 656 657 pkg_error_t err = PKG_OK; 658 if (deps_count > 0) { 659 err = pkg_add_many(ctx, "package.json", deps_specs, (uint32_t)deps_count, false); 660 } 661 if (err == PKG_OK && dev_count > 0) { 662 err = pkg_add_many(ctx, "package.json", dev_specs, (uint32_t)dev_count, true); 663 } 664 free((void *)deps_specs); 665 free((void *)dev_specs); 666 667 if (err != PKG_OK) { 668 if (!pkg_verbose) progress_stop(&progress); 669 print_pkg_error(ctx); 670 pkg_free(ctx); 671 return EXIT_FAILURE; 672 } 673 674 err = pkg_resolve_and_install(ctx, "package.json", "ant.lockb", "node_modules"); 675 if (err != PKG_OK) { 676 if (!pkg_verbose) progress_stop(&progress); 677 print_pkg_error(ctx); 678 pkg_free(ctx); 679 return EXIT_FAILURE; 680 } 681 682 if (!pkg_verbose) progress_stop(&progress); 683 684 pkg_install_result_t result; 685 if (pkg_get_install_result(ctx, &result) == PKG_OK) { 686 print_add_summary(ctx, &result, true); 687 } 688 689 pkg_free(ctx); 690 return EXIT_SUCCESS; 691} 692 693static int cmd_add(const char *const *package_specs, int count, bool dev) { 694 print_install_header(dev ? "add -D" : "add"); 695 696 char resolve_msg[64]; 697 snprintf(resolve_msg, sizeof(resolve_msg), "🔍 Resolving [%d/%d]", count, count); 698 699 progress_t progress; 700 if (!pkg_verbose) { 701 progress_start(&progress, resolve_msg); 702 } 703 704 pkg_options_t opts = { 705 .progress_callback = pkg_verbose ? NULL : progress_callback, 706 .user_data = pkg_verbose ? NULL : &progress, 707 .verbose = pkg_verbose 708 }; 709 pkg_context_t *ctx = pkg_init(&opts); 710 if (!ctx) { 711 fprintf(stderr, "Error: Failed to initialize package manager\n"); 712 return EXIT_FAILURE; 713 } 714 715 pkg_error_t err = pkg_add_many(ctx, "package.json", package_specs, (uint32_t)count, dev); 716 if (err != PKG_OK) { 717 if (!pkg_verbose) { progress_stop(&progress); } 718 print_pkg_error(ctx); 719 pkg_free(ctx); 720 return EXIT_FAILURE; 721 } 722 723 err = pkg_resolve_and_install(ctx, "package.json", "ant.lockb", "node_modules"); 724 if (err != PKG_OK) { 725 if (!pkg_verbose) { progress_stop(&progress); } 726 print_pkg_error(ctx); 727 pkg_free(ctx); 728 return EXIT_FAILURE; 729 } 730 731 if (!pkg_verbose) progress_stop(&progress); 732 733 pkg_install_result_t result; 734 if (pkg_get_install_result(ctx, &result) == PKG_OK) { 735 print_add_summary(ctx, &result, false); 736 } 737 738 pkg_free(ctx); 739 return EXIT_SUCCESS; 740} 741 742static int cmd_remove(const char *package_name) { 743 print_install_header("remove"); 744 progress_t progress; 745 746 if (!pkg_verbose) { 747 progress_start(&progress, "🔍 Resolving"); 748 } 749 750 pkg_options_t opts = { 751 .progress_callback = pkg_verbose ? NULL : progress_callback, 752 .user_data = pkg_verbose ? NULL : &progress, 753 .verbose = pkg_verbose 754 }; 755 pkg_context_t *ctx = pkg_init(&opts); 756 if (!ctx) { 757 fprintf(stderr, "Error: Failed to initialize package manager\n"); 758 return EXIT_FAILURE; 759 } 760 761 pkg_error_t err = pkg_remove(ctx, "package.json", package_name); 762 if (err != PKG_OK && err != PKG_NOT_FOUND) { 763 if (!pkg_verbose) { progress_stop(&progress); } 764 print_pkg_error(ctx); 765 pkg_free(ctx); 766 return EXIT_FAILURE; 767 } 768 769 if (err == PKG_NOT_FOUND) { 770 if (!pkg_verbose) { progress_stop(&progress); } 771 printf("\n%s[%s", C_DIM, C_RESET); 772 printf("%s0ms%s", C_BOLD, C_RESET); 773 printf("%s]%s done\n", C_DIM, C_RESET); 774 pkg_free(ctx); 775 return EXIT_SUCCESS; 776 } 777 778 err = pkg_resolve_and_install(ctx, "package.json", "ant.lockb", "node_modules"); 779 if (err != PKG_OK) { 780 if (!pkg_verbose) { progress_stop(&progress); } 781 print_pkg_error(ctx); 782 pkg_free(ctx); 783 return EXIT_FAILURE; 784 } 785 786 if (!pkg_verbose) { 787 progress_stop(&progress); 788 789 } 790 791 pkg_install_result_t result; 792 if (pkg_get_install_result(ctx, &result) == PKG_OK) { 793 printf("\n%s%u%s package%s installed %s[%s", 794 C_GREEN, result.packages_installed, C_RESET, 795 result.packages_installed == 1 ? "" : "s", 796 C_DIM, C_RESET); 797 print_elapsed(result.elapsed_ms); 798 printf("%s]%s\n", C_DIM, C_RESET); 799 } 800 801 printf("%s-%s Removed: %s%s%s\n", C_RED, C_RESET, C_BOLD, package_name, C_RESET); 802 pkg_free(ctx); 803 804 return EXIT_SUCCESS; 805} 806 807static int cmd_trust(const char **pkgs, int count, bool all) { 808 print_install_header("trust"); 809 810 struct timespec start_time; 811 clock_gettime(CLOCK_MONOTONIC, &start_time); 812 813 pkg_options_t opts = { .verbose = pkg_verbose }; 814 pkg_context_t *ctx = pkg_init(&opts); 815 if (!ctx) { 816 fprintf(stderr, "Error: Failed to initialize package manager\n"); 817 return EXIT_FAILURE; 818 } 819 820 if (pkg_discover_lifecycle_scripts(ctx, "node_modules") != PKG_OK) { 821 fprintf(stderr, "Error: Failed to scan node_modules\n"); 822 pkg_free(ctx); 823 return EXIT_FAILURE; 824 } 825 826 uint32_t script_count = pkg_get_lifecycle_script_count(ctx); 827 if (script_count == 0) { 828 printf("No packages need lifecycle scripts to run.\n"); 829 pkg_free(ctx); 830 return EXIT_SUCCESS; 831 } 832 833 const char **to_run = NULL; 834 uint32_t to_run_count = 0; 835 836 if (all) { 837 to_run = try_oom(script_count * sizeof(char *)); 838 if (to_run) { 839 for (uint32_t i = 0; i < script_count; i++) { 840 pkg_lifecycle_script_t script; 841 if (pkg_get_lifecycle_script(ctx, i, &script) == PKG_OK) { 842 to_run[to_run_count++] = script.name; 843 } 844 } 845 } 846 } else if (count > 0) { 847 to_run = try_oom(count * sizeof(char *)); 848 if (to_run) { 849 for (int i = 0; i < count; i++) { 850 bool found = false; 851 for (uint32_t j = 0; j < script_count; j++) { 852 pkg_lifecycle_script_t script; 853 if (pkg_get_lifecycle_script(ctx, j, &script) == PKG_OK) { 854 if (strcmp(pkgs[i], script.name) == 0) { 855 to_run[to_run_count++] = script.name; 856 found = true; break; 857 } 858 } 859 } 860 if (!found) fprintf(stderr, "Warning: %s has no pending lifecycle script\n", pkgs[i]); 861 } 862 } 863 } else { 864 printf("%s%u%s package%s with lifecycle scripts:\n", 865 C_YELLOW, script_count, C_RESET, 866 script_count == 1 ? "" : "s"); 867 868 for (uint32_t i = 0; i < script_count; i++) { 869 pkg_lifecycle_script_t script; 870 if (pkg_get_lifecycle_script(ctx, i, &script) == PKG_OK) { 871 printf(" %s•%s %s%s%s %s(%s)%s\n", 872 C_DIM, C_RESET, 873 C_CYAN, script.name, C_RESET, 874 C_DIM, script.script, C_RESET); 875 } 876 } 877 printf("\nRun: %sant trust <pkg>%s or %sant trust --all%s\n", C_DIM, C_RESET, C_DIM, C_RESET); 878 pkg_free(ctx); 879 return EXIT_SUCCESS; 880 } 881 882 if (to_run && to_run_count > 0) { 883 if (pkg_verbose) { 884 printf("[trust] adding %u packages to trustedDependencies\n", to_run_count); 885 for (uint32_t i = 0; i < to_run_count; i++) { 886 printf("[trust] %s\n", to_run[i]); 887 } 888 } 889 pkg_error_t add_err = pkg_add_trusted_dependencies("package.json", to_run, to_run_count); 890 if (add_err == PKG_OK) { 891 printf("Added %s%u%s package%s to %strustedDependencies%s in package.json\n", 892 C_GREEN, to_run_count, C_RESET, 893 to_run_count == 1 ? "" : "s", 894 C_BOLD, C_RESET); 895 } else { 896 if (pkg_verbose) printf("[trust] failed to add trustedDependencies: error %d\n", add_err); 897 } 898 899 printf("Running lifecycle scripts for %s%u%s package%s...\n", 900 C_GREEN, to_run_count, C_RESET, 901 to_run_count == 1 ? "" : "s"); 902 pkg_run_postinstall(ctx, "node_modules", to_run, to_run_count); 903 904 struct timespec end_time; 905 clock_gettime(CLOCK_MONOTONIC, &end_time); 906 uint64_t elapsed_ms = timespec_diff_ms(&start_time, &end_time); 907 908 printf("\n%s%u%s package%s trusted %s[%s", 909 C_GREEN, to_run_count, C_RESET, 910 to_run_count == 1 ? "" : "s", 911 C_DIM, C_RESET); 912 print_elapsed(elapsed_ms); 913 printf("%s]%s\n", C_DIM, C_RESET); 914 free((void *)to_run); 915 } 916 917 pkg_free(ctx); 918 return EXIT_SUCCESS; 919} 920 921static int cmd_init(void) { 922 FILE *fp = fopen("package.json", "r"); 923 if (fp) { 924 fclose(fp); 925 fprintf(stderr, "Error: package.json already exists\n"); 926 return EXIT_FAILURE; 927 } 928 929 char cwd[PATH_MAX]; 930 const char *default_name = "my-project"; 931 if (getcwd(cwd, sizeof(cwd))) { 932 char *base = strrchr(cwd, '/'); 933 if (base && base[1]) default_name = base + 1; 934 } 935 936 bool interactive = isatty(fileno(stdin)); 937 938 char name[256] = {0}; 939 char version[64] = {0}; 940 char entry[256] = {0}; 941 942 if (interactive) { 943 printf("%sant init%s\n\n", C_BOLD, C_RESET); 944 945 prompt_with_default("package name", default_name, name, sizeof(name)); 946 prompt_with_default("version", "1.0.0", version, sizeof(version)); 947 prompt_with_default("entry point", "index.js", entry, sizeof(entry)); 948 949 fputc('\n', stdout); 950 } else { 951 strncpy(name, default_name, sizeof(name) - 1); 952 strncpy(version, "1.0.0", sizeof(version) - 1); 953 strncpy(entry, "index.js", sizeof(entry) - 1); 954 } 955 956 fp = fopen("package.json", "w"); 957 if (!fp) { 958 fprintf(stderr, "Error: Could not create package.json\n"); 959 return EXIT_FAILURE; 960 } 961 962 yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); 963 yyjson_mut_val *root = yyjson_mut_obj(doc); 964 yyjson_mut_doc_set_root(doc, root); 965 966 yyjson_mut_obj_add_str(doc, root, "name", name); 967 yyjson_mut_obj_add_str(doc, root, "version", version); 968 yyjson_mut_obj_add_str(doc, root, "type", "module"); 969 yyjson_mut_obj_add_str(doc, root, "main", entry); 970 971 yyjson_mut_val *scripts = yyjson_mut_obj_add_obj(doc, root, "scripts"); 972 char start_cmd[300]; 973 snprintf(start_cmd, sizeof(start_cmd), "ant %s", entry); 974 yyjson_mut_obj_add_str(doc, scripts, "start", start_cmd); 975 976 yyjson_mut_obj_add_obj(doc, root, "dependencies"); 977 yyjson_mut_obj_add_obj(doc, root, "devDependencies"); 978 979 size_t len; char *json_str = yyjson_mut_write( 980 doc, YYJSON_WRITE_PRETTY_TWO_SPACES 981 | YYJSON_WRITE_ESCAPE_UNICODE, &len 982 ); 983 984 if (json_str) { 985 fwrite(json_str, 1, len, fp); 986 free(json_str); 987 } 988 989 yyjson_mut_doc_free(doc); 990 fclose(fp); 991 992 printf("%s+%s Created %spackage.json%s\n", C_GREEN, C_RESET, C_BOLD, C_RESET); 993 return EXIT_SUCCESS; 994} 995 996static int cmd_why(const char *package_name) { 997 struct stat st; 998 if (stat("ant.lockb", &st) != 0) { 999 fprintf(stderr, "Error: No lockfile found. Run 'ant install' first.\n"); 1000 return EXIT_FAILURE; 1001 } 1002 1003 pkg_why_info_t info; 1004 if (pkg_why_info("ant.lockb", package_name, &info) < 0) { 1005 fprintf(stderr, "Error: Failed to read lockfile\n"); 1006 return EXIT_FAILURE; 1007 } 1008 1009 if (!info.found) { 1010 printf("\n%s%s%s is not installed\n\n", C_BOLD, package_name, C_RESET); 1011 return EXIT_SUCCESS; 1012 } 1013 1014 const char *type_label = info.is_peer ? " peer" : (info.is_dev ? " dev" : ""); 1015 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); 1016 1017 why_ctx_t ctx = { .target = package_name, .count = 0 }; 1018 int result = pkg_why("ant.lockb", package_name, print_why_callback, &ctx); 1019 1020 if (result < 0) { 1021 fprintf(stderr, "Error: Failed to read lockfile\n"); 1022 return EXIT_FAILURE; 1023 } 1024 1025 if (ctx.count == 0) { 1026 printf(" %s(no dependents)%s\n", C_DIM, C_RESET); 1027 } 1028 1029 fputc('\n', stdout); 1030 return EXIT_SUCCESS; 1031} 1032 1033int pkg_cmd_init(int argc, char **argv) { 1034 struct arg_lit *help = arg_lit0("h", "help", "display help"); 1035 struct arg_end *end = arg_end(5); 1036 1037 void *argtable[] = { help, end }; 1038 int nerrors = arg_parse(argc, argv, argtable); 1039 1040 int exitcode = EXIT_SUCCESS; 1041 if (help->count > 0) { 1042 printf("Usage: ant init\n\n"); 1043 printf("Create a new package.json\n"); 1044 } else if (nerrors > 0) { 1045 arg_print_errors(stdout, end, "ant init"); 1046 exitcode = EXIT_FAILURE; 1047 } else { 1048 exitcode = cmd_init(); 1049 } 1050 1051 arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); 1052 return exitcode; 1053} 1054 1055int pkg_cmd_install(int argc, char **argv) { 1056 struct arg_str *pkgs = arg_strn(NULL, NULL, "<package[@version]>", 0, 100, NULL); 1057 struct arg_lit *global = arg_lit0("g", "global", "install globally"); 1058 struct arg_lit *dev = arg_lit0("D", "save-dev", "add as devDependency"); 1059 struct arg_lit *help = arg_lit0("h", "help", "display help"); 1060 struct arg_end *end = arg_end(5); 1061 1062 void *argtable[] = { pkgs, global, dev, help, end }; 1063 int nerrors = arg_parse(argc, argv, argtable); 1064 1065 int exitcode = EXIT_SUCCESS; 1066 if (help->count > 0) { 1067 printf("Usage: ant install [packages...] [-g] [-D] [--verbose]\n\n"); 1068 printf("Install from lockfile, or add packages if specified.\n"); 1069 printf("\nOptions:\n -g, --global Install globally to %s\n", get_global_dir()); 1070 printf(" -D, --save-dev Add as devDependency\n"); 1071 } else if (nerrors > 0) { 1072 arg_print_errors(stdout, end, "ant install"); 1073 exitcode = EXIT_FAILURE; 1074 } else if (pkgs->count == 0) { 1075 exitcode = cmd_install(); 1076 } else { 1077 bool is_dev = dev->count > 0; 1078 exitcode = global->count > 0 1079 ? cmd_add_global(pkgs->sval, pkgs->count) 1080 : cmd_add(pkgs->sval, pkgs->count, is_dev); 1081 } 1082 1083 arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); 1084 return exitcode; 1085} 1086 1087int pkg_cmd_update(int argc, char **argv) { 1088 struct arg_str *pkgs = arg_strn(NULL, NULL, "<package[@version]>", 0, 100, NULL); 1089 struct arg_lit *help = arg_lit0("h", "help", "display help"); 1090 struct arg_end *end = arg_end(5); 1091 1092 void *argtable[] = { pkgs, help, end }; 1093 int nerrors = arg_parse(argc, argv, argtable); 1094 1095 int exitcode = EXIT_SUCCESS; 1096 if (help->count > 0) { 1097 printf("Usage: ant update [packages...] [--verbose]\n\n"); 1098 printf("Re-resolve all dependencies, or upgrade specific packages in place.\n"); 1099 } else if (nerrors > 0) { 1100 arg_print_errors(stdout, end, "ant update"); 1101 exitcode = EXIT_FAILURE; 1102 } else { 1103 exitcode = pkgs->count > 0 ? cmd_update_many(pkgs->sval, pkgs->count) : cmd_update(); 1104 } 1105 1106 arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); 1107 return exitcode; 1108} 1109 1110int pkg_cmd_add(int argc, char **argv) { 1111 struct arg_str *pkgs = arg_strn(NULL, NULL, "<package[@version]>", 1, 100, NULL); 1112 struct arg_lit *global = arg_lit0("g", "global", "install globally"); 1113 struct arg_lit *dev = arg_lit0("D", "save-dev", "add as devDependency"); 1114 struct arg_lit *help = arg_lit0("h", "help", "display help"); 1115 struct arg_end *end = arg_end(5); 1116 1117 void *argtable[] = { pkgs, global, dev, help, end }; 1118 int nerrors = arg_parse(argc, argv, argtable); 1119 1120 int exitcode = EXIT_SUCCESS; 1121 if (help->count > 0) { 1122 printf("Usage: ant add <package[@version]>... [options]\n\n"); 1123 printf("Add packages to dependencies.\n"); 1124 printf("\nOptions:\n -g, --global Install globally to %s\n", get_global_dir()); 1125 printf(" -D, --save-dev Add as devDependency\n"); 1126 } else if (nerrors > 0) { 1127 arg_print_errors(stdout, end, "ant add"); 1128 exitcode = EXIT_FAILURE; 1129 } else { 1130 bool is_dev = dev->count > 0; 1131 exitcode = global->count > 0 1132 ? cmd_add_global(pkgs->sval, pkgs->count) 1133 : cmd_add(pkgs->sval, pkgs->count, is_dev); 1134 } 1135 1136 arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); 1137 return exitcode; 1138} 1139 1140int pkg_cmd_remove(int argc, char **argv) { 1141 struct arg_str *pkgs = arg_strn(NULL, NULL, "<package>", 1, 100, NULL); 1142 struct arg_lit *global = arg_lit0("g", "global", "remove from global packages"); 1143 struct arg_lit *help = arg_lit0("h", "help", "display help"); 1144 struct arg_end *end = arg_end(5); 1145 1146 void *argtable[] = { pkgs, global, help, end }; 1147 int nerrors = arg_parse(argc, argv, argtable); 1148 1149 int exitcode = EXIT_SUCCESS; 1150 if (help->count > 0) { 1151 printf("Usage: ant remove <package>... [-g]\n\n"); 1152 printf("Remove packages from dependencies.\n"); 1153 printf("\nOptions:\n -g, --global Remove from global packages\n"); 1154 } else if (nerrors > 0) { 1155 arg_print_errors(stdout, end, "ant remove"); 1156 exitcode = EXIT_FAILURE; 1157 } else { 1158 for (int i = 0; i < pkgs->count && exitcode == EXIT_SUCCESS; i++) { 1159 exitcode = global->count > 0 ? cmd_remove_global(pkgs->sval[i]) : cmd_remove(pkgs->sval[i]); 1160 } 1161 } 1162 1163 arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); 1164 return exitcode; 1165} 1166 1167int pkg_cmd_trust(int argc, char **argv) { 1168 struct arg_str *pkgs = arg_strn(NULL, NULL, "<package>", 0, 100, NULL); 1169 struct arg_lit *all = arg_lit0("a", "all", "trust all packages with lifecycle scripts"); 1170 struct arg_lit *help = arg_lit0("h", "help", "display help"); 1171 struct arg_end *end = arg_end(5); 1172 1173 void *argtable[] = { pkgs, all, help, end }; 1174 int nerrors = arg_parse(argc, argv, argtable); 1175 1176 int exitcode = EXIT_SUCCESS; 1177 if (help->count > 0) { 1178 printf("Usage: ant trust [packages...] [--all]\n\n"); 1179 printf("Run lifecycle scripts for packages.\n"); 1180 printf(" --all, -a Trust and run all pending lifecycle scripts\n"); 1181 } else if (nerrors > 0) { 1182 arg_print_errors(stdout, end, "ant trust"); 1183 exitcode = EXIT_FAILURE; 1184 } else { 1185 exitcode = cmd_trust(pkgs->sval, pkgs->count, all->count > 0); 1186 } 1187 1188 arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); 1189 return exitcode; 1190} 1191 1192int pkg_cmd_run(int argc, char **argv) { 1193 if (argc < 2) { 1194 printf("Usage: ant run <script> [args...]\n\n"); 1195 printf("Run a script from package.json\n\n"); 1196 printf("Available scripts:\n"); 1197 1198 int count = pkg_list_scripts("package.json", NULL, NULL); 1199 if (count < 0) { 1200 printf(" (no package.json found)\n"); 1201 } else if (count == 0) { 1202 printf(" (no scripts defined)\n"); 1203 } else { 1204 pkg_list_scripts("package.json", print_script, NULL); 1205 } 1206 return EXIT_SUCCESS; 1207 } 1208 1209 const char *script_name = argv[1]; 1210 1211 char script_cmd[4096]; 1212 int script_len = pkg_get_script("package.json", script_name, script_cmd, sizeof(script_cmd)); 1213 if (script_len < 0) { 1214 fprintf(stderr, "Error: script '%s' not found in package.json\n", script_name); 1215 fprintf(stderr, "Try 'ant run' to list available scripts.\n"); 1216 return EXIT_FAILURE; 1217 } 1218 1219 char extra_args[4096] = {0}; 1220 int extra_args_len = 0; 1221 1222 int arg_start = 2; 1223 if (arg_start < argc && strcmp(argv[arg_start], "--") == 0) arg_start++; 1224 1225 for (int i = arg_start; i < argc; i++) { 1226 if (extra_args_len > 0) extra_args[extra_args_len++] = ' '; 1227 size_t arg_len = strlen(argv[i]); 1228 if ((size_t)extra_args_len + arg_len < sizeof(extra_args) - 1) { 1229 memcpy(extra_args + extra_args_len, argv[i], arg_len); 1230 extra_args_len += (int)arg_len; 1231 } 1232 } 1233 1234 extra_args[extra_args_len] = '\0'; 1235 printf("%s$%s %s%s%s", C_MAGENTA, C_RESET, C_BOLD, script_cmd, C_RESET); 1236 1237 if (extra_args_len > 0) printf(" %s", extra_args); 1238 fputc('\n', stdout); 1239 1240 pkg_script_result_t result = {0}; 1241 pkg_error_t err = pkg_run_script( 1242 "package.json", script_name, "node_modules", 1243 extra_args_len > 0 ? extra_args : NULL, 1244 &result 1245 ); 1246 1247 if (err != PKG_OK) { 1248 if (err == PKG_NOT_FOUND) { 1249 fprintf(stderr, "Error: script '%s' not found\n", script_name); 1250 } else { 1251 fprintf(stderr, "Error: failed to run script '%s'\n", script_name); 1252 } 1253 return EXIT_FAILURE; 1254 } 1255 1256 if (result.signal != 0) { 1257 fprintf(stderr, "Script '%s' killed by signal %d\n", script_name, result.signal); 1258 return 128 + result.signal; 1259 } 1260 1261 return result.exit_code; 1262} 1263 1264int pkg_cmd_exec(int argc, char **argv) { 1265 if (argc < 2) { 1266 printf("Usage: ant x [--ant] <command> [args...]\n\n"); 1267 printf("Run a command from node_modules/.bin or download temporarily\n\n"); 1268 printf("Options:\n"); 1269 printf(" --ant Run with ant instead of node\n\n"); 1270 printf("Available commands:\n"); 1271 1272 int count = pkg_list_bins("node_modules", NULL, NULL); 1273 if (count < 0) printf(" (no binaries found - run 'ant install' first)\n"); 1274 else if (count == 0) printf(" (no binaries installed)\n"); 1275 else pkg_list_bins("node_modules", print_bin_name, NULL); 1276 1277 return EXIT_SUCCESS; 1278 } 1279 1280 bool use_ant = false; 1281 int cmd_idx = 1; 1282 1283 if (strcmp(argv[1], "--ant") == 0) { 1284 use_ant = true; 1285 cmd_idx = 2; 1286 if (argc < 3) { 1287 fprintf(stderr, "Error: missing command after --ant\n"); 1288 return EXIT_FAILURE; 1289 } 1290 } 1291 1292 const char *cmd_name = argv[cmd_idx]; char bin_path[4096]; 1293 int path_len = pkg_get_bin_path("node_modules", cmd_name, bin_path, sizeof(bin_path)); 1294 1295 if (path_len < 0) { 1296 const char *global_dir = get_global_dir(); 1297 if (global_dir[0]) { 1298 char global_nm[4096]; 1299 snprintf(global_nm, sizeof(global_nm), "%s/node_modules", global_dir); 1300 path_len = pkg_get_bin_path(global_nm, cmd_name, bin_path, sizeof(bin_path)); 1301 } 1302 } 1303 1304 if (path_len < 0) { 1305 progress_t progress; 1306 bool show_progress = !pkg_verbose; 1307 1308 if (show_progress) { 1309 char msg[256]; 1310 snprintf(msg, sizeof(msg), "🔍 Resolving %s", cmd_name); 1311 progress_start(&progress, msg); 1312 } 1313 1314 pkg_options_t opts = { 1315 .progress_callback = show_progress ? progress_callback : NULL, 1316 .user_data = show_progress ? &progress : NULL, 1317 .verbose = pkg_verbose 1318 }; 1319 1320 pkg_context_t *ctx = pkg_init(&opts); 1321 if (!ctx) { 1322 if (show_progress) progress_stop(&progress); 1323 fprintf(stderr, "Error: Failed to initialize package manager\n"); 1324 return EXIT_FAILURE; 1325 } 1326 1327 pkg_error_t err = pkg_exec_temp(ctx, cmd_name, bin_path, sizeof(bin_path)); 1328 if (show_progress) progress_stop(&progress); 1329 1330 if (err != PKG_OK) { 1331 const char *err_msg = pkg_error_string(ctx); 1332 if (err_msg && err_msg[0]) { 1333 fprintf(stderr, "Error: %s\n", err_msg); 1334 } else { 1335 fprintf(stderr, "Error: '%s' not found\n", cmd_name); 1336 } 1337 pkg_free(ctx); 1338 return EXIT_FAILURE; 1339 } 1340 pkg_free(ctx); 1341 } 1342 1343 int arg_offset = cmd_idx + 1; 1344 int extra = use_ant ? 2 : 1; 1345 int new_argc = argc - arg_offset + extra; 1346 1347 char **exec_argv = try_oom(sizeof(char*) * (new_argc + 1)); 1348 if (!exec_argv) { 1349 fprintf(stderr, "Error: out of memory\n"); 1350 return EXIT_FAILURE; 1351 } 1352 1353 int idx = 0; 1354 if (use_ant) exec_argv[idx++] = (char *)"ant"; 1355 exec_argv[idx++] = bin_path; 1356 1357 for (int i = arg_offset; i < argc; i++) exec_argv[idx++] = argv[i]; 1358 exec_argv[idx] = NULL; 1359 1360 const char *cmd = use_ant ? "ant" : bin_path; 1361 execvp(cmd, exec_argv); 1362 free(exec_argv); 1363 1364 if (use_ant) fprintf(stderr, "Error: failed to execute 'ant %s' - is ant installed?\n", bin_path); 1365 else fprintf(stderr, "Error: failed to execute '%s'\n", bin_path); 1366 1367 return EXIT_FAILURE; 1368} 1369 1370int pkg_cmd_why(int argc, char **argv) { 1371 struct arg_str *pkg = arg_str1(NULL, NULL, "<package>", "package name to query"); 1372 struct arg_lit *help = arg_lit0("h", "help", "display help"); 1373 struct arg_end *end = arg_end(5); 1374 1375 void *argtable[] = { pkg, help, end }; 1376 int nerrors = arg_parse(argc, argv, argtable); 1377 1378 int exitcode = EXIT_SUCCESS; 1379 if (help->count > 0) { 1380 printf("Usage: ant why <package>\n\n"); 1381 printf("Show which packages depend on the given package.\n"); 1382 } else if (nerrors > 0) { 1383 arg_print_errors(stdout, end, "ant why"); 1384 exitcode = EXIT_FAILURE; 1385 } else { 1386 exitcode = cmd_why(pkg->sval[0]); 1387 } 1388 1389 arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); 1390 return exitcode; 1391} 1392 1393static const char *format_size(uint64_t bytes, char *buf, size_t buf_size) { 1394 if (bytes >= 1024ULL * 1024 * 1024) snprintf(buf, buf_size, "%.2f GB", (double)bytes / (1024.0 * 1024.0 * 1024.0)); 1395 else if (bytes >= 1024 * 1024) snprintf(buf, buf_size, "%.2f MB", (double)bytes / (1024.0 * 1024.0)); 1396 else if (bytes >= 1024) snprintf(buf, buf_size, "%.2f KB", (double)bytes / 1024.0); 1397 else snprintf(buf, buf_size, "%llu B", (unsigned long long)bytes); 1398 return buf; 1399} 1400 1401static int cmd_info(const char *package_spec) { 1402 pkg_options_t opts = { .verbose = false }; 1403 pkg_context_t *ctx = pkg_init(&opts); 1404 if (!ctx) { 1405 fprintf(stderr, "Error: Failed to initialize package manager\n"); 1406 return EXIT_FAILURE; 1407 } 1408 1409 pkg_info_t info; 1410 pkg_error_t err = pkg_info(ctx, package_spec, &info); 1411 if (err != PKG_OK) { 1412 print_pkg_error(ctx); 1413 pkg_free(ctx); 1414 return EXIT_FAILURE; 1415 } 1416 1417 char size_buf[32]; 1418 1419 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); 1420 if (info.license[0]) printf(" | %s%s%s", C_CYAN, info.license, C_RESET); 1421 printf(" | deps: %u | versions: %u\n", info.dep_count, info.version_count); 1422 1423 if (info.description[0]) printf("%s\n", info.description); 1424 if (info.homepage[0]) printf("%s%s%s\n", C_BLUE, info.homepage, C_RESET); 1425 if (info.keywords[0]) printf("keywords: %s\n", info.keywords); 1426 1427 uint32_t dep_count = pkg_info_dependency_count(ctx); 1428 if (dep_count > 0) { 1429 printf("\n%sdependencies%s (%u):\n", C_BOLD, C_RESET, dep_count); 1430 for (uint32_t i = 0; i < dep_count; i++) { 1431 pkg_dependency_t dep; 1432 if (pkg_info_get_dependency(ctx, i, &dep) == PKG_OK) { 1433 printf("- %s%s%s: %s\n", C_CYAN, dep.name, C_RESET, dep.version); 1434 } 1435 } 1436 } 1437 1438 printf("\n%sdist%s\n", C_BOLD, C_RESET); 1439 if (info.tarball[0]) printf(" %s.tarball:%s %s\n", C_DIM, C_RESET, info.tarball); 1440 if (info.shasum[0]) printf(" %s.shasum:%s %s%s%s\n", C_DIM, C_RESET, C_GREEN, info.shasum, C_RESET); 1441 if (info.integrity[0]) printf(" %s.integrity:%s %s%s%s\n", C_DIM, C_RESET, C_GREEN, info.integrity, C_RESET); 1442 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); 1443 1444 uint32_t tag_count = pkg_info_dist_tag_count(ctx); 1445 if (tag_count > 0) { 1446 printf("\n%sdist-tags:%s\n", C_BOLD, C_RESET); 1447 for (uint32_t i = 0; i < tag_count; i++) { 1448 pkg_dist_tag_t tag; 1449 if (pkg_info_get_dist_tag(ctx, i, &tag) == PKG_OK) { 1450 const char *tag_color = C_MAGENTA; 1451 if (strcmp(tag.tag, "beta") == 0) tag_color = C_BLUE; 1452 else if (strcmp(tag.tag, "latest") == 0) tag_color = C_CYAN; 1453 printf("%s%s%s: %s\n", tag_color, tag.tag, C_RESET, tag.version); 1454 } 1455 } 1456 } 1457 1458 uint32_t maint_count = pkg_info_maintainer_count(ctx); 1459 if (maint_count > 0) { 1460 printf("\n%smaintainers:%s\n", C_BOLD, C_RESET); 1461 for (uint32_t i = 0; i < maint_count; i++) { 1462 pkg_maintainer_t maint; 1463 if (pkg_info_get_maintainer(ctx, i, &maint) == PKG_OK) { 1464 printf("- %s", maint.name); 1465 if (maint.email[0]) printf(" <%s>", maint.email); 1466 fputc('\n', stdout); 1467 } 1468 } 1469 } 1470 1471 if (info.published[0]) printf("\n%sPublished:%s %s\n", C_BOLD, C_RESET, info.published); 1472 1473 pkg_free(ctx); 1474 return EXIT_SUCCESS; 1475} 1476 1477int pkg_cmd_info(int argc, char **argv) { 1478 struct arg_str *pkg = arg_str1(NULL, NULL, "<package[@version]>", "package to look up"); 1479 struct arg_lit *help = arg_lit0("h", "help", "display help"); 1480 struct arg_end *end = arg_end(5); 1481 1482 void *argtable[] = { pkg, help, end }; 1483 int nerrors = arg_parse(argc, argv, argtable); 1484 1485 int exitcode = EXIT_SUCCESS; 1486 if (help->count > 0) { 1487 printf("Usage: ant info <package[@version]>\n\n"); 1488 printf("Show package information from the npm registry.\n"); 1489 } else if (nerrors > 0) { 1490 arg_print_errors(stdout, end, "ant info"); 1491 exitcode = EXIT_FAILURE; 1492 } else { 1493 exitcode = cmd_info(pkg->sval[0]); 1494 } 1495 1496 arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); 1497 return exitcode; 1498} 1499 1500typedef struct { 1501 int count; 1502 bool show_path; 1503 const char *nm_path; 1504} ls_ctx_t; 1505 1506static void print_ls_package(const char *name, void *user_data) { 1507 ls_ctx_t *ctx = (ls_ctx_t *)user_data; 1508 1509 char pkg_json_path[4096]; 1510 snprintf(pkg_json_path, sizeof(pkg_json_path), "%s/%s/package.json", ctx->nm_path, name); 1511 1512 FILE *f = fopen(pkg_json_path, "r"); 1513 if (!f) { 1514 printf(" %s%s%s\n", C_BOLD, name, C_RESET); 1515 ctx->count++; 1516 return; 1517 } 1518 1519 char buf[8192]; 1520 size_t len = fread(buf, 1, sizeof(buf) - 1, f); 1521 fclose(f); 1522 buf[len] = '\0'; 1523 1524 const char *version = "?"; 1525 char version_buf[64] = {0}; 1526 1527 char *ver_key = strstr(buf, "\"version\""); 1528 if (ver_key) { 1529 char *colon = strchr(ver_key, ':'); 1530 if (colon) { 1531 char *quote1 = strchr(colon, '"'); 1532 if (quote1) { 1533 char *quote2 = strchr(quote1 + 1, '"'); 1534 if (quote2) { 1535 size_t vlen = (size_t)(quote2 - quote1 - 1); 1536 if (vlen < sizeof(version_buf)) { 1537 memcpy(version_buf, quote1 + 1, vlen); 1538 version_buf[vlen] = '\0'; 1539 version = version_buf; 1540 } 1541 } 1542 } 1543 } 1544 } 1545 1546 printf(" %s%s%s@%s%s%s\n", C_BOLD, name, C_RESET, C_DIM, version, C_RESET); 1547 ctx->count++; 1548} 1549 1550typedef struct { 1551 int count; 1552 int total; 1553} pkg_ls_ctx_t; 1554 1555static void print_pkg_cb(const char *name, const char *version, void *user_data) { 1556 pkg_ls_ctx_t *ctx = (pkg_ls_ctx_t *)user_data; 1557 ctx->count++; 1558 const char *prefix = (ctx->count == ctx->total) ? "└──" : "├──"; 1559 printf("%s%s%s %s%s%s@%s\n", C_DIM, prefix, C_RESET, C_BOLD, name, C_RESET, version); 1560} 1561 1562static int cmd_ls(bool is_global) { 1563 pkg_options_t opts = { .verbose = pkg_verbose }; 1564 pkg_context_t *ctx = pkg_init(&opts); 1565 if (!ctx) { 1566 fprintf(stderr, "Error: Failed to initialize package manager\n"); 1567 return EXIT_FAILURE; 1568 } 1569 1570 char path_buf[PATH_MAX]; 1571 const char *base_path; 1572 const char *nm_path; 1573 char nm_full_path[PATH_MAX]; 1574 1575 if (is_global) { 1576 base_path = get_global_dir(); 1577 snprintf(nm_full_path, sizeof(nm_full_path), "%s/node_modules", base_path); 1578 nm_path = nm_full_path; 1579 } else { 1580 if (!getcwd(path_buf, sizeof(path_buf))) { 1581 fprintf(stderr, "Error: Could not get current directory\n"); 1582 pkg_free(ctx); 1583 return EXIT_FAILURE; 1584 } 1585 base_path = path_buf; 1586 nm_path = "node_modules"; 1587 } 1588 1589 uint32_t direct = is_global ? pkg_count_global(ctx) : pkg_count_local(ctx); 1590 uint32_t total = pkg_count_installed(nm_path); 1591 1592 printf("%s%s/node_modules%s", C_DIM, base_path, C_RESET); 1593 1594 if (direct == 0) { 1595 printf("\n (no package.json)\n"); 1596 pkg_free(ctx); 1597 return EXIT_SUCCESS; 1598 } 1599 1600 if (total == 0) { 1601 printf("\n (empty)\n"); 1602 pkg_free(ctx); 1603 return EXIT_SUCCESS; 1604 } 1605 1606 printf(" %s(%u)%s\n", C_DIM, total, C_RESET); 1607 1608 pkg_ls_ctx_t ls_ctx = { .count = 0, .total = (int)direct }; 1609 if (is_global) pkg_list_global(ctx, print_pkg_cb, &ls_ctx); 1610 else pkg_list_local(ctx, print_pkg_cb, &ls_ctx); 1611 1612 pkg_free(ctx); 1613 return EXIT_SUCCESS; 1614} 1615 1616int pkg_cmd_ls(int argc, char **argv) { 1617 struct arg_lit *global = arg_lit0("g", "global", "list global packages"); 1618 struct arg_lit *help = arg_lit0("h", "help", "display help"); 1619 struct arg_end *end = arg_end(5); 1620 1621 void *argtable[] = { global, help, end }; 1622 int nerrors = arg_parse(argc, argv, argtable); 1623 1624 int exitcode = EXIT_SUCCESS; 1625 if (help->count > 0) { 1626 printf("Usage: ant ls [-g]\n\n"); 1627 printf("List installed packages.\n"); 1628 printf("\nOptions:\n -g, --global List global packages\n"); 1629 } else if (nerrors > 0) { 1630 arg_print_errors(stdout, end, "ant ls"); 1631 exitcode = EXIT_FAILURE; 1632 } else exitcode = cmd_ls(global->count > 0); 1633 1634 arg_freetable(argtable, sizeof(argtable)/sizeof(argtable[0])); 1635 return exitcode; 1636} 1637 1638static int cmd_cache_info(void) { 1639 pkg_options_t opts = { .verbose = pkg_verbose }; 1640 pkg_context_t *ctx = pkg_init(&opts); 1641 if (!ctx) { 1642 fprintf(stderr, "Error: Failed to initialize package manager\n"); 1643 return EXIT_FAILURE; 1644 } 1645 1646 pkg_cache_stats_t stats; 1647 pkg_error_t err = pkg_cache_stats(ctx, &stats); 1648 if (err != PKG_OK) { 1649 fprintf(stderr, "Error: Failed to get cache stats\n"); 1650 pkg_free(ctx); 1651 return EXIT_FAILURE; 1652 } 1653 1654 char size_buf[64], db_buf[64]; 1655 printf("%sCache location:%s %s\n", C_BOLD, C_RESET, get_cache_dir()); 1656 printf("%sPackages:%s %u\n", C_BOLD, C_RESET, stats.package_count); 1657 printf("%sSize:%s %s\n", C_BOLD, C_RESET, format_size(stats.total_size, size_buf, sizeof(size_buf))); 1658 printf("%sDB size:%s %s\n", C_BOLD, C_RESET, format_size(stats.db_size, db_buf, sizeof(db_buf))); 1659 1660 pkg_free(ctx); 1661 return EXIT_SUCCESS; 1662} 1663 1664static int cmd_cache_prune(uint32_t max_age_days) { 1665 pkg_options_t opts = { .verbose = pkg_verbose }; 1666 pkg_context_t *ctx = pkg_init(&opts); 1667 if (!ctx) { 1668 fprintf(stderr, "Error: Failed to initialize package manager\n"); 1669 return EXIT_FAILURE; 1670 } 1671 1672 int32_t pruned = pkg_cache_prune(ctx, max_age_days); 1673 if (pruned < 0) { 1674 fprintf(stderr, "Error: Failed to prune cache\n"); 1675 pkg_free(ctx); 1676 return EXIT_FAILURE; 1677 } 1678 1679 if (pruned == 0) { 1680 printf("No packages to prune (all packages newer than %u days)\n", max_age_days); 1681 } else { 1682 printf("%sPruned%s %d package%s older than %u days\n", 1683 C_GREEN, C_RESET, pruned, pruned == 1 ? "" : "s", max_age_days); 1684 } 1685 1686 pkg_free(ctx); 1687 return EXIT_SUCCESS; 1688} 1689 1690static int cmd_cache_sync(void) { 1691 pkg_options_t opts = { .verbose = pkg_verbose }; 1692 pkg_context_t *ctx = pkg_init(&opts); 1693 if (!ctx) { 1694 fprintf(stderr, "Error: Failed to initialize package manager\n"); 1695 return EXIT_FAILURE; 1696 } 1697 1698 pkg_cache_sync(ctx); 1699 printf("%sCache synced%s\n", C_GREEN, C_RESET); 1700 1701 pkg_free(ctx); 1702 return EXIT_SUCCESS; 1703} 1704 1705int pkg_cmd_cache(int argc, char **argv) { 1706 if (argc < 2) { 1707 printf("Usage: ant cache <command>\n\n"); 1708 printf("Manage the package cache.\n\n"); 1709 printf("Commands:\n"); 1710 printf(" info Show cache statistics\n"); 1711 printf(" prune [days] Remove packages older than N days (default: 30)\n"); 1712 printf(" sync Sync cache to disk\n"); 1713 return EXIT_SUCCESS; 1714 } 1715 1716 const char *subcmd = argv[1]; 1717 1718 if (strcmp(subcmd, "info") == 0) { 1719 return cmd_cache_info(); 1720 } else if (strcmp(subcmd, "prune") == 0) { 1721 uint32_t days = 30; 1722 if (argc >= 3) { 1723 days = (uint32_t)atoi(argv[2]); 1724 if (days == 0) days = 30; 1725 } 1726 return cmd_cache_prune(days); 1727 } else if (strcmp(subcmd, "sync") == 0) { 1728 return cmd_cache_sync(); 1729 } else { 1730 fprintf(stderr, "Unknown cache command: %s\n", subcmd); 1731 fprintf(stderr, "Run 'ant cache' for usage.\n"); 1732 return EXIT_FAILURE; 1733 } 1734} 1735 1736int pkg_cmd_create(int argc, char **argv) { 1737 if (argc < 2) { 1738 printf("Usage: ant create <template> [dest] [...flags]\n"); 1739 printf(" ant create <github-org/repo> [dest] [...flags]\n\n"); 1740 printf("Scaffold a new project from a template.\n\n"); 1741 printf("Templates:\n"); 1742 printf(" NPM: Runs 'ant x create-<template>' with given arguments\n"); 1743 printf(" GitHub: Clones repository contents as template\n\n"); 1744 printf("Environment variables:\n"); 1745 printf(" GITHUB_TOKEN Supply a token for private repos or higher rate limits\n"); 1746 return EXIT_SUCCESS; 1747 } 1748 1749 const char *template = argv[1]; 1750 bool is_github = (strchr(template, '/') != NULL); 1751 1752 if (is_github) { 1753 const char *dest = NULL; 1754 1755 for (int i = 2; i < argc; i++) { 1756 if (argv[i][0] != '-') { dest = argv[i]; break; } 1757 } 1758 1759 if (!dest) { 1760 const char *slash = strrchr(template, '/'); 1761 dest = slash ? slash + 1 : template; 1762 } 1763 1764 struct stat st; 1765 if (stat(dest, &st) == 0) { 1766 fprintf(stderr, "Error: directory '%s' already exists\n", dest); 1767 return EXIT_FAILURE; 1768 } 1769 1770 char url[1024]; 1771 if (strncmp(template, "https://", 8) == 0 || strncmp(template, "git@", 4) == 0) { 1772 snprintf(url, sizeof(url), "%s", template); 1773 } else snprintf(url, sizeof(url), "https://github.com/%s.git", template); 1774 1775 printf("%s+%s Creating project from %s%s%s...\n", C_GREEN, C_RESET, C_BOLD, template, C_RESET); 1776 1777 char cmd[2048]; 1778 snprintf(cmd, sizeof(cmd), "git clone --depth 1 %s %s", url, dest); 1779 int ret = system(cmd); 1780 if (ret != 0) { 1781 fprintf(stderr, "Error: failed to clone %s\n", url); 1782 return EXIT_FAILURE; 1783 } 1784 1785 char git_dir[1024]; 1786 snprintf(git_dir, sizeof(git_dir), "%s/.git", dest); 1787 1788 char rm_cmd[1024]; 1789 snprintf(rm_cmd, sizeof(rm_cmd), "rm -rf %s", git_dir); 1790 system(rm_cmd); 1791 1792 if (stat(dest, &st) == 0) { 1793 char pkg_json[1024]; 1794 snprintf(pkg_json, sizeof(pkg_json), "%s/package.json", dest); 1795 if (stat(pkg_json, &st) == 0) { 1796 printf("\n%sDone!%s Created %s%s%s\n", C_GREEN, C_RESET, C_BOLD, dest, C_RESET); 1797 printf("\n cd %s\n ant install\n\n", dest); 1798 } else printf("\n%sDone!%s Created %s%s%s\n", C_GREEN, C_RESET, C_BOLD, dest, C_RESET); 1799 } 1800 1801 return EXIT_SUCCESS; 1802 } 1803 1804 char create_pkg[512]; 1805 snprintf(create_pkg, sizeof(create_pkg), "create-%s", template); 1806 1807 int new_argc = argc; 1808 char **new_argv = malloc(sizeof(char*) * (new_argc + 1)); 1809 if (!new_argv) { 1810 fprintf(stderr, "Error: out of memory\n"); 1811 return EXIT_FAILURE; 1812 } 1813 1814 new_argv[0] = argv[0]; 1815 new_argv[1] = create_pkg; 1816 1817 for (int i = 2; i < argc; i++) new_argv[i] = argv[i]; 1818 new_argv[new_argc] = NULL; 1819 1820 int ret = pkg_cmd_exec(new_argc, new_argv); 1821 free(new_argv); 1822 1823 return ret; 1824}