noldoj-cli 0.0.0-stage → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -2
- package/bin/noldoj.js +132 -0
- package/package.json +32 -4
package/README.md
CHANGED
|
@@ -1,3 +1,49 @@
|
|
|
1
|
-
#
|
|
1
|
+
# NoldOJ CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
NoldOJ 评测平台的跨平台命令行客户端。配置站点地址与私人令牌后,可以在终端管理题目、提交代码、参加比赛,或像 `gh api` 一样直接请求该站点的任意接口。
|
|
4
|
+
|
|
5
|
+
- 文档:<https://nojc.dxxj.de5.net>
|
|
6
|
+
- 源码:<https://github.com/dxxjudges/noldoj-cli>
|
|
7
|
+
- 发布:<https://github.com/dxxjudges/noldoj-cli/releases>
|
|
8
|
+
|
|
9
|
+
> CLI 本身不包含题目或数据,也不内置服务器地址:必须先配置一个可访问的 NoldOJ 站点与私人令牌,否则命令无法工作。
|
|
10
|
+
|
|
11
|
+
## 安装
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g noldoj-cli
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
也可直接从 [Releases](https://github.com/dxxjudges/noldoj-cli/releases) 下载对应平台的二进制:Linux x64/x86/arm64、macOS x64/arm64、Windows x64/x86/arm64 均已提供。Android / Termux 请在 Termux 内从源码编译。
|
|
18
|
+
|
|
19
|
+
npm 包在首次运行时才会下载对应平台的二进制,缓存在 `~/.noldoj-cli/bin/<版本>/`;可用 `NOLDOJ_CLI_CACHE` 改变缓存位置,或用 `NOLDOJ_CLI_BIN` 直接指定已有可执行文件。
|
|
20
|
+
|
|
21
|
+
## 快速开始
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
noldoj site add --name main --url https://your-oj.example.com --token <私人令牌>
|
|
25
|
+
noldoj auth tokeninfo
|
|
26
|
+
noldoj problem list --page 1
|
|
27
|
+
noldoj help problem
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 凭据
|
|
31
|
+
|
|
32
|
+
令牌不会明文落盘:`credentials.json` 使用 AES-256-CTR + HMAC-SHA256 加密,主密钥为首次启动时生成的 256 位随机密钥,保存在系统凭据库(Windows 凭据管理器 / macOS 钥匙串 / Linux Secret Service),不可用时回退到配置目录下权限 0600 的 `master.key`。用 `noldoj config path` 查看实际位置。
|
|
33
|
+
|
|
34
|
+
## 从源码构建
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone https://github.com/dxxjudges/noldoj-cli.git
|
|
38
|
+
cd noldoj-cli
|
|
39
|
+
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
|
|
40
|
+
cmake --build build
|
|
41
|
+
python tests/run_tests.py build/noldoj # Windows 为 build/noldoj.exe
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Windows 使用系统 WinHTTP,其余平台使用 libcurl(Linux 需 `libcurl4-openssl-dev`,macOS 使用系统 libcurl)。
|
|
45
|
+
|
|
46
|
+
## 发布
|
|
47
|
+
|
|
48
|
+
- 提交信息为 `build X.Y.Z` 或打 `vX.Y.Z` 标签时,GitHub Actions 会构建全部平台并创建 Release。
|
|
49
|
+
- npm 包版本通过 `npm version patch|minor|major` 更新,不要手改 `package.json` 的版本号。
|
package/bin/noldoj.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// NoldOJ CLI 的 npm 启动器:按平台下载对应 Release 二进制并缓存,然后透传参数执行。
|
|
5
|
+
// 安装阶段不联网;首次运行(或版本变化后)才下载。
|
|
6
|
+
|
|
7
|
+
const { spawn } = require("node:child_process");
|
|
8
|
+
const fs = require("node:fs");
|
|
9
|
+
const https = require("node:https");
|
|
10
|
+
const os = require("node:os");
|
|
11
|
+
const path = require("node:path");
|
|
12
|
+
|
|
13
|
+
const VERSION = require("../package.json").version;
|
|
14
|
+
const REPO = "dxxjudges/noldoj-cli";
|
|
15
|
+
|
|
16
|
+
const ASSETS = {
|
|
17
|
+
"win32-x64": "noldoj-windows-x64.exe",
|
|
18
|
+
"win32-ia32": "noldoj-windows-x86.exe",
|
|
19
|
+
"win32-arm64": "noldoj-windows-arm64.exe",
|
|
20
|
+
"linux-x64": "noldoj-linux-x64",
|
|
21
|
+
"linux-ia32": "noldoj-linux-x86",
|
|
22
|
+
"linux-arm64": "noldoj-linux-arm64",
|
|
23
|
+
"darwin-x64": "noldoj-macos-x64",
|
|
24
|
+
"darwin-arm64": "noldoj-macos-arm64",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function assetName() {
|
|
28
|
+
const key = `${process.platform}-${process.arch}`;
|
|
29
|
+
return ASSETS[key] || null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function cacheDir() {
|
|
33
|
+
const root = process.env.NOLDOJ_CLI_CACHE || path.join(os.homedir(), ".noldoj-cli", "bin");
|
|
34
|
+
return path.join(root, VERSION);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function download(url, target, redirects = 0) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
if (redirects > 5) {
|
|
40
|
+
reject(new Error("下载重定向次数过多"));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
https
|
|
44
|
+
.get(url, { headers: { "user-agent": `noldoj-cli-npm/${VERSION}` } }, (response) => {
|
|
45
|
+
const status = response.statusCode || 0;
|
|
46
|
+
if (status >= 300 && status < 400 && response.headers.location) {
|
|
47
|
+
response.resume();
|
|
48
|
+
download(response.headers.location, target, redirects + 1).then(resolve, reject);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (status !== 200) {
|
|
52
|
+
response.resume();
|
|
53
|
+
reject(new Error(`下载失败(HTTP ${status}):${url}`));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const temporary = `${target}.part`;
|
|
58
|
+
const stream = fs.createWriteStream(temporary, { mode: 0o755 });
|
|
59
|
+
response.pipe(stream);
|
|
60
|
+
stream.on("finish", () => {
|
|
61
|
+
stream.close(() => {
|
|
62
|
+
try {
|
|
63
|
+
fs.renameSync(temporary, target);
|
|
64
|
+
resolve();
|
|
65
|
+
} catch (error) {
|
|
66
|
+
reject(error);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
stream.on("error", (error) => {
|
|
71
|
+
fs.rmSync(temporary, { force: true });
|
|
72
|
+
reject(error);
|
|
73
|
+
});
|
|
74
|
+
})
|
|
75
|
+
.on("error", (error) => {
|
|
76
|
+
reject(new Error(`无法连接下载服务器:${error.message}`));
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function ensureBinary(asset) {
|
|
82
|
+
const target = path.join(cacheDir(), asset);
|
|
83
|
+
if (fs.existsSync(target)) return target;
|
|
84
|
+
|
|
85
|
+
fs.mkdirSync(cacheDir(), { recursive: true });
|
|
86
|
+
const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${asset}`;
|
|
87
|
+
process.stderr.write(`noldoj-cli: 正在下载 ${asset}(v${VERSION})…\n`);
|
|
88
|
+
await download(url, target);
|
|
89
|
+
if (process.platform !== "win32") fs.chmodSync(target, 0o755);
|
|
90
|
+
return target;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function main() {
|
|
94
|
+
const override = process.env.NOLDOJ_CLI_BIN;
|
|
95
|
+
const asset = assetName();
|
|
96
|
+
|
|
97
|
+
if (!override && !asset) {
|
|
98
|
+
process.stderr.write(
|
|
99
|
+
`noldoj-cli: 暂不支持 ${process.platform}/${process.arch} 的预编译二进制。\n` +
|
|
100
|
+
`请从 https://github.com/${REPO} 下载源码编译,或设置 NOLDOJ_CLI_BIN 指向已有可执行文件。\n`
|
|
101
|
+
);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let binary = override;
|
|
106
|
+
if (!binary) {
|
|
107
|
+
try {
|
|
108
|
+
binary = await ensureBinary(asset);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
process.stderr.write(
|
|
111
|
+
`noldoj-cli: ${error.message}\n` +
|
|
112
|
+
`可手动下载 v${VERSION} 的 Release 资产,或用 NOLDOJ_CLI_BIN 指定路径。\n`
|
|
113
|
+
);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const child = spawn(binary, process.argv.slice(2), { stdio: "inherit" });
|
|
119
|
+
child.on("error", (error) => {
|
|
120
|
+
process.stderr.write(`noldoj-cli: 无法启动 ${binary}:${error.message}\n`);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
});
|
|
123
|
+
child.on("exit", (code, signal) => {
|
|
124
|
+
if (signal) {
|
|
125
|
+
process.kill(process.pid, signal);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
process.exit(code === null ? 1 : code);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "noldoj-cli",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "NoldOJ 评测平台的跨平台命令行客户端:配置站点与私人令牌后,即可在终端刷题、出题、打比赛,或直接调用任意 API",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"noldoj",
|
|
7
|
+
"oj",
|
|
8
|
+
"online-judge",
|
|
9
|
+
"cli",
|
|
10
|
+
"competitive-programming"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://nojc.dxxj.de5.net",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/dxxjudges/noldoj-cli/issues"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/dxxjudges/noldoj-cli.git"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"bin": {
|
|
22
|
+
"noldoj": "bin/noldoj.js"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"bin/",
|
|
26
|
+
"README.md"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"test": "node --check bin/noldoj.js"
|
|
33
|
+
}
|
|
34
|
+
}
|