镜像自地址
https://github.com/JGZYES/ParlzPackageManger.git
已同步 2026-09-11 05:42:44 +08:00
release: PMM v0.6.0 + ppdm v0.0.2 — 站点版本/文档/CI 版本提升
- pmm 0.6.0: 结构化错误码(见前), 站点 PMM_VERSION + install.sh 版本 + 文档版本 - ppdm 0.0.2: 新增 list/del 命令(客户端) + web/ppdm/list.php/del.php 后端 - CI: ppdm 构建版本 0.0.1 -> 0.0.2 - docs: ppdm.md 加 list/del, download/install 文档 0.5.6 -> 0.6.0 - CHANGELOG 0.6.0 增 ppdm 0.0.2 全量发布说明
这个提交包含在:
@@ -59,8 +59,8 @@ jobs:
|
||||
${{ matrix.cc }} -O2 -Wall -static -std=c11 -D_GNU_SOURCE -D_FORTIFY_SOURCE=0 -U_FORTIFY_SOURCE -DPMM_VERSION=\"$VER\" -o out/${{ matrix.bin }} \
|
||||
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 src/out.c src/i18n.c
|
||||
# -- ppdm package dev tool (register/login/update/pack/publish) — own version 0.0.1
|
||||
${{ matrix.cc }} -O2 -Wall -static -std=c11 -D_GNU_SOURCE -D_FORTIFY_SOURCE=0 -U_FORTIFY_SOURCE -DPPDM_VERSION=\"0.0.1\" -o out/${{ matrix.ppdm }} \
|
||||
# -- ppdm package dev tool (register/login/list/del/update/pack/publish) — own version 0.0.2
|
||||
${{ matrix.cc }} -O2 -Wall -static -std=c11 -D_GNU_SOURCE -D_FORTIFY_SOURCE=0 -U_FORTIFY_SOURCE -DPPDM_VERSION=\"0.0.2\" -o out/${{ matrix.ppdm }} \
|
||||
src/ppdm.c src/pmm.c src/json.c src/ini.c src/http.c src/repo.c src/install.c \
|
||||
src/sha256.c src/sha1.c src/mirrors.c src/pdm.c src/out.c src/i18n.c
|
||||
|
||||
|
||||
+8
-1
@@ -24,4 +24,11 @@
|
||||
## 说明
|
||||
- 兼容性:错误码在 0.6.0 起稳定;旧脚本若匹配 `[PMM]:[ERROR]:` 前缀,建议改用
|
||||
`[PMM]:[E<NN>]:`(`<NN>` 为两位数字错误码)。
|
||||
- `ppdm` 仍为独立版本 `0.0.1`,本次同步接入错误码格式。
|
||||
|
||||
## 同步:ppdm v0.0.2
|
||||
- **新增 `ppdm list`**:列出当前账号已发布的包(`name@version os/arch + url`)。
|
||||
- **新增 `ppdm del <pkg> [version]`**:删除自己已发布的包,可只删某个版本。
|
||||
- **后端新增 `web/ppdm/list.php`、`web/ppdm/del.php`**(按 `owner` 鉴权,他人包拒绝)。
|
||||
- **ppdm 0.0.2 全量发布**:像 pmm 一样打 `.pdm` 进镜像(`dists/`+`files/`),
|
||||
可用 `pmm install ppdm` 安装;`install-ppdm.sh` 与 GitHub Release 资产同时更新。
|
||||
- ppdm 版本从 `0.0.1` 升到 `0.0.2`(独立于 PMM 0.6.0)。
|
||||
|
||||
+36
-1
@@ -22,7 +22,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#ifndef PPDM_VERSION
|
||||
#define PPDM_VERSION "0.0.1" /* ppdm has its own version, independent of PMM */
|
||||
#define PPDM_VERSION "0.0.2" /* ppdm has its own version, independent of PMM */
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -206,6 +206,8 @@ static void usage(void) {
|
||||
" ppdm logout 撤销并清除本地 token\n"
|
||||
" ppdm whoami 当前登录邮箱 + 服务器\n"
|
||||
" ppdm pack <dir> [out] 把 <dir> 打包成 .pdm(需含 pdm-control)\n"
|
||||
" ppdm list 列出当前账号已发布的包\n"
|
||||
" ppdm del <pkg> [version] 删除自己已发布的包(可只删某版本)\n"
|
||||
" ppdm update 更新 ppdm 自身\n"
|
||||
" ppdm ./xxxx.pdm 发布包(自动生成 json)\n"
|
||||
" ppdm help | -h 帮助\n\n"
|
||||
@@ -310,6 +312,39 @@ int main(int argc, char **argv) {
|
||||
return pdm_pack(argv[2], argc >= 4 ? argv[3] : NULL) == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
/* ---- list : packages owned by the current account ---- */
|
||||
if (strcmp(argv[1], "list") == 0) {
|
||||
if (!g_token[0]) { pmm_error_c(PMM_E_USAGE, "请先执行 ppdm login", "请先 ppdm login\n"); return 1; }
|
||||
snprintf(url, sizeof(url), "%s/list.php", g_server);
|
||||
snprintf(auth, sizeof(auth), "-H 'Authorization: Bearer %s'", g_token);
|
||||
http_post(url, auth, "{}", NULL, resp, sizeof(resp));
|
||||
if (js_ok(resp)) {
|
||||
char list[8192];
|
||||
js_val(resp, "list", list, sizeof(list));
|
||||
if (list[0]) printf("当前账号已发布的包:\n%s\n", list);
|
||||
else pmm_info("当前账号还没有发布任何包\n");
|
||||
} else js_err_print(resp);
|
||||
return js_ok(resp) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* ---- del <pkg> [version] : remove a package you own ---- */
|
||||
if (strcmp(argv[1], "del") == 0 || strcmp(argv[1], "rm") == 0) {
|
||||
if (argc < 3) { pmm_error_c(PMM_E_USAGE, "用法: ppdm del <包名> [版本]", "用法: ppdm del <pkg> [version]\n"); return 1; }
|
||||
if (!g_token[0]) { pmm_error_c(PMM_E_USAGE, "请先执行 ppdm login", "请先 ppdm login\n"); return 1; }
|
||||
char q[2300];
|
||||
if (argc >= 4) snprintf(q, sizeof(q), "%s/del.php?name=%s&version=%s", g_server, argv[2], argv[3]);
|
||||
else snprintf(q, sizeof(q), "%s/del.php?name=%s", g_server, argv[2]);
|
||||
snprintf(auth, sizeof(auth), "-H 'Authorization: Bearer %s'", g_token);
|
||||
http_post(q, auth, "{}", NULL, resp, sizeof(resp));
|
||||
if (js_ok(resp)) {
|
||||
char removed[256] = "";
|
||||
js_val(resp, "removed", removed, sizeof(removed));
|
||||
if (argc >= 4) pmm_success("已删除 %s 的版本 %s\n", argv[2], argv[3]);
|
||||
else pmm_success("已删除包 %s\n", argv[2]);
|
||||
} else js_err_print(resp);
|
||||
return js_ok(resp) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* ---- update : download the latest ppdm and install it under ~/.ppdm/bin/ppdm ---- */
|
||||
if (strcmp(argv[1], "update") == 0) {
|
||||
char dir[1024], bin[1400], tmp[1500];
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
* then pmm_header($active,$title); ... pmm_footer(); */
|
||||
if (!defined('PMM_SITE')) { http_response_code(403); exit('forbidden'); }
|
||||
|
||||
define('PMM_VERSION', '0.5.6');
|
||||
define('PMM_VERSION', '0.6.0');
|
||||
|
||||
function pmm_nav_links(string $active): string {
|
||||
$items = [
|
||||
|
||||
+7
-7
@@ -10,22 +10,22 @@ curl -sSL https://pmm.parlz.com/download/install.sh | bash
|
||||
|
||||
## 各平台产物(`/download/`)
|
||||
|
||||
- [pmm-0.5.6-windows-amd64.zip](/download/pmm-0.5.6-windows-amd64.zip) — Windows 免安装
|
||||
- [pmm_0.5.6_amd64.deb](/download/pmm_0.5.6_amd64.deb) — Debian/Ubuntu
|
||||
- [pmm-0.5.6.x86_64.rpm](/download/pmm-0.5.6.x86_64.rpm) — CentOS/RHEL
|
||||
- [pmm-0.5.6.apk](/download/pmm-0.5.6.apk) — Alpine
|
||||
- [pmm-0.5.6.pkg.tar.zst](/download/pmm-0.5.6.pkg.tar.zst) — Arch
|
||||
- [pmm-0.6.0-windows-amd64.zip](/download/pmm-0.6.0-windows-amd64.zip) — Windows 免安装
|
||||
- [pmm_0.6.0_amd64.deb](/download/pmm_0.6.0_amd64.deb) — Debian/Ubuntu
|
||||
- [pmm-0.6.0.x86_64.rpm](/download/pmm-0.6.0.x86_64.rpm) — CentOS/RHEL
|
||||
- [pmm-0.6.0.apk](/download/pmm-0.6.0.apk) — Alpine
|
||||
- [pmm-0.6.0.pkg.tar.zst](/download/pmm-0.6.0.pkg.tar.zst) — Arch
|
||||
- [pmm](/download/pmm) — Linux 二进制
|
||||
- [pmm.exe](/download/pmm.exe) — Windows 二进制
|
||||
- [install.sh](/download/install.sh) — 一键安装脚本
|
||||
- [install-ppdm.sh](/download/install-ppdm.sh) — ppdm 开发者工具一键安装脚本
|
||||
|
||||
> `.pdm` 包走镜像注册表:`pmm install pmm==0.5.6`(见 [镜像源](index.php?page=mirror))。
|
||||
> `.pdm` 包走镜像注册表:`pmm install pmm==0.6.0`(见 [镜像源](index.php?page=mirror))。
|
||||
|
||||
## 用 pmm 安装(从镜像注册表)
|
||||
|
||||
```bash
|
||||
pmm install pmm==0.5.6
|
||||
pmm install pmm==0.6.0
|
||||
pmm install nodejs
|
||||
```
|
||||
|
||||
|
||||
+4
-4
@@ -14,7 +14,7 @@ curl -sSL https://pmm.parlz.com/download/install.sh | bash
|
||||
|
||||
```bash
|
||||
# PowerShell
|
||||
Invoke-WebRequest https://pmm.parlz.com/download/pmm-0.5.6-windows-amd64.zip -OutFile pmm.zip
|
||||
Invoke-WebRequest https://pmm.parlz.com/download/pmm-0.6.0-windows-amd64.zip -OutFile pmm.zip
|
||||
Expand-Archive pmm.zip -DestinationPath pmm
|
||||
```
|
||||
|
||||
@@ -23,21 +23,21 @@ Expand-Archive pmm.zip -DestinationPath pmm
|
||||
## Debian / Ubuntu(.deb)
|
||||
|
||||
```bash
|
||||
curl -L -o pmm.deb https://pmm.parlz.com/download/pmm_0.5.6_amd64.deb
|
||||
curl -L -o pmm.deb https://pmm.parlz.com/download/pmm_0.6.0_amd64.deb
|
||||
sudo apt install ./pmm.deb
|
||||
```
|
||||
|
||||
## CentOS / RHEL(.rpm)
|
||||
|
||||
```bash
|
||||
curl -L -o pmm.rpm https://pmm.parlz.com/download/pmm-0.5.6.x86_64.rpm
|
||||
curl -L -o pmm.rpm https://pmm.parlz.com/download/pmm-0.6.0.x86_64.rpm
|
||||
sudo rpm -Uvh pmm.rpm
|
||||
```
|
||||
|
||||
## 用 pmm 安装 pmm 自身
|
||||
|
||||
```bash
|
||||
pmm install pmm==0.5.6
|
||||
pmm install pmm==0.6.0
|
||||
```
|
||||
|
||||
## 装好后
|
||||
|
||||
+17
-3
@@ -3,7 +3,7 @@
|
||||
`ppdm`(ParlzPackageDevManager)是 PMM 生态里的**开发者工具**:把软件打包成 `.pdm` 并发布到镜像注册表。
|
||||
它与 `pmm`(安装/使用包)分开,负责“做包、发包”。
|
||||
|
||||
- 版本:独立版本号(当前 `0.0.1`),不受 PMM 主版本影响。
|
||||
- 版本:独立版本号(当前 `0.0.2`),不受 PMM 主版本影响。
|
||||
- 服务端:`https://pmm.parlz.com/ppdm`(PHP,对应仓库 `web/ppdm/`)。
|
||||
- 配置:`~/.ppdm/config`(Linux)或 `D:\.ppdm\config`(Windows)。
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
```bash
|
||||
curl -sSL https://pmm.parlz.com/download/install-ppdm.sh | bash
|
||||
hash -r
|
||||
ppdm -v # ppdm 0.0.1
|
||||
ppdm -v # ppdm 0.0.2
|
||||
```
|
||||
|
||||
脚本会自动下载最新 `ppdm` 装到 `~/.ppdm/bin/ppdm`(与 `ppdm update` 同一路径),并把 `~/.ppdm/bin` 加进 PATH。
|
||||
@@ -34,7 +34,7 @@ ppdm update
|
||||
验证:
|
||||
|
||||
```bash
|
||||
ppdm -v # ppdm 0.0.1
|
||||
ppdm -v # ppdm 0.0.2
|
||||
ppdm help
|
||||
```
|
||||
|
||||
@@ -47,6 +47,8 @@ ppdm help
|
||||
| `ppdm logout` | 撤销并清除 token |
|
||||
| `ppdm whoami` | 显示当前邮箱 + 服务器 |
|
||||
| `ppdm pack <dir> [out]` | 把 `dir` 打包成 `.pdm`(`dir` 内需有 `pdm-control`) |
|
||||
| `ppdm list` | 列出当前账号已发布的包 |
|
||||
| `ppdm del <pkg> [version]` | 删除自己已发布的包(可只删某版本) |
|
||||
| `ppdm update` | 更新 ppdm 自身 |
|
||||
| `ppdm ./xxx.pdm` | 发布包(自动生成 json) |
|
||||
| `ppdm help` | 帮助 |
|
||||
@@ -113,6 +115,18 @@ ppdm ./myapp_1.0.0.pdm
|
||||
- 同版本重复上传 → 409;
|
||||
- 别人改你的包 → 409(阻止越权)。
|
||||
|
||||
#### 管理自己发布的包(`ppdm list` / `ppdm del`)
|
||||
|
||||
```bash
|
||||
ppdm list # 列出当前账号已发布的所有包(name@version os/arch + url)
|
||||
ppdm del myapp # 删除整个包(所有版本)
|
||||
ppdm del myapp 1.0.0 # 只删除某一个版本(其它版本保留)
|
||||
```
|
||||
|
||||
- `list` 需要先 `ppdm login`;只返回**当前账号作为 owner** 的包。
|
||||
- `del` 只能删自己创建的包;他人包会返回 `you are not the owner`。
|
||||
- 删整包时,`dists/<pkg>.json`、`dists/<pkg>/<ver>.json` 与 `files/<首字母>/<pkg>/*.pdm` 一并移除。
|
||||
|
||||
## 4. 用 pmm 安装刚发布的包
|
||||
|
||||
```bash
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
# 下载官方 release 二进制并安装到 ~/.pmm/root/bin/pmm(与 `pmm install pmm` 自升级同一路径,
|
||||
# 避免 install.sh 与 pmm self-update 两处安装“串”)。
|
||||
set -e
|
||||
VER="0.5.6"
|
||||
VER="0.6.0"
|
||||
REPO="JGZYES/ParlzPackageManger"
|
||||
|
||||
# ---- 检测平台 ----
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/* web/ppdm/del.php — delete a package (or one version) that the current account
|
||||
* owns. Requires a valid bearer token.
|
||||
* ?name=<pkg>[&version=<ver>] ver optional: omit to remove the whole package.
|
||||
* Returns {"ok":true,...} on success. A non-owner or unknown package is rejected. */
|
||||
define('PMM_SITE', 1);
|
||||
require __DIR__ . '/lib.php';
|
||||
|
||||
[$tok, $email] = pmu_require_auth_token();
|
||||
|
||||
$name = trim((string)($_GET['name'] ?? ($_POST['name'] ?? '')));
|
||||
$ver = trim((string)($_GET['version'] ?? ($_POST['version'] ?? '')));
|
||||
if (!preg_match('/^[A-Za-z0-9][A-Za-z0-9._-]*$/', $name)) pmu_fail('invalid package name');
|
||||
if ($ver !== '' && !preg_match('/^[A-Za-z0-9][A-Za-z0-9._-]*$/', $ver)) pmu_fail('invalid version');
|
||||
|
||||
$regDir = __DIR__ . '/../mirror/dists';
|
||||
$filesRoot = __DIR__ . '/../mirror/files';
|
||||
$pkgJson = $regDir . '/' . $name . '.json';
|
||||
|
||||
if (!is_file($pkgJson)) pmu_fail("package '$name' not found", 404);
|
||||
$m = json_decode(file_get_contents($pkgJson), true) ?: null;
|
||||
if (($m['owner'] ?? '') !== $email) pmu_fail("you are not the owner of '$name'", 403);
|
||||
|
||||
$letter = strtolower(substr($name, 0, 1));
|
||||
$pkgDir = $filesRoot . '/' . $letter . '/' . $name;
|
||||
|
||||
/* delete just one version */
|
||||
if ($ver !== '') {
|
||||
$new = []; $removed = 0;
|
||||
foreach (($m['variants'] ?? []) as $v) {
|
||||
if (($v['version'] ?? '') === $ver) {
|
||||
if (is_file($pkgDir . '/' . ($v['file'] ?? ''))) @unlink($pkgDir . '/' . $v['file']);
|
||||
$removed++;
|
||||
} else {
|
||||
$new[] = $v;
|
||||
}
|
||||
}
|
||||
if (!$removed) pmu_fail("version '$ver' not found in '$name'", 404);
|
||||
$m['variants'] = $new;
|
||||
if (!empty($new)) {
|
||||
file_put_contents($pkgJson, json_encode($m, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
} else {
|
||||
/* last version gone -> drop the whole package below */
|
||||
if (is_file($pkgJson)) @unlink($pkgJson);
|
||||
}
|
||||
@unlink($regDir . '/' . $name . '/' . $ver . '.json');
|
||||
if (empty($new)) {
|
||||
$vd = $regDir . '/' . $name;
|
||||
if (is_dir($vd)) { foreach (glob($vd . '/*') as $f) @unlink($f); @rmdir($vd); }
|
||||
$pk = $regDir . '/packages.json';
|
||||
$list = is_file($pk) ? (json_decode(file_get_contents($pk), true) ?: []) : [];
|
||||
$list = array_values(array_filter($list, fn($n) => $n !== $name));
|
||||
if (is_file($pk)) file_put_contents($pk, json_encode($list, JSON_PRETTY_PRINT));
|
||||
}
|
||||
pmu_ok(['name' => $name, 'version' => $ver, 'removed' => $removed]);
|
||||
}
|
||||
|
||||
/* delete the whole package */
|
||||
if (is_dir($pkgDir)) { foreach (glob($pkgDir . '/*') as $f) @unlink($f); @rmdir($pkgDir); }
|
||||
if (is_file($pkgJson)) @unlink($pkgJson);
|
||||
$vd = $regDir . '/' . $name;
|
||||
if (is_dir($vd)) { foreach (glob($vd . '/*') as $f) @unlink($f); @rmdir($vd); }
|
||||
$pk = $regDir . '/packages.json';
|
||||
$list = is_file($pk) ? (json_decode(file_get_contents($pk), true) ?: []) : [];
|
||||
$list = array_values(array_filter($list, fn($n) => $n !== $name));
|
||||
if (is_file($pk)) file_put_contents($pk, json_encode($list, JSON_PRETTY_PRINT));
|
||||
|
||||
pmu_ok(['name' => $name, 'removed' => true]);
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/* web/ppdm/list.php — list packages owned by the current account.
|
||||
* Requires a valid bearer token. Returns:
|
||||
* {"ok":true,"list":"name@ver os/arch description url\n..."}
|
||||
* The list field uses real newlines (the tiny C client reads it via substring
|
||||
* search, so we deliberately do NOT json_encode the newlines). */
|
||||
define('PMM_SITE', 1);
|
||||
require __DIR__ . '/lib.php';
|
||||
|
||||
[$tok, $email] = pmu_require_auth_token();
|
||||
|
||||
$regDir = __DIR__ . '/../mirror/dists';
|
||||
$out = [];
|
||||
foreach (glob($regDir . '/*.json') as $f) {
|
||||
if (basename($f) === 'packages.json') continue;
|
||||
$m = json_decode(file_get_contents($f), true) ?: [];
|
||||
if (($m['owner'] ?? '') !== $email) continue;
|
||||
foreach (($m['variants'] ?? []) as $v) {
|
||||
$nm = $v['name'] ?? ($m['name'] ?? '');
|
||||
$ver = $v['version'] ?? ($m['version'] ?? '');
|
||||
$os = $v['os'] ?? 'linux';
|
||||
$arch = $v['arch'] ?? 'amd64';
|
||||
$desc = $v['description'] ?? '';
|
||||
$url = $v['url'] ?? '';
|
||||
$out[] = sprintf("%s@%s %s/%s %s %s", $nm, $ver, $os, $arch, $desc, $url);
|
||||
}
|
||||
}
|
||||
$text = implode("\n", $out);
|
||||
echo '{"ok":true,"list":"' . $text . '"}';
|
||||
在新工单中引用
屏蔽一个用户