diff --git a/README.md b/README.md index 9ff6cca..0058ce9 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ pmm install --gitea https://git.example.com/owner/repo # Gitea/Forgejo(含 pmm install --git owner/repo --host forgejo # 强制指定主机类型 pmm mirror list / add <名> <源> / use <名> / remove <名> +pmm self-update # 从镜像安装最新版 pmm+pdm(自动识别本机 os/arch) pmm list pmm help / version pmm install -pd # 安装到 D:\.pmm(可换成 -pc 回到 C 盘,-px 任意盘) diff --git a/src/install.c b/src/install.c index 5edaba8..4118ca1 100644 --- a/src/install.c +++ b/src/install.c @@ -303,6 +303,11 @@ static const char *cur_os_name(void) { switch (pmm_detect_os()) { case OS_WINDOWS: return "windows"; case OS_LINUX: return "linux"; case OS_MACOS: return "macos"; default: return "any"; } } +static const char *cur_arch_name(void) { + const char *av = getenv("PMM_ARCH_OVERRIDE"); /* debug/testing */ + if (av && *av) return av; + return pmm_detect_arch(); +} int install_from_registry(const char *name, const char *spec, const char *mirror_active) { if (!name || !*name) return -1; @@ -364,18 +369,21 @@ int install_from_registry(const char *name, const char *spec, const char *mirror } const char *osn = cur_os_name(); + const char *arch = cur_arch_name(); JsonValue *variants = json_get(meta, "variants"); const char *dl = NULL, *file = NULL; char *want_sha = NULL; const char *chosen = NULL; if (variants && variants->count > 0) { - /* pick highest variant that matches OS (or 'any') + version spec */ + /* pick highest variant matching OS + ARCH (or 'any') + version spec */ const char *bestver = NULL; for (int i = 0; i < variants->count; i++) { JsonValue *v = json_at(variants, i); if (!v || v->type != JSON_OBJECT) continue; const char *vos = json_str(v, "os"); if (!vos) continue; if (strcmp(vos, osn) != 0 && strcmp(vos, "any") != 0) continue; + const char *varch = json_str(v, "arch"); + if (varch && varch[0] && strcmp(varch, arch) != 0 && strcmp(varch, "any") != 0) continue; const char *ver = json_str(v, "version"); if (!ver) continue; if (spec && *spec && !spec_match(ver, spec)) continue; if (!bestver || vcmp(ver, bestver) > 0) { bestver = ver; chosen = ver; @@ -383,11 +391,11 @@ int install_from_registry(const char *name, const char *spec, const char *mirror const char *s = json_str(v, "sha256"); free(want_sha); want_sha = s ? strdup(s) : NULL; } } if (!chosen) { - fprintf(stderr, "pmm: no version of '%s' for os=%s%s%s\n", name, osn, + fprintf(stderr, "pmm: no version of '%s' for os=%s arch=%s%s%s\n", name, osn, arch, (spec && *spec) ? " satisfying '" : "", (spec && *spec) ? spec : ""); json_free(meta); mirrors_free(ml); return -1; } - printf("pmm: selected %s@%s (os=%s)\n", name, chosen, osn); + printf("pmm: selected %s@%s (os=%s arch=%s)\n", name, chosen, osn, arch); } else { /* legacy single-platform entry */ dl = json_str(meta, "url"); file = json_str(meta, "file"); diff --git a/src/main.c b/src/main.c index 2ccb5ea..c5cef0d 100644 --- a/src/main.c +++ b/src/main.c @@ -356,6 +356,21 @@ int main(int argc, char **argv) { if (argc < 3) { fprintf(stderr, "pmm: usage: pmm remove \n"); return 1; } return pdm_remove(argv[2]) == 0 ? 0 : 1; } + /* pmm self-update: install the latest 'pmm' tool package (auto os+arch) */ + if (strcmp(argv[1], "self-update") == 0 || strcmp(argv[1], "update") == 0) { + PmmConfig cfg; MirrorSel mirror; + load_config(&cfg); + load_mirror(&cfg, &mirror); + printf("pmm: self-update -> installing latest pmm (%s/%s)\n", + pmm_os_name(pmm_detect_os()), pmm_detect_arch()); + int rc = install_from_registry("pmm", NULL, mirror.name); + free(cfg.registry_url); free(cfg.mirror_name); + free(mirror.name); free(mirror.api_base); + if (rc == 0) + printf("pmm: updated. New tools are under %s/bin (pmm/pdm). Re-run from there, or add it to PATH.\n", + pmm_config_dir((char[1024]){0}, 1024)); + return rc == 0 ? 0 : 1; + } if (strcmp(argv[1], "install") == 0) { if (argc >= 3 && (strcmp(argv[2], "--git") == 0 || strcmp(argv[2], "--github") == 0 || diff --git a/src/pmm.c b/src/pmm.c index b999e6d..04ac0c7 100644 --- a/src/pmm.c +++ b/src/pmm.c @@ -58,6 +58,25 @@ const char *pmm_os_name(PmmOS os) { } } +const char *pmm_detect_arch(void) { +#if defined(_WIN32) + /* Windows: x64 vs arm64 (ARM64 / AMD64 env) */ + const char *p = getenv("PROCESSOR_ARCHITECTURE"); + if (p && (strcmp(p, "ARM64") == 0 || strcmp(p, "arm64") == 0)) return "aarch64"; + const char *w = getenv("PROCESSOR_ARCHITEW6432"); + if (w && (strcmp(w, "ARM64") == 0)) return "aarch64"; + return "amd64"; +#elif defined(__aarch64__) || defined(__arm64__) + return "aarch64"; +#elif defined(__x86_64__) || defined(_M_X64) + return "amd64"; +#elif defined(__i386__) || defined(__i686__) || defined(_M_IX86) + return "x86"; +#else + return "any"; +#endif +} + static void mkdir_p(const char *path) { char tmp[1024]; strncpy(tmp, path, sizeof(tmp) - 1); diff --git a/src/pmm.h b/src/pmm.h index c116e58..996bd40 100644 --- a/src/pmm.h +++ b/src/pmm.h @@ -45,6 +45,9 @@ const char *pmm_self_path(void); typedef enum { OS_WINDOWS, OS_LINUX, OS_MACOS, OS_UNKNOWN } PmmOS; +/* CPU architecture name string: "amd64", "aarch64", "arm64", "x86", ... */ +const char *pmm_detect_arch(void); + typedef enum { HOST_GITHUB, HOST_GITLAB, HOST_GITEA, HOST_FORGEJO, HOST_AUTO, HOST_UNKNOWN } PmmHost; PmmOS pmm_detect_os(void);