install: add -dpkg (Linux deb) and -msi (Windows msi) local installs; split install_path dispatch + install_local_file

这个提交包含在:
JGZYES
2026-09-02 12:34:39 +08:00
父节点 474043f05f
当前提交 a83be8169d
修改 3 个文件,包含 56 行新增7 行删除
+25 -6
查看文件
@@ -151,8 +151,7 @@ static int native_binary_ok(const char *path, PmmOS os) {
}
int install_file(const char *url, const char *name) {
PmmOS os = pmm_detect_os();
char cache[1024], path[1200], cmd[2600];
char cache[1024], path[1200];
pmm_cache_dir(cache, sizeof(cache));
snprintf(path, sizeof(path), "%s/%s", cache, name);
@@ -189,6 +188,17 @@ int install_file(const char *url, const char *name) {
return -1;
}
return install_path(path, name);
}
/* Install an already-local file path by its extension. Shared by downloads
* (install_file) and local `pmm install -dpkg/-msi <file>` / `install file.deb`.
* Returns 0 on success. */
static int install_path(const char *path, const char *name) {
PmmOS os = pmm_detect_os();
char dest[1024];
pmm_install_dir(dest, sizeof(dest));
const char *bname = base_name(name);
/* A bare binary (no extension) must really be a native executable for this
* OS; otherwise refuse so the caller can fall back to the os-named asset. */
@@ -197,18 +207,16 @@ int install_file(const char *url, const char *name) {
if (!native_binary_ok(path, os)) {
fprintf(stderr, "pmm: %s is not a usable %s binary; will fall back\n",
bname, pmm_os_name(os));
remove(path);
return -1;
}
}
char dest[1024];
pmm_install_dir(dest, sizeof(dest));
/* forward-slash clone of the cached path (native exes/tools accept it and the
/* forward-slash clone of the path (native exes/tools accept it and the
* git-bash shell won't mangle a command word like "C:/...") */
char pwin[1200];
snprintf(pwin, sizeof(pwin), "%s", path);
for (char *q = pwin; *q; q++) if (*q == '\\') *q = '/';
char cmd[2600];
/* .pdm packages are installed through the deb-like manager */
if (has_suffix(bname, ".pdm") || has_suffix(bname, ".PDM")) {
@@ -276,6 +284,17 @@ int install_file(const char *url, const char *name) {
return 0;
}
/* Install a local file by its extension — e.g. `pmm install -dpkg foo.deb`
* (Linux) or `pmm install -msi foo.msi` (Windows). Returns 0 on success. */
int install_local_file(const char *path) {
if (!path || !*path) { fprintf(stderr, "pmm: empty file path\n"); return -1; }
FILE *chk = fopen(path, "rb");
if (!chk) { fprintf(stderr, "pmm: cannot open file: %s\n", path); return -1; }
fclose(chk);
printf("pmm: installing local file %s\n", path);
return install_path(path, path);
}
/* ---------- python-style version selection (==,>=,<=,>,<,!= , comma list) ---------- */
/* Compare dotted version strings numerically ("24.20.0" vs "24.2.0"). */
+4
查看文件
@@ -6,6 +6,10 @@
* name is the asset file name used to decide the install method. */
int install_file(const char *url, const char *name);
/* Install a local file path according to its extension — e.g.
* `pmm install -dpkg foo.deb` (Linux) or `pmm install -msi foo.msi` (Windows). */
int install_local_file(const char *path);
/* Install from a remote registry (apt-style multi-mirror fallback):
* looks up package `name` in the configured registry mirrors by priority.
* If `version` is non-NULL, fetches {registry}/{name}/{version}.json, otherwise
+27 -1
查看文件
@@ -138,6 +138,19 @@ static PmmHost host_from_name(const char *h) {
return HOST_UNKNOWN;
}
/* True if the filename has a known auto-installable extension (local packages). */
static int has_installer_ext(const char *s) {
static const char *exts[] = { ".deb", ".rpm", ".appimage", ".msi", ".exe", ".zip",
".tgz", ".tar.gz", ".tar.xz", ".tar.bz2", ".7z",
".dmg", ".pkg", ".pkg.tar.zst", NULL };
size_t l = strlen(s);
for (int i = 0; exts[i]; i++) {
size_t el = strlen(exts[i]);
if (l >= el && strcmp(s + l - el, exts[i]) == 0) return 1;
}
return 0;
}
/* <flag> <repo-ish> [--host <name>] */
static int cmd_install_git(int argc, char **argv, const char *flag) {
const char *repo = NULL;
@@ -397,15 +410,21 @@ int main(int argc, char **argv) {
strcmp(argv[2], "--forgejo") == 0))
return cmd_install_git(argc - 3, argv + 3, argv[2] + 2);
if (argc < 3) {
fprintf(stderr, "pmm: usage: pmm install <pkg|file.pdm> [...] | pmm install --git <repo>\n");
fprintf(stderr, "pmm: usage: pmm install <pkg|file.deb|file.msi|file.pdm> [pkg2 ...]\n"
" | pmm install -dpkg <x.deb> install a .deb (Linux)\n"
" | pmm install -msi <x.msi> install an .msi (Windows)\n"
" | pmm install --git <repo>\n");
return 1;
}
/* collect one or more package arguments (each may carry an inline version
* spec like nodejs>=24,<25); optional -v/--version applies to a single one */
const char *version = NULL;
int forced = 0; /* 1 = -dpkg, 2 = -msi (install a local package by type) */
const char *items[64]; int ni = 0;
for (int i = 2; i < argc; i++) {
const char *a = argv[i];
if (strcmp(a, "-dpkg") == 0) { forced = 1; if (i + 1 < argc) items[ni++] = argv[++i]; continue; }
if (strcmp(a, "-msi") == 0) { forced = 2; if (i + 1 < argc) items[ni++] = argv[++i]; continue; }
if (strncmp(a, "-v", 2) == 0 && a[2]) { version = a + 2; continue; }
if (strcmp(a, "-v") == 0 && i + 1 < argc) { version = argv[++i]; continue; }
if (strcmp(a, "--version") == 0 && i + 1 < argc) { version = argv[++i]; continue; }
@@ -443,6 +462,13 @@ int main(int argc, char **argv) {
if (pdm_install_file(pkg) == 0) ok++; else fprintf(stderr, "pmm: failed to install %s\n", pkg);
continue;
}
/* local file install: forced -dpkg/-msi, or an existing installer file
* (e.g. `pmm install foo.deb` / `pmm install foo.msi`) */
if (forced == 1 || forced == 2 || has_installer_ext(pkg)) {
if (install_local_file(pkg) == 0) ok++;
else fprintf(stderr, "pmm: failed to install %s\n", pkg);
continue;
}
if (install_from_registry(pkg, spec[0] ? spec : NULL, mirror.name) == 0) ok++;
}
free(cfg.registry_url); free(cfg.mirror_name);