Skip to content

Add Sdkman module for Java/Maven version management#602

Merged
xpf0000 merged 1 commit intoxpf0000:masterfrom
HeavenSky:feat/sdkman-module
Mar 27, 2026
Merged

Add Sdkman module for Java/Maven version management#602
xpf0000 merged 1 commit intoxpf0000:masterfrom
HeavenSky:feat/sdkman-module

Conversation

@HeavenSky
Copy link
Contributor

sdkman-source - SDKMAN 渠道源集成

创建日期: 2026-03-27

需求概述

参考 Homebrew 和 MacPorts 的渠道源实现模式, 新增 SDKMAN (https://sdkman.io) 作为第四个安装渠道源.
SDKMAN 是 JVM 生态专用的版本管理工具, 支持 macOS 和 Linux, 主要为 Java 和 Maven 提供版本安装/卸载/切换能力.
与 brew/port 相比, SDKMAN 不需要 sudo, 安装在用户目录 ~/.sdkman/ 下, Java 支持多 Vendor (Corretto/Temurin/Zulu 等).

现状分析

渠道源架构 (brew/port/static)

当前系统支持三种渠道源, 实现模式如下:

Fork 层 (后端):

  • 每个模块 (Java/Maven 等) 在 src/fork/module/<Name>/index.ts 中实现 brewinfo() / portinfo() 方法
  • src/fork/util/Version.ts 提供 brewInfoJson() / portSearch() / brewSearch() 通用函数
  • src/fork/module/Brew/index.tsMacPorts/index.ts 管理 brew/port 自身 (换源/扩展等)
  • src/fork/BaseManager.ts 通过 switch-case 注册模块, 动态导入

主进程:

  • src/main/Application.tscheckBrewOrPort() 检测 brew/port 安装状态
  • src/global.d.ts 定义 ServerType 包含 BrewCellar, MacPorts 等属性
  • 检测结果通过 global.Server 传递给渲染进程

渲染进程核心:

  • src/render/core/Module/Module.ts: 核心类, 包含 brew[], port[], static[] 三组数据 + fetchBrew/fetchPort/fetchStatic 方法
  • src/render/core/Module/ModuleHomebrewItem.ts / ModuleMacportsItem.ts / ModuleStaticItem.ts: 渠道项模型
  • src/render/util/Brew.ts: brewInfo() / portInfo() IPC 桥接函数
  • src/render/store/brew.ts: BrewStore, LibUse 管理渠道选择, modules 管理模块实例

UI 组件:

  • src/render/components/VersionManager/: 包含 brew/port/static/local 四个子目录
  • 每个子目录有 index.vue (列表 UI) + setup.ts (组合式 API)
  • setup.ts / setupAll.ts: 管理 libSrc 切换 ('brew' | 'port' | 'static' | 'local')
  • index.vue / all.vue: 顶层组件, 渲染 radio-group 切换和对应子组件

Java/Maven 模块当前实现

Java (src/fork/module/Java/index.ts):

  • brewinfo(): 通过 brew search + brewInfoJson 获取 jdk/openjdk 列表
  • portinfo(): 通过 portSearch 搜索 ^((open)?)jdk([\d\.]*)$
  • fetchAllOnlineVersion(): 从远端获取静态版本列表
  • Java 安装路径: /Library/Java/JavaVirtualMachines/<name>/Contents/Home/bin/java

Maven (src/fork/module/Maven/index.ts):

  • brewinfo(): 固定搜索 ['maven']
  • portinfo(): 搜索 ^maven\d*$
  • fetchAllOnlineVersion(): 从远端获取静态版本列表
  • Maven 安装路径: AppDir/maven-<version>/bin/mvn

Java 页面 (src/render/components/Java/Index.vue):

  • Tab 结构: Service | VersionManager (Java) | Maven | Projects
  • Java VersionManager: 使用 VersionManager/index.vue, 支持 brew/port/static
  • Maven VersionManager: 使用 VersionManager/all.vue, 支持 local/brew/port/static

SDKMAN 特性 (研究结果)

环境信息:

  • 安装路径: ~/.sdkman/
  • 初始化: source ~/.sdkman/bin/sdkman-init.sh
  • 配置: ~/.sdkman/etc/config
  • Candidates 目录: ~/.sdkman/candidates/<candidate>/<version>/
  • 当前版本: ~/.sdkman/candidates/<candidate>/current (符号链接)
  • 跨平台: macOS + Linux, 不支持 Windows

Java 版本列表格式 (sdk list java):

 Vendor        | Use | Version      | Dist    | Status     | Identifier
--------------------------------------------------------------------------------
 Corretto      |     | 26           | amzn    |            | 26-amzn
 Temurin       | >>> | 21.0.10      | tem     | installed  | 21.0.10-tem
  • 包含 15+ Vendor: Corretto, Temurin, Zulu, GraalVM, Oracle, Microsoft 等
  • Identifier 格式: <version>-<dist>, 如 21.0.10-tem
  • Status 标记: installed / local only
  • Use 标记: >>> 表示当前使用

Maven 版本列表格式 (sdk list maven):

     4.0.0-rc-5          3.9.1               3.5.4
 > * 3.9.14              3.8.9               3.5.3
  • 简单版本列表, * = 已安装, > = 当前使用

安装路径:

  • Java: ~/.sdkman/candidates/java/<identifier>/bin/java
  • Maven: ~/.sdkman/candidates/maven/<version>/bin/mvn

实现方案

推荐方案: CLI 解析 + XTerm 执行

与 brew/port 完全一致的实现模式:

  • Fork 层通过 sdk list 命令获取版本列表, 解析 CLI 输出
  • 安装/卸载通过 XTerm 终端执行 sdk install/sdk uninstall
  • 需要先 source ~/.sdkman/bin/sdkman-init.sh 初始化环境

优势: 与现有架构完全一致, 开发成本可控
劣势: CLI 输出解析比 JSON 脆弱, 但 SDKMAN 输出格式已稳定多年

备选方案: REST API

SDKMAN 提供 REST API (https://api.sdkman.io/2/candidates/java/<platform>/versions/list), 可获取版本列表.
但 API 无法反映本地已安装状态, 仍需 CLI 补充. 增加复杂度, 不推荐.

缺失清单

  • SDKMAN CLI 输出格式已确认
  • SDKMAN 目录结构已确认
  • 现有 brew/port 实现模式已分析

已确认事项

  • SDKMAN 暂不提供"安装自身"入口, 仅检测已安装, 未安装时不显示 SDKMAN tab
  • Java 版本平铺展示, Vendor 作为表格额外列信息
  • Tab 标签使用 "SDKMAN" (官方写法)

跨平台策略 (参考 Homebrew)

Homebrew 在 Windows 上的三层隔离机制

  1. 主进程检测层: checkBrewOrPort() 仅在 isMacOS()/isLinux() 分支执行

    • Windows 上 global.Server.BrewCellar 永远是 undefined
    • MacPorts 检测仅在 isMacOS() 分支
  2. UI 模板层: VersionManager/index.vueall.vue 按平台分三个 v-if 分支

    • macOS: static + brew + port (由 showBrewLib/showPortLib props 控制)
    • Linux: static + brew (没有 port)
    • Windows: 只有 title + StaticVM (无 radio-group)
  3. Props 控制层: 各模块页面通过 show-brew-lib/show-port-lib 控制显示

    • Java: show-brew-lib=true, show-port-lib=true
    • Elasticsearch: show-brew-lib=false, show-port-lib=false (仅 static)

SDKMAN 跨平台策略 (对齐 Homebrew)

SDKMAN 支持 macOS + Linux, 不支持 Windows. 与 Homebrew 一致, 但比 MacPorts (仅 macOS) 更广:

  1. 主进程检测层: checkBrewOrPort() 在 macOS/Linux 分支添加 SDKMAN 检测

    • 检测 ~/.sdkman/bin/sdkman-init.sh 是否存在
    • 设置 global.Server.SdkmanHome
    • Windows 跳过
  2. UI 模板层: macOS/Linux 模板分支中添加 SDKMAN radio-button

    • macOS: static + brew + port + sdkman
    • Linux: static + brew + sdkman
    • Windows: 不变 (仅 static)
  3. Props 控制层: 新增 showSdkmanLib prop (默认 false)

    • 仅 Java 和 Maven 传 :show-sdkman-lib="true"
    • 其他模块不显示 SDKMAN tab
  4. 数据层: checkSdkman computed 依赖 window.Server.SdkmanHome

    • 未安装时 radio-button 不显示 (与 brew 的 checkBrew 逻辑一致)

开发步骤

1. 类型定义与检测基础

  • src/global.d.ts: ServerType 添加 SdkmanHome?: string 属性
  • src/main/Application.ts: checkBrewOrPort() 中添加 SDKMAN 检测逻辑
    • isMacOS()isLinux() 分支内检测 ~/.sdkman/bin/sdkman-init.sh
    • 存在则设置 global.Server.SdkmanHome = join(homedir, '.sdkman')
    • Windows 跳过 (与 brew/port 一致)

2. Fork 层 - SDKMAN 管理模块

  • src/fork/module/Sdkman/index.ts: 新建, 继承 Base
    • checkInstalled(): 检测 SDKMAN 是否安装
    • listJava(): 执行 sdk list java, 解析版本列表
    • listMaven(): 执行 sdk list maven, 解析版本列表
    • 所有命令需要先 source ~/.sdkman/bin/sdkman-init.sh
  • src/fork/util/Version.ts: 添加 sdkmanSearch() 通用函数
    • 解析 Java 表格格式 (Vendor/Version/Dist/Status/Identifier)
    • 解析 Maven 简单列表格式 (*/> 标记)
  • src/fork/Fn.ts: 导出 sdkmanSearch 函数
  • src/fork/BaseManager.ts: 注册 sdkman 模块 (添加 Sdkman 属性和 switch-case)

3. Fork 层 - Java/Maven 添加 sdkmaninfo

  • src/fork/module/Java/index.ts: 添加 sdkmaninfo() 方法
    • 调用 Sdkman 模块的 listJava() 或直接解析 sdk list java
    • 返回格式: { name, version, installed, flag: 'sdkman', vendor?, identifier? }
    • 判断安装状态: 检查 ~/.sdkman/candidates/java/<identifier>/bin/java
  • src/fork/module/Maven/index.ts: 添加 sdkmaninfo() 方法
    • 解析 sdk list maven 输出
    • 判断安装状态: 检查 ~/.sdkman/candidates/maven/<version>/bin/mvn

4. 渲染进程核心 - 数据模型

  • src/render/core/Module/ModuleSdkmanItem.ts: 新建 SDKMAN 项模型
    • 参考 ModuleHomebrewItem.ts 结构
    • 属性: typeFlag, version, installed, name, vendor?, identifier?
    • fetchCommand(): 返回 sdk install java <identifier>sdk uninstall java <identifier>
    • copyCommand(): 复制命令到剪贴板
    • runCommand(dom): XTerm 执行安装/卸载
      • 命令: source ~/.sdkman/bin/sdkman-init.sh && sdk install/uninstall <candidate> <identifier>
  • src/render/core/Module/Module.ts:
    • 添加 sdkman: ModuleSdkmanItem[] 数据数组
    • 添加 sdkmanFetching: boolean 状态
    • 添加 fetchSdkman() 方法, 参考 fetchBrew()/fetchPort() 模式
  • src/render/util/Brew.ts: 添加 sdkmanInfo(flag) IPC 桥接函数
    • IPC.send('app-fork:<flag>', 'sdkmaninfo', flag) 获取版本列表

5. 渲染进程 Store

  • src/render/store/brew.ts:
    • LibUse 类型: 添加 'sdkman' 选项
    • module() action: 添加 module.fetchSdkman = module.fetchSdkman.bind(module)

6. UI 组件 - SDKMAN 版本管理

  • src/render/components/VersionManager/sdkman/setup.ts: 新建
    • 参考 port/setup.ts 结构
    • SdkmanSetup reactive 状态 (installing, installEnd, xterm, checkSdkman, reFetch)
    • Setup(typeFlag) 组合式函数
    • checkSdkman computed: 检测 window.Server.SdkmanHome
    • handleVersion: XTerm 执行 sdk install/uninstall
    • tableData: 版本列表排序
  • src/render/components/VersionManager/sdkman/index.vue: 新建
    • 参考 port/index.vue 结构
    • 表格列: Name/Version/Vendor(Java only)/Status/Actions

7. UI 组件 - 集成到 VersionManager (跨平台)

  • src/render/components/VersionManager/setup.ts:
    • libSrc computed 添加 'sdkman' 选项
    • showFooter/taskEnd/taskConfirm/taskCancel/loading/reFetch 添加 sdkman 分支
  • src/render/components/VersionManager/setupAll.ts: 同上
  • src/render/components/VersionManager/index.vue:
    • 新增 showSdkmanLib prop (默认 false)
    • macOS 分支 radio-group: 添加 v-if="showSdkmanLib !== false" 的 SDKMAN radio-button
    • Linux 分支 radio-group: 同上 (SDKMAN 支持 Linux)
    • Windows 分支: 不变
    • 三个平台分支内添加 v-if="libSrc === 'sdkman'" -> <SdkmanVM />
  • src/render/components/VersionManager/all.vue: 同上
  • src/render/components/Java/Index.vue:
    • Java Manager: 添加 :show-sdkman-lib="true"
    • Maven: 添加 :show-sdkman-lib="true"

文件变更清单

操作 文件路径 变更内容
修改 src/global.d.ts ServerType 添加 SdkmanHome
修改 src/main/Application.ts checkBrewOrPort 添加 SDKMAN 检测
新建 src/fork/module/Sdkman/index.ts SDKMAN 管理模块
修改 src/fork/util/Version.ts 添加 sdkmanSearch 函数
修改 src/fork/Fn.ts 导出 sdkmanSearch
修改 src/fork/BaseManager.ts 注册 sdkman 模块
修改 src/fork/module/Java/index.ts 添加 sdkmaninfo()
修改 src/fork/module/Maven/index.ts 添加 sdkmaninfo()
新建 src/render/core/Module/ModuleSdkmanItem.ts SDKMAN 项数据模型
修改 src/render/core/Module/Module.ts 添加 sdkman 数据/方法
修改 src/render/util/Brew.ts 添加 sdkmanInfo()
修改 src/render/store/brew.ts LibUse 添加 sdkman
新建 src/render/components/VersionManager/sdkman/setup.ts SDKMAN 组合式 API
新建 src/render/components/VersionManager/sdkman/index.vue SDKMAN 版本列表 UI
修改 src/render/components/VersionManager/setup.ts 添加 sdkman 分支
修改 src/render/components/VersionManager/setupAll.ts 添加 sdkman 分支
修改 src/render/components/VersionManager/index.vue 添加 SDKMAN tab
修改 src/render/components/VersionManager/all.vue 添加 SDKMAN tab

新建 4 个文件, 修改 14 个文件. 预估 ~800 行新增代码.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@xpf0000 xpf0000 merged commit 38783b1 into xpf0000:master Mar 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants