镜像自地址
https://github.com/JGZYES/ParlzPackageManger.git
已同步 2026-09-11 08:52:45 +08:00
feat: pmm cache clean; install --no-cache; --git repo@tag / -b branch (specific release)
这个提交包含在:
@@ -152,10 +152,13 @@ static int native_binary_ok(const char *path, PmmOS os) {
|
|||||||
|
|
||||||
static int install_path(const char *path, const char *name);
|
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) {
|
int install_file(const char *url, const char *name) {
|
||||||
char cache[1024], path[1200];
|
char cache[1024], path[1200];
|
||||||
pmm_cache_dir(cache, sizeof(cache));
|
pmm_cache_dir(cache, sizeof(cache));
|
||||||
snprintf(path, sizeof(path), "%s/%s", cache, name);
|
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 */
|
/* apt-style fallback: mirrors (by priority) first, then the origin URL */
|
||||||
MirrorList *ml = mirrors_load();
|
MirrorList *ml = mirrors_load();
|
||||||
|
|||||||
@@ -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). */
|
* `pmm install -dpkg foo.deb` (Linux) or `pmm install -msi foo.msi` (Windows). */
|
||||||
int install_local_file(const char *path);
|
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):
|
/* Install from a remote registry (apt-style multi-mirror fallback):
|
||||||
* looks up package `name` in the configured registry mirrors by priority.
|
* looks up package `name` in the configured registry mirrors by priority.
|
||||||
* If `version` is non-NULL, fetches {registry}/{name}/{version}.json, otherwise
|
* If `version` is non-NULL, fetches {registry}/{name}/{version}.json, otherwise
|
||||||
|
|||||||
+54
@@ -18,6 +18,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -261,9 +266,50 @@ static int cmd_verify(int argc, char **argv) {
|
|||||||
return 0;
|
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>] */
|
/* <flag> <repo-ish> [--host <name>] */
|
||||||
static int cmd_install_git(int argc, char **argv, const char *flag) {
|
static int cmd_install_git(int argc, char **argv, const char *flag) {
|
||||||
const char *repo = NULL;
|
const char *repo = NULL;
|
||||||
|
const char *branch = NULL;
|
||||||
PmmHost host = HOST_AUTO;
|
PmmHost host = HOST_AUTO;
|
||||||
PmmConfig cfg; MirrorSel mirror;
|
PmmConfig cfg; MirrorSel mirror;
|
||||||
load_config(&cfg);
|
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]);
|
fprintf(stderr, "pmm: unknown host '%s'\n", argv[i]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
} else if ((strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--branch") == 0) && i + 1 < argc) {
|
||||||
|
branch = argv[++i];
|
||||||
} else if (!repo) {
|
} else if (!repo) {
|
||||||
repo = argv[i];
|
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);
|
RepoContext *ctx = repo_open(host, repo, mirror.api_base);
|
||||||
if (!ctx) return 1;
|
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,
|
printf("pmm: host=%s repo=%s%s%s\n", host_name(host), repo,
|
||||||
mirror.name ? " mirror=" : "", mirror.name ? mirror.name : "");
|
mirror.name ? " mirror=" : "", mirror.name ? mirror.name : "");
|
||||||
|
|
||||||
@@ -539,6 +588,7 @@ int main(int argc, char **argv) {
|
|||||||
const char *items[64]; int ni = 0;
|
const char *items[64]; int ni = 0;
|
||||||
for (int i = 2; i < argc; i++) {
|
for (int i = 2; i < argc; i++) {
|
||||||
const char *a = argv[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, "-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 (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 (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)
|
if (strcmp(argv[1], "search") == 0)
|
||||||
return cmd_search(argc - 2, argv + 2);
|
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)
|
if (strcmp(argv[1], "info") == 0)
|
||||||
return cmd_info(argc - 2, argv + 2);
|
return cmd_info(argc - 2, argv + 2);
|
||||||
if (strcmp(argv[1], "verify") == 0)
|
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));
|
RepoContext *ctx = calloc(1, sizeof(RepoContext));
|
||||||
if (!ctx) return NULL;
|
if (!ctx) return NULL;
|
||||||
ctx->host = host;
|
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];
|
char api[1024];
|
||||||
ctx->repo_norm = strdup(norm);
|
ctx->repo_norm = strdup(norm);
|
||||||
|
|
||||||
char origin[512];
|
char origin[512];
|
||||||
extract_origin(repo, origin, sizeof(origin));
|
extract_origin(repo_src, origin, sizeof(origin));
|
||||||
ctx->origin = strdup(origin);
|
ctx->origin = strdup(origin);
|
||||||
|
|
||||||
const char *base = NULL;
|
const char *base = NULL;
|
||||||
@@ -155,6 +167,7 @@ void repo_close(RepoContext *ctx) {
|
|||||||
free(ctx->page_url);
|
free(ctx->page_url);
|
||||||
free(ctx->origin);
|
free(ctx->origin);
|
||||||
free(ctx->repo_norm);
|
free(ctx->repo_norm);
|
||||||
|
free(ctx->ref);
|
||||||
free(ctx);
|
free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,10 +346,12 @@ ReleaseAsset *repo_latest_asset(RepoContext *ctx, PmmOS os) {
|
|||||||
|
|
||||||
switch (ctx->host) {
|
switch (ctx->host) {
|
||||||
case HOST_GITLAB:
|
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;
|
break;
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
return fetch_latest(url, ctx->host, os, NULL);
|
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) {
|
ReleaseAsset *repo_asset_matching(RepoContext *ctx, PmmOS os, const char *name_sub) {
|
||||||
if (!ctx || !ctx->api_url || !name_sub) return NULL;
|
if (!ctx || !ctx->api_url || !name_sub) return NULL;
|
||||||
char url[2048];
|
char url[2048];
|
||||||
if (ctx->host == HOST_GITLAB)
|
if (ctx->host == 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
|
else snprintf(url, sizeof(url), "%s/releases/permalink/latest", ctx->api_url);
|
||||||
snprintf(url, sizeof(url), "%s/releases/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);
|
return fetch_latest(url, ctx->host, os, name_sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -16,6 +16,7 @@ typedef struct {
|
|||||||
char *page_url; /* resolved raw/home endpoint */
|
char *page_url; /* resolved raw/home endpoint */
|
||||||
char *origin; /* scheme://host for full URLs (HOST_AUTO probing) */
|
char *origin; /* scheme://host for full URLs (HOST_AUTO probing) */
|
||||||
char *repo_norm; /* normalized "owner/repo" */
|
char *repo_norm; /* normalized "owner/repo" */
|
||||||
|
char *ref; /* optional specific release tag/branch (repo@ref); "" = latest */
|
||||||
} RepoContext;
|
} RepoContext;
|
||||||
|
|
||||||
/* Detect host from a repo slug like "owner/repo" or a full URL. */
|
/* Detect host from a repo slug like "owner/repo" or a full URL. */
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户