add pmm self-update + arch-aware variant selection; package pmm tools (win/linux/linux-aarch64)

- pmm_detect_arch(): amd64/aarch64/x86 from PROCESSOR_ARCHITECTURE or __aarch64__/__x86_64__
- install_from_registry: match variants by os AND arch (variant.arch) + version spec
- pmm self-update: installs latest 'pmm' tool package (auto os+arch) to <root>/bin
- pmm tools packed as pmm-0.1.0-<os>-<arch>.pdm for self-update
这个提交包含在:
JGZYES
2026-08-30 19:11:13 +08:00
父节点 b41a6d01f1
当前提交 1aa9c3a416
修改 5 个文件,包含 49 行新增3 行删除
+1
查看文件
@@ -36,6 +36,7 @@ pmm install --gitea https://git.example.com/owner/repo # Gitea/Forgejo(含
pmm install --git owner/repo --host forgejo # 强制指定主机类型 pmm install --git owner/repo --host forgejo # 强制指定主机类型
pmm mirror list / add <名> <源> / use <名> / remove <名> pmm mirror list / add <名> <源> / use <名> / remove <名>
pmm self-update # 从镜像安装最新版 pmm+pdm(自动识别本机 os/arch
pmm list pmm list
pmm help / version pmm help / version
pmm install <pkg> -pd # 安装到 D:\.pmm(可换成 -pc 回到 C 盘,-px 任意盘) pmm install <pkg> -pd # 安装到 D:\.pmm(可换成 -pc 回到 C 盘,-px 任意盘)
+11 -3
查看文件
@@ -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"; switch (pmm_detect_os()) { case OS_WINDOWS: return "windows"; case OS_LINUX: return "linux";
case OS_MACOS: return "macos"; default: return "any"; } 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) { int install_from_registry(const char *name, const char *spec, const char *mirror_active) {
if (!name || !*name) return -1; 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 *osn = cur_os_name();
const char *arch = cur_arch_name();
JsonValue *variants = json_get(meta, "variants"); JsonValue *variants = json_get(meta, "variants");
const char *dl = NULL, *file = NULL; const char *dl = NULL, *file = NULL;
char *want_sha = NULL; char *want_sha = NULL;
const char *chosen = NULL; const char *chosen = NULL;
if (variants && variants->count > 0) { 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; const char *bestver = NULL;
for (int i = 0; i < variants->count; i++) { for (int i = 0; i < variants->count; i++) {
JsonValue *v = json_at(variants, i); JsonValue *v = json_at(variants, i);
if (!v || v->type != JSON_OBJECT) continue; if (!v || v->type != JSON_OBJECT) continue;
const char *vos = json_str(v, "os"); if (!vos) continue; const char *vos = json_str(v, "os"); if (!vos) continue;
if (strcmp(vos, osn) != 0 && strcmp(vos, "any") != 0) 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; const char *ver = json_str(v, "version"); if (!ver) continue;
if (spec && *spec && !spec_match(ver, spec)) continue; if (spec && *spec && !spec_match(ver, spec)) continue;
if (!bestver || vcmp(ver, bestver) > 0) { bestver = ver; chosen = ver; 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; } const char *s = json_str(v, "sha256"); free(want_sha); want_sha = s ? strdup(s) : NULL; }
} }
if (!chosen) { 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 : ""); (spec && *spec) ? " satisfying '" : "", (spec && *spec) ? spec : "");
json_free(meta); mirrors_free(ml); return -1; 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 { } else {
/* legacy single-platform entry */ /* legacy single-platform entry */
dl = json_str(meta, "url"); file = json_str(meta, "file"); dl = json_str(meta, "url"); file = json_str(meta, "file");
+15
查看文件
@@ -356,6 +356,21 @@ int main(int argc, char **argv) {
if (argc < 3) { fprintf(stderr, "pmm: usage: pmm remove <pkg>\n"); return 1; } if (argc < 3) { fprintf(stderr, "pmm: usage: pmm remove <pkg>\n"); return 1; }
return pdm_remove(argv[2]) == 0 ? 0 : 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 (strcmp(argv[1], "install") == 0) {
if (argc >= 3 && (strcmp(argv[2], "--git") == 0 || strcmp(argv[2], "--github") == 0 || if (argc >= 3 && (strcmp(argv[2], "--git") == 0 || strcmp(argv[2], "--github") == 0 ||
+19
查看文件
@@ -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) { static void mkdir_p(const char *path) {
char tmp[1024]; char tmp[1024];
strncpy(tmp, path, sizeof(tmp) - 1); strncpy(tmp, path, sizeof(tmp) - 1);
+3
查看文件
@@ -45,6 +45,9 @@ const char *pmm_self_path(void);
typedef enum { OS_WINDOWS, OS_LINUX, OS_MACOS, OS_UNKNOWN } PmmOS; 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; typedef enum { HOST_GITHUB, HOST_GITLAB, HOST_GITEA, HOST_FORGEJO, HOST_AUTO, HOST_UNKNOWN } PmmHost;
PmmOS pmm_detect_os(void); PmmOS pmm_detect_os(void);