drop standalone pdm; all functionality in pmm (install local .pdm, pack, info, list, remove, self-update); remove pdm from builds/workflow

这个提交包含在:
JGZYES
2026-08-30 20:16:23 +08:00
父节点 3d8e319f8f
当前提交 9095c74785
修改 6 个文件,包含 67 行新增217 行删除
+3 -5
查看文件
@@ -6,6 +6,9 @@ on:
- 'v*'
workflow_dispatch:
permissions:
contents: write
jobs:
build:
strategy:
@@ -41,10 +44,6 @@ jobs:
src/main.c src/json.c src/ini.c src/pmm.c src/http.c src/repo.c src/install.c \
src/sha256.c src/sha1.c src/mirrors.c src/pdm.c
- name: Build pdm
run: |
${{ matrix.cc }} -O2 -Wall -static -std=c11 -o out/pdm${{ matrix.ext }} \
src/pdm_main.c src/pdm.c src/pmm.c src/sha256.c src/install.c src/http.c \
src/json.c src/ini.c src/mirrors.c src/sha1.c
- name: Upload artifact
@@ -60,6 +59,5 @@ jobs:
with:
files: |
out/pmm${{ matrix.ext }}
out/pdm${{ matrix.ext }}
generate_release_notes: true
name: PMM ${{ github.ref_name }}
+7 -14
查看文件
@@ -2,28 +2,21 @@ CC ?= gcc
CFLAGS ?= -O2 -Wall -static -Wextra -std=c11
PREFIX ?= /usr/local
CORE = src/main.c src/json.c src/ini.c src/pmm.c src/http.c src/repo.c \
SRC = src/main.c src/json.c src/ini.c src/pmm.c src/http.c src/repo.c \
src/install.c src/sha256.c src/sha1.c src/mirrors.c src/pdm.c
all: pmm pdm
all: pmm
pmm: $(CORE) $(wildcard src/*.h)
$(CC) $(CFLAGS) -o $@ $(CORE)
pmm: $(SRC) $(wildcard src/*.h)
$(CC) $(CFLAGS) -o $@ $(SRC)
PDM_DEPS = src/pdm_main.c src/pdm.c src/pmm.c src/sha256.c src/install.c \
src/http.c src/json.c src/ini.c src/mirrors.c src/sha1.c
pdm: $(PDM_DEPS) $(wildcard src/*.h)
$(CC) $(CFLAGS) -o $@ $(PDM_DEPS)
install: all
install: pmm
install -m 755 pmm $(PREFIX)/bin/pmm
install -m 755 pdm $(PREFIX)/bin/pdm
uninstall:
rm -f $(PREFIX)/bin/pmm $(PREFIX)/bin/pdm
rm -f $(PREFIX)/bin/pmm
clean:
rm -f pmm pdm pmm.exe pdm.exe
rm -f pmm pmm.exe
.PHONY: all install uninstall clean
+8 -9
查看文件
@@ -8,12 +8,12 @@
## 构建
```sh
make # Linux / macOS(或任何有 make 的环境),生成 pmm + pdm 两个二进制
build.bat # Windows(只需 MinGW gcc),同样生成 pmm.exe + pdm.exe
make # Linux / macOS(或任何有 make 的环境),生成 pmm 二进制
build.bat # Windows(只需 MinGW gcc),生成 pmm.exe
make install # 安装到 /usr/local/bin(可选)
```
产物是单文件 `pmm` / `pdm`(或 `.exe`),无 DLL/第三方库依赖。
产物是单文件 `pmm`(或 `pmm.exe`),无 DLL/第三方库依赖。
> 重要:Windows 构建须用**静态链接**`-static`)。否则产物会依赖 MinGW 的
> `libmcfgthread-2.dll`,在没装 MinGW 的普通 PowerShell 里会因为找不到该 DLL 而
@@ -36,7 +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 self-update # 从镜像安装最新版 pmm(自动识别本机 os/arch
pmm list
pmm help / version
pmm install <pkg> -pd # 安装到 D:\.pmm(可换成 -pc 回到 C 盘,-px 任意盘)
@@ -69,14 +69,14 @@ SHA 实现为纯 C 内置(FIPS 180-4),无外部依赖。
## .pdm 包格式(模拟 dpkg 的 deb
`pdm pack ./目录` 会把目录打包成一个 `.pdm`(一个 tar 归档,含
`pmm pack ./目录` 会把目录打包成一个 `.pdm`(一个 tar 归档,含
`control.tar.gz` / `data.tar.gz` / `sha256sums` 三个成员,与 deb 的
`control.tar`+`data.tar` 思路一致):
- 目录里需有一个 `pdm-control` 文件,格式为 `KEY: value` 行:
`Package` / `Version` / `Architecture` / `Description` / `Maintainer`
- 其余文件全部作为文件有效载荷,安装时解包到安装根目录(`~/.pmm/root`
- `pdm install <pkg.pdm>` / `pmm install <pkg.pdm>` 安装,`pdm remove` 卸载
- `pmm install <pkg.pdm>` 安装,`pmm remove` 卸载
- 安装记录写入 `~/.pmm/installed/<包名>.info`,含文件清单,用于卸载
## apt 式镜像(mirror.ini / mirror.conf
@@ -181,7 +181,7 @@ pmm install "nodejs>=24,<25" # 带空格/组合时加引号
## 自动加入 PATH
每次成功安装后,pmm/pdm 会把 PMM 目录 **自动加入用户 PATH**(幂等,不重复):
每次成功安装后,pmm 会把 PMM 目录 **自动加入用户 PATH**(幂等,不重复):
- 始终加入 `~/.pmm/bin` 与 `~/.pmm/root`;
- 还会扫描 `~/.pmm/root/` 下含有可执行文件的子目录并加入,例如安装 Node.js 后
@@ -204,7 +204,7 @@ pmm install "nodejs>=24,<25" # 带空格/组合时加引号
**自动按当前系统选平台**
```sh
pdmm install nodejs # Windows 上装 node.exe 版,Linux 上自动装 ELF 版
pmm install nodejs # Windows 上装 node.exe 版,Linux 上自动装 ELF 版
pmm install nodejs
```
@@ -240,7 +240,6 @@ src/sha256.c/.h SHA-256FIPS 180-4
src/sha1.c/.h SHA-1FIPS 180-4
src/mirrors.c/.h apt 式镜像列表(priority 排序 + 下载回退)
src/pdm.c/.h .pdm 打包/安装/卸载(模拟 deb)
src/pdm_main.c 独立 pdm 工具
src/install.c/.h 下载、校验与各平台安装
mirror/ 镜像站(Node.js 网页版)
examples/ 配置文件示例
+2 -4
查看文件
@@ -1,8 +1,6 @@
@echo off
rem One-shot Windows build: produces pmm.exe and pdm.exe (needs MinGW gcc + curl in PATH)
rem One-shot Windows build: produces pmm.exe (needs MinGW gcc + curl in PATH)
set SRC=src\main.c src\json.c src\ini.c src\pmm.c src\http.c src\repo.c src\install.c src\sha256.c src\sha1.c src\mirrors.c src\pdm.c
gcc -O2 -Wall -static -Wextra -std=c11 -o pmm.exe %SRC%
if errorlevel 1 (echo pmm build failed & exit /b 1)
gcc -O2 -Wall -static -Wextra -std=c11 -o pdm.exe src\pdm_main.c src\pdm.c src\pmm.c src\sha256.c src\install.c src\http.c src\json.c src\ini.c src\mirrors.c src\sha1.c
if errorlevel 1 (echo pdm build failed & exit /b 1)
echo built pmm.exe and pdm.exe
echo built pmm.exe
+46 -62
查看文件
@@ -273,27 +273,17 @@ static int cmd_mirror(int argc, char **argv) {
return 1;
}
static int cmd_list(void) {
char dir[1024];
pmm_install_dir(dir, sizeof(dir));
printf("install dir: %s\n", dir);
#ifdef _WIN32
char cmd[1200];
snprintf(cmd, sizeof(cmd), "dir /b \"%s\" 2>nul", dir);
#else
char cmd[1200];
snprintf(cmd, sizeof(cmd), "ls -1 \"%s\" 2>/dev/null", dir);
#endif
return system(cmd) == 0 ? 0 : 0;
}
static void print_help(void) {
printf("ParlzPackageManger (PMM) v%s\n\n", PMM_VERSION);
printf("usage:\n");
printf(" pmm install <pkg> install from registry mirrors (apt-style)\n");
printf(" pmm install <file.pdm> install a local .pdm package\n");
printf(" pmm install <pkg> [pkg2 ...] install several packages\n");
printf(" pmm pack <dir> [out.pdm] pack a folder into a .pdm\n");
printf(" pmm pdm install|list|remove|info ... manage .pdm packages\n");
printf(" pmm info <file.pdm> show package control info\n");
printf(" pmm list list installed packages\n");
printf(" pmm remove <pkg> uninstall a package\n");
printf(" pmm self-update update pmm (auto os/arch)\n");
printf(" pmm install --git <repo-url.git> any git host, API auto-detected\n");
printf(" pmm install --github <owner/repo> GitHub latest release\n");
printf(" pmm install --gitlab <owner/repo> GitLab latest release\n");
@@ -349,7 +339,7 @@ int main(int argc, char **argv) {
printf("pmm %s (%s) [%s]\n", PMM_VERSION, pmm_os_name(pmm_detect_os()), pmm_detect_arch());
return 0;
}
if (strcmp(argv[1], "list") == 0) return cmd_list();
if (strcmp(argv[1], "list") == 0) { pdm_list_installed(); return 0; }
if (strcmp(argv[1], "mirror") == 0) return cmd_mirror(argc - 2, argv + 2);
/* pmm remove <pkg> (also used by the Windows "Uninstall" registration) */
if (strcmp(argv[1], "remove") == 0) {
@@ -378,55 +368,57 @@ 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.pdm> [...] | pmm install --git <repo>\n");
return 1;
}
/* parse package name + optional version spec:
* pmm install nodejs==24.20.0
* pmm install "nodejs>=24,<25"
* pmm install nodejs -v 24.20.0 / --version ">=24,<25" */
const char *raw_pkg = NULL, *version = NULL;
/* 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;
const char *items[64]; int ni = 0;
for (int i = 2; i < argc; i++) {
const char *a = argv[i];
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; }
if (strncmp(a, "--version=", 10) == 0) { version = a + 10; continue; }
if (!raw_pkg && a[0] != '-') { raw_pkg = a; continue; }
if (a[0] != '-' && ni < 64) items[ni++] = a;
}
if (!raw_pkg) raw_pkg = argv[2];
/* split "nodejs>=24,<25" -> pkg="nodejs", spec=">=24,<25"; else pkg only */
char pkg[256], spec[256];
if (version && *version) {
strncpy(pkg, raw_pkg, sizeof(pkg) - 1);
strncpy(spec, version, sizeof(spec) - 1);
} else {
const char *ops[] = { ">=", "<=", "==", "!=", ">", "<", NULL };
const char *pos = NULL;
for (int i = 0; ops[i]; i++) { pos = strstr(raw_pkg, ops[i]); if (pos) break; }
if (pos) {
size_t n = (size_t)(pos - raw_pkg);
if (n >= sizeof(pkg)) n = sizeof(pkg) - 1;
memcpy(pkg, raw_pkg, n); pkg[n] = '\0';
strncpy(spec, pos, sizeof(spec) - 1);
} else {
strncpy(pkg, raw_pkg, sizeof(pkg) - 1);
spec[0] = '\0';
}
}
pkg[sizeof(pkg) - 1] = '\0'; spec[sizeof(spec) - 1] = '\0';
/* local .pdm file? */
size_t la = strlen(pkg);
if (la > 4 && (strcmp(pkg + la - 4, ".pdm") == 0 || strcmp(pkg + la - 4, ".PDM") == 0))
return pdm_install_file(pkg) == 0 ? 0 : 1;
if (ni == 0) items[ni++] = argv[2];
PmmConfig cfg; MirrorSel mirror;
load_config(&cfg);
load_mirror(&cfg, &mirror);
/* apt-style: mirrors.first-wins by priority, active mirror if named */
int rc = install_from_registry(pkg, spec[0] ? spec : NULL, mirror.name);
int ok = 0;
for (int k = 0; k < ni; k++) {
const char *raw = items[k];
char pkg[256], spec[256];
if (ni == 1 && version && *version) {
strncpy(pkg, raw, sizeof(pkg) - 1); pkg[sizeof(pkg)-1] = '\0';
strncpy(spec, version, sizeof(spec) - 1); spec[sizeof(spec)-1] = '\0';
} else {
const char *ops[] = { ">=", "<=", "==", "!=", ">", "<", NULL };
const char *pos = NULL;
for (int i = 0; ops[i]; i++) { pos = strstr(raw, ops[i]); if (pos) break; }
if (pos) {
size_t n = (size_t)(pos - raw);
if (n >= sizeof(pkg)) n = sizeof(pkg) - 1;
memcpy(pkg, raw, n); pkg[n] = '\0';
strncpy(spec, pos, sizeof(spec) - 1); spec[sizeof(spec)-1] = '\0';
} else {
strncpy(pkg, raw, sizeof(pkg) - 1); pkg[sizeof(pkg)-1] = '\0';
spec[0] = '\0';
}
}
size_t la = strlen(pkg);
if (la > 4 && (strcmp(pkg + la - 4, ".pdm") == 0 || strcmp(pkg + la - 4, ".PDM") == 0)) {
if (pdm_install_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);
free(mirror.name); free(mirror.api_base);
return rc == 0 ? 0 : 1;
return ok == ni ? 0 : 1;
}
if (strcmp(argv[1], "pack") == 0) {
@@ -437,17 +429,9 @@ int main(int argc, char **argv) {
return pdm_pack(argv[2], argc >= 4 ? argv[3] : NULL) == 0 ? 0 : 1;
}
if (strcmp(argv[1], "pdm") == 0) {
/* pmm pdm install/list/remove/info (sugar for the standalone pdm tool) */
if (argc >= 3 && strcmp(argv[2], "install") == 0)
return pdm_install_file(argc >= 4 ? argv[3] : NULL) == 0 ? 0 : 1;
if (argc >= 3 && strcmp(argv[2], "list") == 0) { pdm_list_installed(); return 0; }
if (argc >= 3 && strcmp(argv[2], "remove") == 0)
return pdm_remove(argc >= 4 ? argv[3] : NULL) == 0 ? 0 : 1;
if (argc >= 3 && strcmp(argv[2], "info") == 0)
return pdm_info(argc >= 4 ? argv[3] : NULL) == 0 ? 0 : 1;
fprintf(stderr, "pmm: usage: pmm pdm install|list|remove|info ...\n");
return 1;
if (strcmp(argv[1], "info") == 0) {
if (argc < 3) { fprintf(stderr, "pmm: usage: pmm info <file.pdm>\n"); return 1; }
return pdm_info(argv[2]) == 0 ? 0 : 1;
}
fprintf(stderr, "pmm: unknown command '%s' (try 'pmm help')\n", argv[1]);
-122
查看文件
@@ -1,122 +0,0 @@
/* pdm_main.c - standalone `pdm` tool (pack/install/remove/info/list)
*
* usage:
* pdm pack <dir> [output.pdm] pack a folder (with pdm-control) into .pdm
* pdm install <file.pdm> install local .pdm
* pdm info <file.pdm> show package control info
* pdm list list installed packages
* pdm remove <name> remove installed package
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "pdm.h"
#include "pmm.h"
#include "install.h"
static void usage(void) {
printf("pdm - Parlz .pdm package tool\n\n"
"usage:\n"
" pdm pack <dir> [output.pdm] pack folder (needs pdm-control) into .pdm\n"
" pdm install <file.pdm> install local .pdm\n"
" pdm install <pkg> [-v <ver>] install from registry (pmm mirror)\n"
" pdm info <file.pdm> show control info\n"
" pdm list list installed packages\n"
" pdm remove <name> remove installed package\n"
"options: -p<drive> install under <DRIVE>:\\.pdm (e.g. -pd -> D:\\.pdm)\n");
}
/* Parse "-p<drive>" / "-p <drive>" and compact argv; records the drive so
* pdm installs under <DRIVE>:\.pmm. */
static int consume_drive_flag(int argc, char **argv) {
int w = 1;
for (int r = 1; r < argc; r++) {
const char *a = argv[r];
if (a[0] == '-' && a[1] == 'p' && (a[2] >= 'A' && a[2] <= 'Z' || a[2] >= 'a' && a[2] <= 'z')) {
char dr[2] = { a[2], '\0' };
pmm_set_install_drive(dr);
continue;
}
if (strcmp(a, "-p") == 0 && r + 1 < argc) {
const char *nxt = argv[r + 1];
if (nxt[0] && (nxt[0] >= 'A' && nxt[0] <= 'Z' || nxt[0] >= 'a' && nxt[0] <= 'z') && nxt[1] == '\0') {
char dr[2] = { nxt[0], '\0' };
pmm_set_install_drive(dr);
r++;
continue;
}
}
argv[w++] = argv[r];
}
return w;
}
int main(int argc, char **argv) {
if (argc < 2) { usage(); return 0; }
pmm_set_self_path(argv[0]);
argc = consume_drive_flag(argc, argv);
if (argc < 2) { usage(); return 0; }
/* version: pdm -v / --version */
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-v") == 0) {
printf("pdm %s (%s) [%s]\n", PMM_VERSION, pmm_os_name(pmm_detect_os()), pmm_detect_arch());
return 0;
}
/* self-update: install the latest pmm tool package (contains pmm + pdm) */
if (strcmp(argv[1], "update") == 0 || strcmp(argv[1], "self-update") == 0) {
printf("pdm: updating pmm+pdm for %s/%s\n", pmm_os_name(pmm_detect_os()), pmm_detect_arch());
int rc = install_from_registry("pmm", NULL, NULL);
if (rc == 0)
printf("pdm: updated. New tools are under %s/root/bin\n",
pmm_config_dir((char[1024]){0}, 1024));
return rc == 0 ? 0 : 1;
}
if (strcmp(argv[1], "pack") == 0) {
if (argc < 3) { fprintf(stderr, "pdm: usage: pdm pack <dir> [output.pdm]\n"); return 1; }
return pdm_pack(argv[2], argc >= 4 ? argv[3] : NULL) == 0 ? 0 : 1;
}
if (strcmp(argv[1], "install") == 0 || strcmp(argv[1], "-i") == 0) {
if (argc < 3) { fprintf(stderr, "pdm: usage: pdm install <file.pdm|pkg> [-v ver]\n"); return 1; }
/* parse [pkg] [ -v <ver> ] ; pkg may be "nodejs==24.20.0" / "nodejs>=24,<25" */
const char *raw = NULL, *version = NULL;
for (int i = 2; i < argc; i++) {
const char *a = argv[i];
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; }
if (strncmp(a, "--version=", 10) == 0) { version = a + 10; continue; }
if (!raw && a[0] != '-') { raw = a; continue; }
}
if (!raw) raw = argv[2];
char pkg[256], spec[256];
if (version && *version) {
strncpy(pkg, raw, sizeof(pkg) - 1);
strncpy(spec, version, sizeof(spec) - 1);
} else {
const char *ops[] = { ">=", "<=", "==", "!=", ">", "<", NULL };
const char *pos = NULL;
for (int i = 0; ops[i]; i++) { pos = strstr(raw, ops[i]); if (pos) break; }
if (pos) { size_t n = (size_t)(pos - raw); if (n >= sizeof(pkg)) n = sizeof(pkg) - 1; memcpy(pkg, raw, n); pkg[n] = '\0'; strncpy(spec, pos, sizeof(spec) - 1); }
else { strncpy(pkg, raw, sizeof(pkg) - 1); spec[0] = '\0'; }
}
pkg[sizeof(pkg) - 1] = '\0'; spec[sizeof(spec) - 1] = '\0';
size_t l = strlen(pkg);
if (l > 4 && (strcmp(pkg + l - 4, ".pdm") == 0 || strcmp(pkg + l - 4, ".PDM") == 0))
return pdm_install_file(pkg) == 0 ? 0 : 1;
/* otherwise treat as a registry package name */
return install_from_registry(pkg, spec[0] ? spec : NULL, NULL) == 0 ? 0 : 1;
}
if (strcmp(argv[1], "info") == 0) {
if (argc < 3) { fprintf(stderr, "pdm: usage: pdm info <file.pdm>\n"); return 1; }
return pdm_info(argv[2]) == 0 ? 0 : 1;
}
if (strcmp(argv[1], "list") == 0 || strcmp(argv[1], "-l") == 0) {
pdm_list_installed();
return 0;
}
if (strcmp(argv[1], "remove") == 0 || strcmp(argv[1], "-r") == 0) {
if (argc < 3) { fprintf(stderr, "pdm: usage: pdm remove <name>\n"); return 1; }
return pdm_remove(argv[2]) == 0 ? 0 : 1;
}
usage();
return 1;
}