jvm-manager-cli 1.0.0 → 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/AGENTS.md ADDED
@@ -0,0 +1,191 @@
1
+ # AGENTS.md - jvm-manager
2
+
3
+ ## 项目概述
4
+
5
+ jvm-manager (`jvm-manager-cli`) 是一个纯 Node.js CLI 工具,用于在 Linux 上管理 JDK 安装。
6
+ 单文件架构 (`bin/jvm.js`),零运行时依赖,通过 npm 全局安装后提供 `jvm` 命令。
7
+
8
+ - **语言**: JavaScript (ES Modules)
9
+ - **运行时**: Node.js >= 14
10
+ - **模块系统**: ESM (`"type": "module"` in package.json)
11
+ - **依赖**: 零运行时依赖;仅 jest 作为 devDependency
12
+ - **平台**: 仅 Linux (Ubuntu/Debian, Fedora/CentOS/RHEL, Arch Linux)
13
+
14
+ ## 构建 / 测试 / 发布命令
15
+
16
+ ```bash
17
+ # 安装依赖
18
+ npm install
19
+
20
+ # 运行全部测试
21
+ npm test
22
+ # 等价于: node --experimental-vm-modules node_modules/jest/bin/jest.js
23
+
24
+ # 运行单个测试文件
25
+ node --experimental-vm-modules node_modules/jest/bin/jest.js test/basic.spec.mjs
26
+
27
+ # 运行匹配名称的测试
28
+ node --experimental-vm-modules node_modules/jest/bin/jest.js -t "should display help"
29
+
30
+ # 验证 CLI 可执行
31
+ npm run check # node bin/jvm.js --help
32
+
33
+ # 本地链接为全局命令
34
+ npm run link # npm unlink && npm link
35
+
36
+ # 构建 (仅拷贝文件到 dist/)
37
+ npm run build
38
+ ```
39
+
40
+ ### CI/CD
41
+
42
+ - GitHub Actions: `.github/workflows/publish.yml`
43
+ - 推送 `main` 分支触发构建,推送 `v*` 标签触发 npm 发布
44
+ - CI 使用 Node.js 18
45
+
46
+ ## 项目结构
47
+
48
+ ```
49
+ bin/jvm.js # 唯一源文件,包含所有业务逻辑 (~800 行)
50
+ shell/jvm.sh # Shell 集成脚本 (由 jvm init 输出,注入 CLI 路径)
51
+ test/
52
+ basic.spec.mjs # Jest 测试 (ESM, .spec.mjs 格式)
53
+ debug.js # 调试脚本 (非测试)
54
+ detectLatestBuild.js # 辅助脚本 (非测试)
55
+ installSystem.js # 辅助脚本 (非测试)
56
+ package.json
57
+ ```
58
+
59
+ ## 代码风格
60
+
61
+ ### 通用规则
62
+
63
+ - **无 linter/formatter 配置** — 项目未使用 ESLint/Prettier,遵循现有代码风格即可
64
+ - 缩进: 2 空格
65
+ - 字符串: 主文件 (`bin/jvm.js`) 使用**单引号**,测试文件使用**双引号**
66
+ - 分号: 必须加分号
67
+ - 行尾: LF (Unix)
68
+ - 最大行宽: 无硬性限制,但保持合理 (~120 字符)
69
+
70
+ ### 导入风格
71
+
72
+ ```javascript
73
+ // ESM import — 仅使用 Node.js 内置模块,无第三方依赖
74
+ import { execSync } from 'child_process';
75
+ import { existsSync, mkdirSync, readFileSync } from 'fs';
76
+ import { dirname, join, resolve } from 'path';
77
+ import { homedir } from 'os';
78
+
79
+ // 测试文件中也可使用 node: 前缀
80
+ import { existsSync, readdirSync } from 'node:fs';
81
+ ```
82
+
83
+ - 使用**命名导入** (named imports),不使用默认导入
84
+ - 主文件使用裸模块名 (`'fs'`),测试/调试脚本中也使用 `'node:fs'` 前缀
85
+ - 导入顺序: child_process → fs → path → os
86
+
87
+ ### 函数风格
88
+
89
+ - 所有功能使用**顶层 function 声明** (非箭头函数、非 class)
90
+ - 函数命名: camelCase
91
+ - 常量: UPPER_SNAKE_CASE(仅限模块级别常量)
92
+ - 无 async/await — 所有外部命令通过 `execSync` 同步执行
93
+
94
+ ```javascript
95
+ // 常量定义
96
+ const APP_NAME = 'jvm-manager';
97
+ const HOME = homedir();
98
+ const APP_DIR = join(HOME, '.local', 'share', APP_NAME);
99
+
100
+ // 函数定义
101
+ function install(version) { ... }
102
+ function listInstalled() { ... }
103
+ ```
104
+
105
+ ### 错误处理
106
+
107
+ ```javascript
108
+ // 致命错误: 使用 fail() 打印消息并 process.exit(1)
109
+ function fail(msg) {
110
+ console.error(`Error: ${msg}`);
111
+ process.exit(1);
112
+ }
113
+
114
+ // 外部命令执行: try/catch 包裹 execSync
115
+ try {
116
+ run('sudo apt update -qq');
117
+ } catch (err) {
118
+ console.error('Failed to update...');
119
+ fail('Failed to install OpenJDK');
120
+ }
121
+
122
+ // 顶层命令分发的 catch:
123
+ try { ... } catch (error) {
124
+ const message = error?.stderr || error?.message || String(error);
125
+ fail(message);
126
+ }
127
+ ```
128
+
129
+ - 使用 `console.error()` 输出错误信息
130
+ - 使用 `console.log()` 输出正常信息
131
+ - 非致命警告直接 `console.log(err)` 后继续
132
+
133
+ ### 外部命令执行
134
+
135
+ ```javascript
136
+ // 统一通过 run() 封装 execSync
137
+ function run(cmd, options = {}) {
138
+ return execSync(cmd, {
139
+ stdio: ['ignore', 'pipe', 'pipe'],
140
+ encoding: 'utf8',
141
+ ...options
142
+ }).trim();
143
+ }
144
+ ```
145
+
146
+ - 路径参数用双引号包裹: `run('readlink -f "' + path + '"')`
147
+ - 字符串拼接使用 `+` 运算符(非模板字符串),主文件中两者混用
148
+ - 模板字符串主要用于用户提示消息
149
+
150
+ ### 测试规范
151
+
152
+ - 框架: Jest 29,ESM 模式 (`--experimental-vm-modules`)
153
+ - 测试文件: `test/**/*.spec.mjs` 或 `test/**/*.test.js`
154
+ - 测试风格: `describe()` + `it()` (非 `test()`)
155
+ - 通过 `execSync` 调用 `node bin/jvm.js` 进行集成测试
156
+ - 断言: `expect(...).toContain()`, `expect(...).not.toThrowError()`
157
+
158
+ ```javascript
159
+ // 测试辅助函数
160
+ function runJvmCmd(cmd, options = {}) {
161
+ return execSync(`node bin/jvm.js ${cmd}`, {
162
+ encoding: "utf8",
163
+ stdio: "pipe",
164
+ ...options
165
+ }).trim();
166
+ }
167
+
168
+ describe("jvm CLI basic functionality", () => {
169
+ it("should display help information", () => {
170
+ const helpOutput = runJvmCmd("help");
171
+ expect(helpOutput.toLowerCase()).toContain("usage:");
172
+ });
173
+ });
174
+ ```
175
+
176
+ ## 关键约束
177
+
178
+ 1. **零依赖原则** — 不引入任何运行时第三方依赖
179
+ 2. **单文件架构** — 所有逻辑在 `bin/jvm.js` 中,如需拆分需与维护者确认
180
+ 3. **仅限 Linux** — 不考虑 macOS/Windows 兼容
181
+ 4. **同步执行** — 使用 `execSync`,不使用 async/await
182
+ 5. **ESM 模块** — 使用 `import`/`export`,不使用 `require()`
183
+ 6. **注释语言** — 代码注释使用中文或英文均可(现有代码中混用)
184
+ 7. **commit 消息** — 中文,格式: `fix: 修复xxx` / `feat: 新增xxx`
185
+
186
+ ## 数据目录
187
+
188
+ - 应用根目录: `~/.local/share/jvm-manager/`
189
+ - JDK 存储: `~/.local/share/jvm-manager/jdks/`
190
+ - 当前全局版本: `~/.local/share/jvm-manager/current` (符号链接)
191
+ - 项目版本: 项目根目录的 `.jvmrc` 文件
package/README.md CHANGED
@@ -1,224 +1,94 @@
1
1
  # jvm-manager
2
2
 
3
- jvm-manager 是一个用于在 Linux 系统上管理 Java 开发工具包 (JDK) 的命令行工具。它提供了简单的接口来安装、链接、切换和管理不同版本的 Java。
3
+ Linux 上的 JDK 版本管理工具。通过简单的命令安装、切换和管理不同版本的 Java。
4
4
 
5
- ## 功能特性
6
-
7
- - **安装 JDK**:从系统依赖库安装(支持 Ubuntu/Debian、Fedora/CentOS/RHEL、Arch Linux)或从 Oracle 官方下载
8
- - **链接系统 JDK**:链接系统已安装的 JDK 到 jvm-manager 管理的目录
9
- - **切换 JDK 版本**:在全局和项目级别切换不同版本的 Java
10
- - **列出已安装 JDK**:显示所有已安装的 JDK 版本,包括系统 JDK
11
- - **管理环境变量**:生成可用于设置 Java 环境变量的命令
12
- - **系统兼容性检查**:检查系统是否满足运行 Java 的要求
5
+ ## 环境要求
13
6
 
14
- ## 快速开始
7
+ - Linux (Ubuntu/Debian, Fedora/CentOS/RHEL, Arch Linux)
8
+ - Node.js >= 14
9
+ - sudo 权限(用于系统包管理器安装 JDK)
15
10
 
16
- ### 安装 jvm-manager
11
+ ## 安装
17
12
 
18
13
  ```bash
19
14
  npm install -g jvm-manager-cli
20
15
  ```
21
16
 
22
- ### 使用
23
-
24
- #### 1. 查看帮助
17
+ 安装后,在 `.bashrc` 或 `.zshrc` 中添加 shell 集成:
25
18
 
26
19
  ```bash
27
- jvm help
20
+ eval "$(jvm init)"
28
21
  ```
29
22
 
30
- #### 2. 安装 JDK
23
+ 重新打开终端或 `source ~/.bashrc` 生效。启用后 `jvm use` 会自动设置当前 shell 的 `JAVA_HOME` 和 `PATH`。
24
+
25
+ ## 使用
31
26
 
32
27
  ```bash
28
+ # 安装 JDK
33
29
  jvm install 17
34
- ```
35
-
36
- #### 3. 列出所有已安装的 JDK 版本
37
30
 
38
- ```bash
31
+ # 查看已安装版本
39
32
  jvm list
40
- ```
41
-
42
- #### 4. 切换全局默认 JDK
43
-
44
- ```bash
45
- jvm use 17 --global
46
- ```
47
33
 
48
- #### 5. 在项目中使用特定版本的 JDK
34
+ # 切换全局版本
35
+ jvm use 17
49
36
 
50
- ```bash
37
+ # 为当前项目指定版本 (写入 .jvmrc)
51
38
  jvm use 11 --project
52
- ```
53
-
54
- #### 6. 设置 Java 环境变量
55
-
56
- ```bash
57
- eval "$(jvm env --global)"
58
- java -version
59
- ```
60
-
61
- #### 7. 检查系统兼容性
62
-
63
- ```bash
64
- jvm doctor
65
- ```
66
-
67
- ## 命令说明
68
-
69
- ### install
70
-
71
- 安装指定版本的 JDK。支持系统依赖库安装(apt、yum、pacman)和 Oracle 官方下载。
72
-
73
- ```bash
74
- jvm install <version>
75
- ```
76
-
77
- **参数:**
78
- - `<version>`:Java 版本号(如 8、11、17、21 等)
79
-
80
- ### list
81
-
82
- 列出所有已安装的 JDK 版本,包括系统 JDK。
83
-
84
- ```bash
85
- jvm list
86
- ```
87
-
88
- ### use
89
-
90
- 切换到指定版本的 JDK。支持全局和项目级别。
91
-
92
- ```bash
93
- jvm use <version> [--global|--project]
94
- ```
95
-
96
- **参数:**
97
- - `<version>`:Java 版本号(如 8、11、17、21 等)
98
- - `--global`(可选):将指定版本设置为全局默认(默认)
99
- - `--project`(可选):将指定版本设置为项目默认,创建或更新 `.jvmrc` 文件
100
-
101
- ### env
102
-
103
- 生成可用于设置 Java 环境变量的命令。支持全局和项目级别。
104
-
105
- ```bash
106
- jvm env [--global|--project]
107
- ```
108
39
 
109
- **参数:**
110
- - `--global`(可选):生成全局 Java 环境变量设置命令(默认)
111
- - `--project`(可选):生成项目 Java 环境变量设置命令
112
-
113
- ### current
114
-
115
- 显示当前全局和项目级别的 Java 版本。
116
-
117
- ```bash
40
+ # 查看当前版本
118
41
  jvm current
119
- ```
120
-
121
- ### remove
122
-
123
- 移除指定版本的 JDK。
124
-
125
- ```bash
126
- jvm remove <version>
127
- ```
128
-
129
- **参数:**
130
- - `<version>`:Java 版本号(如 8、11、17、21 等)
131
-
132
- ### link
133
42
 
134
- 链接系统已安装的 JDK 到 jvm-manager 管理的目录。
135
-
136
- ```bash
137
- jvm link <system-path> <version>
138
- ```
139
-
140
- **参数:**
141
- - `<system-path>`:系统上已安装的 Java 路径(如 `/usr/lib/jvm/java-17-openjdk-amd64`)
142
- - `<version>`:Java 版本号(如 17)
143
-
144
- ### doctor
43
+ # 链接系统已有的 JDK
44
+ jvm link /usr/lib/jvm/java-17-openjdk-amd64 17
145
45
 
146
- 检查系统是否满足运行 Java 的要求,包括 Node.js 版本、架构、操作系统平台和所需的工具。
46
+ # 移除已安装版本
47
+ jvm remove 17
147
48
 
148
- ```bash
49
+ # 检查系统兼容性
149
50
  jvm doctor
150
51
  ```
151
52
 
152
- ## 项目级配置
153
-
154
- 在项目根目录创建一个名为 `.jvmrc` 的文件,其中包含所需的 Java 版本号,即可实现项目级别的 Java 版本管理。
53
+ ## 命令参考
155
54
 
156
- ```bash
157
- # 在项目根目录创建 .jvmrc 文件
158
- jvm use 11 --project
159
- ```
55
+ | 命令 | 说明 |
56
+ |------|------|
57
+ | `jvm install <version>` | 安装指定版本 JDK(通过系统包管理器或 Oracle 下载) |
58
+ | `jvm list` | 列出所有已安装的 JDK,包括系统 JDK |
59
+ | `jvm use <version> [--global\|--project]` | 切换 JDK 版本,默认全局;`--project` 写入 `.jvmrc` |
60
+ | `jvm current` | 显示当前全局和项目级 Java 版本 |
61
+ | `jvm env [--global\|--project]` | 输出 `export JAVA_HOME=...` 等环境变量设置语句 |
62
+ | `jvm init` | 输出 shell 集成脚本,用于 `eval` |
63
+ | `jvm remove <version>` | 移除已安装的 JDK |
64
+ | `jvm link <path> <version>` | 将系统已安装的 JDK 链接到 jvm-manager |
65
+ | `jvm doctor` | 检查系统兼容性 |
160
66
 
161
- ## 系统兼容性
162
-
163
- jvm-manager 支持以下操作系统:
164
- - Ubuntu/Debian
165
- - Fedora/CentOS/RHEL
166
- - Arch Linux
167
- - 其他 Linux 发行版(会尝试使用 Oracle 官方下载)
168
-
169
- ## 环境要求
67
+ ## 项目级配置
170
68
 
171
- - Node.js 14 或更高版本
172
- - 具有执行 `sudo` 命令的权限(用于系统依赖库安装)
69
+ 在项目根目录执行 `jvm use <version> --project` 会创建 `.jvmrc` 文件。启用 shell 集成后,进入项目目录时可通过 `jvm use --project` 切换到项目指定版本。
173
70
 
174
71
  ## 常见问题
175
72
 
176
- ### 1. 安装失败
177
-
178
- 如果在使用系统依赖库安装时遇到问题,请尝试手动运行以下命令更新包管理器:
179
-
180
- ```bash
181
- # Ubuntu/Debian
182
- sudo apt update
183
- ```
184
-
185
- ### 2. 权限问题
73
+ **`jvm use` 后 `java -version` 没变?**
74
+ 需要启用 shell 集成。在 `.bashrc` 中添加 `eval "$(jvm init)"`,否则需手动执行 `eval "$(jvm env --global)"`。
186
75
 
187
- 如果遇到权限问题,请确保您有执行 `sudo` 命令的权限,并在需要时输入密码。
76
+ **安装失败?**
77
+ 先手动更新包管理器:`sudo apt update`(Debian/Ubuntu)或 `sudo yum makecache`(RHEL/CentOS)。
188
78
 
189
- ### 3. 无法找到 JDK
190
-
191
- 如果系统上已安装 Java,但 jvm-manager 无法找到,请尝试使用 `jvm link` 命令手动链接:
192
-
193
- ```bash
194
- jvm link /usr/lib/jvm/java-17-openjdk-amd64 17
195
- ```
196
-
197
- ## 故障排除
198
-
199
- 如果您遇到任何问题,请尝试使用 `jvm doctor` 命令检查系统兼容性,或使用 `--help` 查看特定命令的帮助信息。
79
+ **系统已有 JDK jvm-manager 找不到?**
80
+ 用 `jvm link` 手动链接:`jvm link /usr/lib/jvm/java-17-openjdk-amd64 17`。
200
81
 
201
82
  ## 开发
202
83
 
203
- ### 本地开发
204
-
205
84
  ```bash
206
- git clone https://github.com/your-username/jvm-manager.git
85
+ git clone https://github.com/veater16/jvm-manager.git
207
86
  cd jvm-manager
208
87
  npm install
209
- npm link
88
+ npm link # 本地链接为全局命令
89
+ npm test # 运行测试
210
90
  ```
211
91
 
212
- ### 运行测试
213
-
214
- ```bash
215
- npm test
216
- ```
217
-
218
- ## 贡献
219
-
220
- 欢迎提交问题和拉取请求。对于重大更改,请先创建一个问题来讨论您想要更改的内容。
221
-
222
92
  ## 许可证
223
93
 
224
- MIT License
94
+ MIT
package/bin/jvm.js CHANGED
@@ -3,6 +3,7 @@
3
3
  import { execSync } from 'child_process';
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, symlinkSync, writeFileSync } from 'fs';
5
5
  import { dirname, join, resolve } from 'path';
6
+ import { fileURLToPath } from 'url';
6
7
  import { homedir } from 'os';
7
8
 
8
9
  const APP_NAME = 'jvm-manager';
@@ -44,6 +45,7 @@ Usage:
44
45
  jvm use <version> --project Write .jvmrc in current project
45
46
  jvm current Show current global and project JDK
46
47
  jvm env [--global|--project] Print export lines for shell
48
+ jvm init Print shell integration script
47
49
  jvm doctor Check system for compatibility
48
50
  jvm remove <version> Remove installed JDK
49
51
  jvm link <system-path> <version> Link system JDK to local store
@@ -53,7 +55,9 @@ Examples:
53
55
  jvm use 21 --global
54
56
  jvm use 17 --project
55
57
  jvm link /usr/lib/jvm/java-17-openjdk-amd64 17
56
- eval "$(jvm env --project)"`);
58
+
59
+ Shell integration (add to .bashrc or .zshrc):
60
+ eval "$(jvm init)"`);
57
61
  }
58
62
 
59
63
  function detectArch() {
@@ -550,7 +554,7 @@ function setGlobal(version) {
550
554
  rmSync(CURRENT_GLOBAL, { recursive: true, force: true });
551
555
  symlinkSync(target, CURRENT_GLOBAL, 'dir');
552
556
  console.log('Global JDK set to ' + version);
553
- console.log('Run: eval "$(jvm env --global)"');
557
+ console.log('Tip: eval "$(jvm init)" in .bashrc to auto-apply on use');
554
558
  }
555
559
 
556
560
  function setProject(version) {
@@ -574,7 +578,7 @@ function setProject(version) {
574
578
  const file = join(cwd, PROJECT_FILE);
575
579
  writeFileSync(file, version + '\n', 'utf8');
576
580
  console.log('Project JDK set to ' + version + ' via ' + PROJECT_FILE);
577
- console.log('Run: eval "$(jvm env --project)"');
581
+ console.log('Tip: eval "$(jvm init)" in .bashrc to auto-apply on use');
578
582
  }
579
583
 
580
584
  function findProjectVersion(startDir) {
@@ -711,6 +715,17 @@ function doctor() {
711
715
  }
712
716
  }
713
717
 
718
+ function printInit() {
719
+ const cliPath = resolve(fileURLToPath(import.meta.url));
720
+ const shellScript = join(dirname(cliPath), '..', 'shell', 'jvm.sh');
721
+ if (!existsSync(shellScript)) {
722
+ fail('Shell integration script not found: ' + shellScript);
723
+ }
724
+ const content = readFileSync(shellScript, 'utf8');
725
+ // 注入 CLI 实际路径,替换动态查找
726
+ console.log(content.replace('__JVM_CLI__', cliPath));
727
+ }
728
+
714
729
  function parseFlags(args) {
715
730
  const flags = new Set(args.filter(a => a.startsWith('--')));
716
731
  return {
@@ -775,6 +790,10 @@ function main() {
775
790
  showCurrent();
776
791
  return;
777
792
  }
793
+ if (cmd === 'init') {
794
+ printInit();
795
+ return;
796
+ }
778
797
  if (cmd === 'doctor') {
779
798
  doctor();
780
799
  return;
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "jvm-manager-cli",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "A simple CLI to manage Java installations on Linux",
5
5
  "main": "bin/jvm.js",
6
6
  "scripts": {
7
7
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
8
8
  "check": "node bin/jvm.js --help",
9
9
  "link": "npm unlink 2>/dev/null || true && npm link",
10
- "build": "mkdir -p dist && cp bin/jvm.js dist/ && cp package.json dist/ && cp README.md dist/ && cp LICENSE dist/"
10
+ "build": "mkdir -p dist && cp bin/jvm.js dist/ && cp package.json dist/ && cp README.md dist/ && cp LICENSE dist/ && cp -r shell dist/"
11
11
  },
12
12
  "author": "",
13
13
  "license": "MIT",
package/shell/jvm.sh ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+ # jvm-manager shell 集成
3
+ # 使用方式: eval "$(jvm init)"
4
+
5
+ __JVM_CLI="__JVM_CLI__"
6
+
7
+ jvm() {
8
+ case "$1" in
9
+ use)
10
+ command node "$__JVM_CLI" "$@"
11
+ local rc=$?
12
+ if [ $rc -ne 0 ]; then
13
+ return $rc
14
+ fi
15
+
16
+ local env_flag="--global"
17
+ local arg
18
+ for arg in "$@"; do
19
+ if [ "$arg" = "--project" ]; then
20
+ env_flag="--project"
21
+ break
22
+ fi
23
+ done
24
+
25
+ eval "$(command node "$__JVM_CLI" env "$env_flag" 2>/dev/null)"
26
+ ;;
27
+ env)
28
+ eval "$(command node "$__JVM_CLI" "$@")"
29
+ ;;
30
+ *)
31
+ command node "$__JVM_CLI" "$@"
32
+ ;;
33
+ esac
34
+ }
35
+
36
+ if [ -L "${HOME}/.local/share/jvm-manager/current" ]; then
37
+ eval "$(command node "$__JVM_CLI" env --global 2>/dev/null)"
38
+ fi