Files
FanTools/src/main/code-launchpad/ide-versions-check.ts

234 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type {
checkIDEResultDto,
checkIDEsResultDto,
checkIDEsVersionDto,
checkIDEVersionDto,
IDECode
} from '@my-type/settings'
import { execSync } from 'node:child_process'
import path from 'path'
import { loadJsonFile } from 'load-json-file'
import os from 'os'
import {
JetBrainsIDEDisplayNameEnum as JIN,
JetBrainsProductCode,
JetBrainsStateDto,
toProductDisplayName
} from '@my-type/jetbrains-state-tools'
import { settingsManager } from '../settings'
import { isNodeError } from '@my-type/node-error'
import { JetBrainsDataProductDto } from '@my-type/jetbrains-data-products'
const JETBRAINS_TOOLBOX_STATE_JSON_PATH = path.join(
os.homedir(),
'AppData/Local/JetBrains/Toolbox/state.json'
)
/**
* 通过 where.exe 检查系统中的指定 IDE 是否安装可用。
* @param display IDE 的正式显示名称,例如 `Visual Studio Code`。
* @param command IDE 的命令行别名,例如 `code`。
* @param code JetBrains IDE的产品代号对于其他 IDE 为空字符串
*/
function checkIDE(display: string, command: string, code: IDECode): checkIDEResultDto | null {
try {
const paths = execSync(`where.exe ${command}`).toString().split('\n').slice(0, -1)
return { code, display: display, command: command, paths: paths }
} catch {
return null
}
}
/**
* 检查 JetBrains IDEs 是否安装可用。
*/
async function checkJetBrainsIDEs(): Promise<checkIDEsResultDto> {
// 构建数据结构的辅助函数
const _ = (command: string, code: JetBrainsProductCode): checkIDEResultDto => {
return {
code,
command,
display: JIN[command],
paths: []
}
}
const result: checkIDEsResultDto = {
PY: _('pycharm', 'PY'),
CL: _('clion', 'CL'),
WS: _('webstorm', 'WS'),
PS: _('phpstorm', 'PS'),
IU: _('idea', 'IU')
}
// 优先从 JBTState.json 查找
if (settingsManager._settings?.codeLaunchpadIDESearchPolicy.includes('JBTState.json')) {
// 处理文件不存在,即 JetBrains Toolbox 相关问题
try {
const data: JetBrainsStateDto = await loadJsonFile(JETBRAINS_TOOLBOX_STATE_JSON_PATH)
for (const ide of data.tools) {
for (const resultElement of Object.values(result)) {
if (resultElement?.code === ide.productCode) {
resultElement.paths = [ide.launchCommand]
}
}
}
} catch (error) {
if (isNodeError(error)) {
if (error.code === 'ENOENT') {
console.log('由于 JBTState.json 不存在,回退到 where.exe。')
}
} else {
console.error(error)
}
}
}
// 从 where.exe 查找
// 此分支确保在设置中启用 where.exe 方式,以及 JBTState.json 方式没有结果(未找到任何,或出现错误)时进入
if (
settingsManager._settings?.codeLaunchpadIDESearchPolicy.includes('where.exe') &&
Object.entries(result).length === 0
) {
result['clion'] = checkIDE(JIN.clion, 'clion', 'CL')
result['pycharm'] = checkIDE(JIN.pycharm, 'pycharm', 'PY')
result['webstorm'] = checkIDE(JIN.webstorm, 'webstorm', 'WS')
result['phpstorm'] = checkIDE(JIN.phpstorm, 'phpstorm', 'PS')
result['idea'] = checkIDE(JIN.idea, 'idea', 'IU')
}
return result
}
/**
* 获取系统中的各 IDE 是否安装可用。
*/
export async function getIDEs(): Promise<checkIDEsResultDto> {
return global.installedIDEs === null ? await checkIDEs() : global.installedIDEs
}
/**
* 检查系统中的各 IDE 是否安装可用。
* 原理是运行 `where.exe ${command}` 并检查返回值。
*/
export async function checkIDEs(): Promise<checkIDEsResultDto> {
console.log('在系统中查找已安装的 IDE ...')
const vscodeIDEs = {
VSC: checkIDE('Visual Studio Code', 'code', 'VSC')
}
global.installedIDEs = { ...vscodeIDEs, ...(await checkJetBrainsIDEs()) }
return global.installedIDEs
}
/**
* 检查 VSCode 的版本信息,通过 code --version。
*/
async function checkVSCodeVersion(): Promise<checkIDEVersionDto> {
const install = execSync('code --version').toString().split('\n')[0]
let latest = 'unknown'
try {
latest = await fetch('https://update.code.visualstudio.com/api/releases/stable')
.then((res) => res.json())
.then((data) => data[0])
} catch (error) {
console.error('获取 VSCode 版本列表时出现错误。错误提供如下。')
console.error(error)
}
return { code: 'VSC', install, latest, display: 'Visual Studio Code' }
}
/**
* 检查 JetBrains IDE 的版本信息
*/
export async function checkJetBrainsIDEsVersion(): Promise<checkIDEsVersionDto> {
// 构建数据结构的辅助函数
const _ = (code: JetBrainsProductCode): checkIDEVersionDto => {
return {
code,
display: toProductDisplayName(code) as string,
install: 'unknown',
latest: 'unknown'
}
}
const result: checkIDEsVersionDto = {
PY: _('PY'),
CL: _('CL'),
WS: _('WS'),
PS: _('PS'),
IU: _('IU')
}
// 尝试从 JBTState.json 获取已安装的 JetBrains IDEs 的版本
// TODO添加更多获取 JetBrains IDEs 已安装版本的方案
try {
const data: JetBrainsStateDto = await loadJsonFile(JETBRAINS_TOOLBOX_STATE_JSON_PATH)
for (const tool of data.tools) {
for (const resultElement of Object.values(result)) {
if (resultElement?.code === tool.productCode) {
resultElement.install = tool.displayVersion
}
}
}
} catch (error) {
if (isNodeError(error)) {
if (error.code === 'ENOENT') {
console.log('由于 JBTState.json 不存在,检查 JetBrains IDEs 已安装版本的任务失败。')
}
} else {
console.error(error)
}
}
// 从命令行获取 JetBrains IDE 的已安装版本的方案仍然在科研中
// 所以这个方法就暂时先结束了~
// 从网络接口获取 JetBrains IDEs 的版本列表
const codes: JetBrainsProductCode[] = []
for (const resultElement of Object.values(result)) {
codes.push(<JetBrainsProductCode>resultElement?.code)
}
try {
const params = new URLSearchParams({
type: 'release',
code: codes.join(',')
})
const data: JetBrainsDataProductDto[] = await fetch(
`https://data.services.jetbrains.com/products?${params}`
).then((res) => res.json())
for (const datum of data) {
for (const resultElement of Object.values(result)) {
if (resultElement?.code === datum.intellijProductCode) {
resultElement.latest = datum.releases[0].version
}
}
}
} catch (error) {
console.error('从 JetBrains IDEs 版本列表接口获取数据失败。错误提供如下。')
console.error(error)
}
return result
}
/**
* 获取各 IDE 的版本信息。
*/
export async function getIDEsVersion(): Promise<checkIDEsVersionDto> {
return global.installedIDEsVersion === null
? await checkIDEsVersion()
: global.installedIDEsVersion
}
/**
* 检查各 IDE 的版本信息。
*/
export async function checkIDEsVersion(): Promise<checkIDEsVersionDto> {
let result: checkIDEsVersionDto = {}
for (const ide in await getIDEs()) {
switch (ide) {
case 'VSC':
result['VSC'] = await checkVSCodeVersion()
break
}
}
result = { ...result, ...(await checkJetBrainsIDEsVersion()) }
global.installedIDEsVersion = result
return result
}