feat: pmm cache clean; install --no-cache; --git repo@tag / -b branch (specific release)

这个提交包含在:
JGZYES
2026-09-02 18:10:22 +08:00
父节点 f4d9da3cf9
当前提交 bd558e5c29
修改 5 个文件,包含 87 行新增8 行删除
+3
查看文件
@@ -152,10 +152,13 @@ static int native_binary_ok(const char *path, PmmOS os) {
static int install_path(const char *path, const char *name);
int pmm_no_cache = 0; /* --no-cache: drop cached file before download */
int install_file(const char *url, const char *name) {
char cache[1024], path[1200];
pmm_cache_dir(cache, sizeof(cache));
snprintf(path, sizeof(path), "%s/%s", cache, name);
if (pmm_no_cache) remove(path); /* force a fresh download */
/* apt-style fallback: mirrors (by priority) first, then the origin URL */
MirrorList *ml = mirrors_load();
+3
查看文件
@@ -10,6 +10,9 @@ int install_file(const char *url, const char *name);
* `pmm install -dpkg foo.deb` (Linux) or `pmm install -msi foo.msi` (Windows). */
int install_local_file(const char *path);
/* Set by `pmm install --no-cache` to force a fresh download (drop cache file). */
extern int pmm_no_cache;
/* 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
+54
查看文件
@@ -18,6 +18,11 @@
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
@@ -261,9 +266,50 @@ static int cmd_verify(int argc, char **argv) {
return 0;
}
/* Recursively delete a directory (for the download cache). */
static void rm_tree(const char *dir) {
#ifdef _WIN32
char pat[1200]; snprintf(pat, sizeof(pat), "%s\\*", dir);
WIN32_FIND_DATAA fd; HANDLE h = FindFirstFileA(pat, &fd);
if (h != INVALID_HANDLE_VALUE) {
do {
if (strcmp(fd.cFileName, ".") == 0 || strcmp(fd.cFileName, "..") == 0) continue;
char full[1400]; snprintf(full, sizeof(full), "%s\\%s", dir, fd.cFileName);
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) rm_tree(full);
else DeleteFileA(full);
} while (FindNextFileA(h, &fd));
FindClose(h);
}
RemoveDirectoryA(dir);
#else
DIR *d = opendir(dir);
if (!d) return;
struct dirent *e;
while ((e = readdir(d))) {
if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue;
char full[1400]; snprintf(full, sizeof(full), "%s/%s", dir, e->d_name);
struct stat st;
if (stat(full, &st) == 0 && S_ISDIR(st.st_mode)) rm_tree(full);
else remove(full);
}
closedir(d);
rmdir(dir);
#endif
}
/* pmm cache clean — wipe the download cache. */
static int cmd_cache_clean(void) {
char dir[1024];
pmm_cache_dir(dir, sizeof(dir));
printf("pmm: cleaning cache %s\n", dir);
rm_tree(dir);
return 0;
}
/* <flag> <repo-ish> [--host <name>] */
static int cmd_install_git(int argc, char **argv, const char *flag) {
const char *repo = NULL;
const char *branch = NULL;
PmmHost host = HOST_AUTO;
PmmConfig cfg; MirrorSel mirror;
load_config(&cfg);
@@ -281,6 +327,8 @@ static int cmd_install_git(int argc, char **argv, const char *flag) {
fprintf(stderr, "pmm: unknown host '%s'\n", argv[i]);
return 1;
}
} else if ((strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--branch") == 0) && i + 1 < argc) {
branch = argv[++i];
} else if (!repo) {
repo = argv[i];
}
@@ -299,6 +347,7 @@ static int cmd_install_git(int argc, char **argv, const char *flag) {
RepoContext *ctx = repo_open(host, repo, mirror.api_base);
if (!ctx) return 1;
if (branch && *branch) { free(ctx->ref); ctx->ref = strdup(branch); }
printf("pmm: host=%s repo=%s%s%s\n", host_name(host), repo,
mirror.name ? " mirror=" : "", mirror.name ? mirror.name : "");
@@ -539,6 +588,7 @@ int main(int argc, char **argv) {
const char *items[64]; int ni = 0;
for (int i = 2; i < argc; i++) {
const char *a = argv[i];
if (strcmp(a, "--no-cache") == 0) { pmm_no_cache = 1; continue; }
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; }
@@ -613,6 +663,10 @@ int main(int argc, char **argv) {
if (strcmp(argv[1], "search") == 0)
return cmd_search(argc - 2, argv + 2);
if (strcmp(argv[1], "cache") == 0) {
if (argc >= 3 && strcmp(argv[2], "clean") == 0) return cmd_cache_clean();
fprintf(stderr, "pmm: usage: pmm cache clean\n"); return 1;
}
if (strcmp(argv[1], "info") == 0)
return cmd_info(argc - 2, argv + 2);
if (strcmp(argv[1], "verify") == 0)
+26 -8
查看文件
@@ -93,12 +93,24 @@ RepoContext *repo_open(PmmHost host, const char *repo, const char *mirror_api_ba
RepoContext *ctx = calloc(1, sizeof(RepoContext));
if (!ctx) return NULL;
ctx->host = host;
char *norm = normalize_repo(repo);
/* support "repo@ref" (e.g. owner/repo@v1.2.3) → specific release tag */
const char *lastslash = strrchr(repo, '/');
const char *at = strrchr(repo, '@');
char repo_buf[1024];
const char *repo_src = repo;
if (at && lastslash && at > lastslash) {
snprintf(repo_buf, sizeof(repo_buf), "%.*s", (int)(at - repo), repo);
repo_src = repo_buf;
ctx->ref = strdup(at + 1);
} else {
ctx->ref = strdup("");
}
char *norm = normalize_repo(repo_src);
char api[1024];
ctx->repo_norm = strdup(norm);
char origin[512];
extract_origin(repo, origin, sizeof(origin));
extract_origin(repo_src, origin, sizeof(origin));
ctx->origin = strdup(origin);
const char *base = NULL;
@@ -155,6 +167,7 @@ void repo_close(RepoContext *ctx) {
free(ctx->page_url);
free(ctx->origin);
free(ctx->repo_norm);
free(ctx->ref);
free(ctx);
}
@@ -333,10 +346,12 @@ ReleaseAsset *repo_latest_asset(RepoContext *ctx, PmmOS os) {
switch (ctx->host) {
case HOST_GITLAB:
snprintf(url, sizeof(url), "%s/releases/permalink/latest", ctx->api_url);
if (ctx->ref && *ctx->ref) { char *e = url_encode(ctx->ref); snprintf(url, sizeof(url), "%s/releases/%s", ctx->api_url, e); free(e); }
else snprintf(url, sizeof(url), "%s/releases/permalink/latest", ctx->api_url);
break;
default:
snprintf(url, sizeof(url), "%s/releases/latest", ctx->api_url);
if (ctx->ref && *ctx->ref) { char *e = url_encode(ctx->ref); snprintf(url, sizeof(url), "%s/releases/tags/%s", ctx->api_url, e); free(e); }
else snprintf(url, sizeof(url), "%s/releases/latest", ctx->api_url);
break;
}
return fetch_latest(url, ctx->host, os, NULL);
@@ -349,10 +364,13 @@ ReleaseAsset *repo_latest_asset(RepoContext *ctx, PmmOS os) {
ReleaseAsset *repo_asset_matching(RepoContext *ctx, PmmOS os, const char *name_sub) {
if (!ctx || !ctx->api_url || !name_sub) return NULL;
char url[2048];
if (ctx->host == HOST_GITLAB)
snprintf(url, sizeof(url), "%s/releases/permalink/latest", ctx->api_url);
else
snprintf(url, sizeof(url), "%s/releases/latest", ctx->api_url);
if (ctx->host == HOST_GITLAB) {
if (ctx->ref && *ctx->ref) { char *e = url_encode(ctx->ref); snprintf(url, sizeof(url), "%s/releases/%s", ctx->api_url, e); free(e); }
else snprintf(url, sizeof(url), "%s/releases/permalink/latest", ctx->api_url);
} else {
if (ctx->ref && *ctx->ref) { char *e = url_encode(ctx->ref); snprintf(url, sizeof(url), "%s/releases/tags/%s", ctx->api_url, e); free(e); }
else snprintf(url, sizeof(url), "%s/releases/latest", ctx->api_url);
}
return fetch_latest(url, ctx->host, os, name_sub);
}
+1
查看文件
@@ -16,6 +16,7 @@ typedef struct {
char *page_url; /* resolved raw/home endpoint */
char *origin; /* scheme://host for full URLs (HOST_AUTO probing) */
char *repo_norm; /* normalized "owner/repo" */
char *ref; /* optional specific release tag/branch (repo@ref); "" = latest */
} RepoContext;
/* Detect host from a repo slug like "owner/repo" or a full URL. */