@wwkit/opm 1.0.1 → 1.0.2
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/package.json +2 -1
- package/src/cli/groups/docker.js +116 -0
- package/src/cli/groups/wsl.js +220 -0
- package/src/cli/index.js +6 -0
- package/src/config.json5 +15 -0
- package/src/index.js +15 -0
- package/src/managers/docker.js +295 -0
- package/src/managers/wsl.js +258 -0
- package/src/tools/ftp/client.js +214 -0
- package/src/tools/ftp/index.js +271 -0
- package/src/tools/ftp/util.js +174 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docker 管理器
|
|
3
|
+
*
|
|
4
|
+
* 跨平台安装策略:
|
|
5
|
+
* - Linux: 官方便捷脚本 get.docker.com
|
|
6
|
+
* - macOS: brew install --cask docker (Docker Desktop)
|
|
7
|
+
* - Windows: WSL2 内跑便捷脚本(WSL 当作 Linux)
|
|
8
|
+
*
|
|
9
|
+
* daemon 管理:
|
|
10
|
+
* - Linux: systemctl start/stop/restart docker
|
|
11
|
+
* - macOS: open/quit Docker Desktop app
|
|
12
|
+
* - Windows: wsl -e systemctl start/stop/restart docker
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { execSync, spawnSync } from 'node:child_process'
|
|
16
|
+
import fs from 'node:fs'
|
|
17
|
+
import { getBrewBin } from './brew.js'
|
|
18
|
+
import { openWsl } from './wsl.js'
|
|
19
|
+
|
|
20
|
+
const DOCKER_INSTALL_URL = 'https://get.docker.com'
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 检查 docker 命令是否可用
|
|
24
|
+
* @returns {boolean}
|
|
25
|
+
*/
|
|
26
|
+
export function isDockerInstalled() {
|
|
27
|
+
try {
|
|
28
|
+
execSync('docker --version', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] })
|
|
29
|
+
return true
|
|
30
|
+
} catch {
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 获取 docker 版本
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
export function getDockerVersion() {
|
|
40
|
+
const out = execSync('docker --version', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] })
|
|
41
|
+
const m = out.match(/Docker version\s+(\S+)/)
|
|
42
|
+
return m ? m[1] : out.trim()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 在 Linux 环境中执行 Docker 便捷脚本
|
|
47
|
+
* @private
|
|
48
|
+
*/
|
|
49
|
+
function runConvenienceScript() {
|
|
50
|
+
execSync(`curl -fsSL ${DOCKER_INSTALL_URL} | sh`, { stdio: 'inherit', shell: true })
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 安装 Docker
|
|
55
|
+
* @returns {{ action: string, method: string, hint?: string }}
|
|
56
|
+
*/
|
|
57
|
+
export function installDocker() {
|
|
58
|
+
const platform = process.platform
|
|
59
|
+
|
|
60
|
+
if (platform === 'linux') {
|
|
61
|
+
runConvenienceScript()
|
|
62
|
+
return { action: 'installed', method: 'convenience-script' }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (platform === 'darwin') {
|
|
66
|
+
execSync(`${getBrewBin()} install --cask docker`, { stdio: 'inherit', shell: true })
|
|
67
|
+
return { action: 'installed', method: 'brew-cask', hint: 'Start Docker Desktop from Applications' }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (platform === 'win32') {
|
|
71
|
+
execSync('wsl.exe -e bash -c "curl -fsSL https://get.docker.com | sh"', { stdio: 'inherit', shell: true })
|
|
72
|
+
return { action: 'installed', method: 'wsl-convenience-script', hint: 'Docker installed inside WSL2' }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
throw new Error(`Unsupported platform: ${platform}`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 升级 Docker
|
|
80
|
+
* @returns {{ action: string, method: string }}
|
|
81
|
+
*/
|
|
82
|
+
export function upgradeDocker() {
|
|
83
|
+
const platform = process.platform
|
|
84
|
+
|
|
85
|
+
if (platform === 'linux') {
|
|
86
|
+
try {
|
|
87
|
+
execSync('apt-get update && apt-get upgrade -y docker-ce', { stdio: 'inherit', shell: true })
|
|
88
|
+
return { action: 'upgraded', method: 'apt' }
|
|
89
|
+
} catch {
|
|
90
|
+
try {
|
|
91
|
+
execSync('dnf upgrade -y docker-ce', { stdio: 'inherit', shell: true })
|
|
92
|
+
return { action: 'upgraded', method: 'dnf' }
|
|
93
|
+
} catch {
|
|
94
|
+
runConvenienceScript()
|
|
95
|
+
return { action: 'upgraded', method: 'convenience-script' }
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (platform === 'darwin') {
|
|
101
|
+
execSync(`${getBrewBin()} upgrade --cask docker`, { stdio: 'inherit', shell: true })
|
|
102
|
+
return { action: 'upgraded', method: 'brew-cask' }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (platform === 'win32') {
|
|
106
|
+
execSync('wsl.exe -e bash -c "sudo apt-get update && sudo apt-get upgrade -y docker-ce"', { stdio: 'inherit', shell: true })
|
|
107
|
+
return { action: 'upgraded', method: 'wsl-apt' }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
throw new Error(`Unsupported platform: ${platform}`)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 卸载 Docker
|
|
115
|
+
* @returns {{ action: string, hint: string }}
|
|
116
|
+
*/
|
|
117
|
+
export function uninstallDocker() {
|
|
118
|
+
const platform = process.platform
|
|
119
|
+
|
|
120
|
+
if (platform === 'linux') {
|
|
121
|
+
try {
|
|
122
|
+
execSync('apt-get purge -y docker-ce docker-ce-cli containerd.io', { stdio: 'inherit', shell: true })
|
|
123
|
+
} catch {
|
|
124
|
+
execSync('dnf remove -y docker-ce docker-ce-cli containerd.io', { stdio: 'inherit', shell: true })
|
|
125
|
+
}
|
|
126
|
+
return { action: 'uninstalled', hint: 'Images/containers left in /var/lib/docker, remove manually if needed' }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (platform === 'darwin') {
|
|
130
|
+
execSync(`${getBrewBin()} uninstall --cask docker`, { stdio: 'inherit', shell: true })
|
|
131
|
+
return { action: 'uninstalled', hint: 'Docker Desktop app removed' }
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (platform === 'win32') {
|
|
135
|
+
return {
|
|
136
|
+
action: 'uninstall',
|
|
137
|
+
hint: 'Run in WSL: sudo apt-get purge -y docker-ce docker-ce-cli containerd.io',
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
throw new Error(`Unsupported platform: ${platform}`)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 获取 Docker 数据目录
|
|
146
|
+
* @returns {string}
|
|
147
|
+
*/
|
|
148
|
+
export function getDockerDir() {
|
|
149
|
+
const platform = process.platform
|
|
150
|
+
|
|
151
|
+
if (platform === 'linux') {
|
|
152
|
+
return '/var/lib/docker'
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (platform === 'darwin') {
|
|
156
|
+
const home = process.env.HOME || ''
|
|
157
|
+
return `${home}/.docker`
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (platform === 'win32') {
|
|
161
|
+
const localAppData = process.env.LOCALAPPDATA || ''
|
|
162
|
+
return localAppData ? `${localAppData}\\Docker` : ''
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return ''
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* 获取 Docker 状态(docker info 摘要)
|
|
170
|
+
* @returns {{ installed: boolean, running?: boolean, info?: string }}
|
|
171
|
+
*/
|
|
172
|
+
export function getDockerStatus() {
|
|
173
|
+
if (!isDockerInstalled()) return { installed: false }
|
|
174
|
+
try {
|
|
175
|
+
const out = execSync('docker info --format "{{.ServerVersion}} {{.OperatingSystem}} {{.Containers}} {{.Images}}"', {
|
|
176
|
+
encoding: 'utf8',
|
|
177
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
178
|
+
})
|
|
179
|
+
const [serverVersion, operatingSystem, containers, images] = out.trim().split(' ')
|
|
180
|
+
return {
|
|
181
|
+
installed: true,
|
|
182
|
+
running: true,
|
|
183
|
+
serverVersion,
|
|
184
|
+
operatingSystem,
|
|
185
|
+
containers: parseInt(containers, 10) || 0,
|
|
186
|
+
images: parseInt(images, 10) || 0,
|
|
187
|
+
}
|
|
188
|
+
} catch {
|
|
189
|
+
return { installed: true, running: false, hint: 'Docker daemon not running' }
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* 启动 Docker daemon
|
|
195
|
+
* @returns {{ action: string, method: string }}
|
|
196
|
+
*/
|
|
197
|
+
export function startDocker() {
|
|
198
|
+
const platform = process.platform
|
|
199
|
+
|
|
200
|
+
if (platform === 'linux') {
|
|
201
|
+
execSync('sudo systemctl start docker', { stdio: 'inherit', shell: true })
|
|
202
|
+
return { action: 'started', method: 'systemctl' }
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (platform === 'darwin') {
|
|
206
|
+
execSync('open -a Docker', { stdio: 'inherit', shell: true })
|
|
207
|
+
return { action: 'started', method: 'docker-desktop' }
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (platform === 'win32') {
|
|
211
|
+
execSync('wsl.exe -e sudo systemctl start docker', { stdio: 'inherit', shell: true })
|
|
212
|
+
return { action: 'started', method: 'wsl-systemctl' }
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
throw new Error(`Unsupported platform: ${platform}`)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* 停止 Docker daemon
|
|
220
|
+
* @returns {{ action: string, method: string }}
|
|
221
|
+
*/
|
|
222
|
+
export function stopDocker() {
|
|
223
|
+
const platform = process.platform
|
|
224
|
+
|
|
225
|
+
if (platform === 'linux') {
|
|
226
|
+
execSync('sudo systemctl stop docker', { stdio: 'inherit', shell: true })
|
|
227
|
+
return { action: 'stopped', method: 'systemctl' }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (platform === 'darwin') {
|
|
231
|
+
execSync('osascript -e \'quit app "Docker"\'', { stdio: 'inherit', shell: true })
|
|
232
|
+
return { action: 'stopped', method: 'docker-desktop' }
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (platform === 'win32') {
|
|
236
|
+
execSync('wsl.exe -e sudo systemctl stop docker', { stdio: 'inherit', shell: true })
|
|
237
|
+
return { action: 'stopped', method: 'wsl-systemctl' }
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
throw new Error(`Unsupported platform: ${platform}`)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* 重启 Docker daemon
|
|
245
|
+
* @returns {{ action: string, method: string }}
|
|
246
|
+
*/
|
|
247
|
+
export function restartDocker() {
|
|
248
|
+
const platform = process.platform
|
|
249
|
+
|
|
250
|
+
if (platform === 'linux') {
|
|
251
|
+
execSync('sudo systemctl restart docker', { stdio: 'inherit', shell: true })
|
|
252
|
+
return { action: 'restarted', method: 'systemctl' }
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (platform === 'darwin') {
|
|
256
|
+
execSync('osascript -e \'quit app "Docker"\' && sleep 1 && open -a Docker', { stdio: 'inherit', shell: true })
|
|
257
|
+
return { action: 'restarted', method: 'docker-desktop' }
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (platform === 'win32') {
|
|
261
|
+
execSync('wsl.exe -e sudo systemctl restart docker', { stdio: 'inherit', shell: true })
|
|
262
|
+
return { action: 'restarted', method: 'wsl-systemctl' }
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
throw new Error(`Unsupported platform: ${platform}`)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* 打开终端并确保 docker 可用
|
|
270
|
+
* - Linux: 新开终端
|
|
271
|
+
* - macOS: 打开 Terminal.app
|
|
272
|
+
* - Windows: 打开 PowerShell → WSL2(docker 装在 WSL 内)
|
|
273
|
+
* @returns {{ action: string, method: string }}
|
|
274
|
+
*/
|
|
275
|
+
export function openDocker() {
|
|
276
|
+
const platform = process.platform
|
|
277
|
+
|
|
278
|
+
if (platform === 'linux') {
|
|
279
|
+
const shell = process.env.SHELL || 'bash'
|
|
280
|
+
spawnSync(shell, [], { stdio: 'inherit' })
|
|
281
|
+
return { action: 'opened', method: 'shell' }
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (platform === 'darwin') {
|
|
285
|
+
execSync('open -a Terminal', { stdio: 'inherit', shell: true })
|
|
286
|
+
return { action: 'opened', method: 'terminal-app' }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (platform === 'win32') {
|
|
290
|
+
openWsl('')
|
|
291
|
+
return { action: 'opened', method: 'wsl-powershell' }
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
throw new Error(`Unsupported platform: ${platform}`)
|
|
295
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WSL2 管理器(Windows Subsystem for Linux)
|
|
3
|
+
*
|
|
4
|
+
* 通过 wsl.exe CLI 管理自身与发行版。仅 Windows 可用。
|
|
5
|
+
* wsl.exe 输出为 UTF-16LE 编码,需用对应 encoding 读取。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { execSync, spawnSync } from 'node:child_process'
|
|
9
|
+
import fs from 'node:fs'
|
|
10
|
+
import path from 'node:path'
|
|
11
|
+
|
|
12
|
+
const WSL_EXE = 'wsl.exe'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 要求 Windows 平台,否则抛出
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
function requireWindows() {
|
|
19
|
+
if (process.platform !== 'win32') {
|
|
20
|
+
throw new Error('WSL is only available on Windows')
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 检查 WSL 是否已安装(wsl.exe 是否可用)
|
|
26
|
+
* @returns {boolean}
|
|
27
|
+
*/
|
|
28
|
+
export function isWslInstalled() {
|
|
29
|
+
if (process.platform !== 'win32') return false
|
|
30
|
+
try {
|
|
31
|
+
execSync(`${WSL_EXE} --version`, { encoding: 'utf16le', stdio: ['pipe', 'pipe', 'pipe'] })
|
|
32
|
+
return true
|
|
33
|
+
} catch {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 解析 wsl --version 输出,提取 WSL 版本号
|
|
40
|
+
* @param {string} out
|
|
41
|
+
* @returns {string}
|
|
42
|
+
*/
|
|
43
|
+
export function parseWslVersionOutput(out) {
|
|
44
|
+
const m = out.match(/WSL\s+(?:版本|version)[:\s]\s*([\d.]+)/i)
|
|
45
|
+
return m ? m[1] : out.trim().split('\n')[0].trim()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 获取 WSL 版本号
|
|
50
|
+
* @returns {string}
|
|
51
|
+
*/
|
|
52
|
+
export function getWslVersion() {
|
|
53
|
+
requireWindows()
|
|
54
|
+
const out = execSync(`${WSL_EXE} --version`, { encoding: 'utf16le', stdio: ['pipe', 'pipe', 'pipe'] })
|
|
55
|
+
return parseWslVersionOutput(out)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 安装 WSL2(含默认发行版)
|
|
60
|
+
* @returns {{ action: string, hint: string }}
|
|
61
|
+
*/
|
|
62
|
+
export function installWsl() {
|
|
63
|
+
requireWindows()
|
|
64
|
+
execSync(`${WSL_EXE} --install`, { stdio: 'inherit', shell: true })
|
|
65
|
+
return { action: 'installed', hint: 'Restart may be required' }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 更新 WSL 内核
|
|
70
|
+
* @returns {{ action: string }}
|
|
71
|
+
*/
|
|
72
|
+
export function updateWsl() {
|
|
73
|
+
requireWindows()
|
|
74
|
+
execSync(`${WSL_EXE} --update`, { stdio: 'inherit', shell: true })
|
|
75
|
+
return { action: 'updated' }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 卸载 WSL 提示(需通过 Windows 设置操作)
|
|
80
|
+
* @returns {{ action: string, hint: string }}
|
|
81
|
+
*/
|
|
82
|
+
export function uninstallWsl() {
|
|
83
|
+
return {
|
|
84
|
+
action: 'uninstall',
|
|
85
|
+
hint: 'Go to Settings > Apps > Optional Features > "Windows Subsystem for Linux" to uninstall',
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 获取 WSL 数据目录
|
|
91
|
+
* @returns {string}
|
|
92
|
+
*/
|
|
93
|
+
export function getWslDir() {
|
|
94
|
+
if (process.platform !== 'win32') return ''
|
|
95
|
+
const localAppData = process.env.LOCALAPPDATA || ''
|
|
96
|
+
if (!localAppData) return ''
|
|
97
|
+
const packagesDir = path.join(localAppData, 'Packages')
|
|
98
|
+
try {
|
|
99
|
+
const entries = fs.readdirSync(packagesDir)
|
|
100
|
+
const wslEntry = entries.find((e) => /CanonicalGroupLimited|Microsoft\.WSL/i.test(e))
|
|
101
|
+
if (wslEntry) return path.join(packagesDir, wslEntry)
|
|
102
|
+
} catch {}
|
|
103
|
+
return packagesDir
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* 解析 wsl -l -v 输出为发行版列表
|
|
108
|
+
* @param {string} out
|
|
109
|
+
* @returns {{ name: string, state: string, version: string, default: boolean }[]}
|
|
110
|
+
*/
|
|
111
|
+
export function parseDistroList(out) {
|
|
112
|
+
const lines = out.split('\n').map((l) => l.trim()).filter(Boolean)
|
|
113
|
+
const distros = []
|
|
114
|
+
for (const line of lines) {
|
|
115
|
+
if (/NAME/i.test(line) && /STATE/i.test(line)) continue
|
|
116
|
+
const parts = line.split(/\s+/)
|
|
117
|
+
if (parts.length >= 3) {
|
|
118
|
+
const isDefault = parts[0] === '*'
|
|
119
|
+
const name = isDefault ? parts[1] : parts[0]
|
|
120
|
+
const state = isDefault ? parts[2] : parts[1]
|
|
121
|
+
const version = isDefault ? parts[3] : parts[2]
|
|
122
|
+
distros.push({ name, state, version, default: isDefault })
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return distros
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 列出已安装的发行版
|
|
130
|
+
* @returns {{ name: string, state: string, version: string, default: boolean }[]}
|
|
131
|
+
*/
|
|
132
|
+
export function listDistros() {
|
|
133
|
+
requireWindows()
|
|
134
|
+
const out = execSync(`${WSL_EXE} -l -v`, { encoding: 'utf16le', stdio: ['pipe', 'pipe', 'pipe'] })
|
|
135
|
+
return parseDistroList(out)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 解析 wsl -l -o 输出为可用发行版名称列表
|
|
140
|
+
* @param {string} out
|
|
141
|
+
* @returns {string[]}
|
|
142
|
+
*/
|
|
143
|
+
export function parseAvailableList(out) {
|
|
144
|
+
const lines = out.split('\n').map((l) => l.trim()).filter(Boolean)
|
|
145
|
+
return lines.slice(1).map((l) => l.split(/\s+/)[0]).filter(Boolean)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 列出可安装的发行版
|
|
150
|
+
* @returns {string[]}
|
|
151
|
+
*/
|
|
152
|
+
export function listAvailable() {
|
|
153
|
+
requireWindows()
|
|
154
|
+
const out = execSync(`${WSL_EXE} -l -o`, { encoding: 'utf16le', stdio: ['pipe', 'pipe', 'pipe'] })
|
|
155
|
+
return parseAvailableList(out)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 安装指定发行版
|
|
160
|
+
* @param {string} name
|
|
161
|
+
* @returns {{ name: string, action: string }}
|
|
162
|
+
*/
|
|
163
|
+
export function installDistro(name) {
|
|
164
|
+
requireWindows()
|
|
165
|
+
execSync(`${WSL_EXE} --install -d ${name}`, { stdio: 'inherit', shell: true })
|
|
166
|
+
return { name, action: 'installed' }
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* 移除指定发行版
|
|
171
|
+
* @param {string} name
|
|
172
|
+
* @returns {{ name: string, action: string }}
|
|
173
|
+
*/
|
|
174
|
+
export function removeDistro(name) {
|
|
175
|
+
requireWindows()
|
|
176
|
+
execSync(`${WSL_EXE} --unregister ${name}`, { stdio: 'inherit', shell: true })
|
|
177
|
+
return { name, action: 'removed' }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* 在当前终端启动发行版
|
|
182
|
+
* @param {string} name
|
|
183
|
+
* @returns {{ name: string, action: string }}
|
|
184
|
+
*/
|
|
185
|
+
export function startDistro(name) {
|
|
186
|
+
requireWindows()
|
|
187
|
+
execSync(`${WSL_EXE} -d ${name}`, { stdio: 'inherit', shell: true })
|
|
188
|
+
return { name, action: 'started' }
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 停止指定发行版
|
|
193
|
+
* @param {string} name
|
|
194
|
+
* @returns {{ name: string, action: string }}
|
|
195
|
+
*/
|
|
196
|
+
export function stopDistro(name) {
|
|
197
|
+
requireWindows()
|
|
198
|
+
execSync(`${WSL_EXE} --terminate ${name}`, { stdio: 'inherit', shell: true })
|
|
199
|
+
return { name, action: 'stopped' }
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 停止所有发行版
|
|
204
|
+
* @returns {{ action: string }}
|
|
205
|
+
*/
|
|
206
|
+
export function stopAll() {
|
|
207
|
+
requireWindows()
|
|
208
|
+
execSync(`${WSL_EXE} --shutdown`, { stdio: 'inherit', shell: true })
|
|
209
|
+
return { action: 'all stopped' }
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 设置默认发行版
|
|
214
|
+
* @param {string} name
|
|
215
|
+
* @returns {{ name: string, action: string }}
|
|
216
|
+
*/
|
|
217
|
+
export function setDefaultDistro(name) {
|
|
218
|
+
requireWindows()
|
|
219
|
+
execSync(`${WSL_EXE} --set-default ${name}`, { stdio: 'inherit', shell: true })
|
|
220
|
+
return { name, action: 'default set' }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* 获取当前默认发行版名称
|
|
225
|
+
* @returns {string}
|
|
226
|
+
*/
|
|
227
|
+
export function getDefaultDistro() {
|
|
228
|
+
if (!isWslInstalled()) return ''
|
|
229
|
+
const distros = listDistros()
|
|
230
|
+
const def = distros.find((d) => d.default)
|
|
231
|
+
return def ? def.name : ''
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* 获取 WSL 状态
|
|
236
|
+
* @returns {{ installed: boolean, status?: string }}
|
|
237
|
+
*/
|
|
238
|
+
export function getWslStatus() {
|
|
239
|
+
if (!isWslInstalled()) return { installed: false }
|
|
240
|
+
try {
|
|
241
|
+
const out = execSync(`${WSL_EXE} --status`, { encoding: 'utf16le', stdio: ['pipe', 'pipe', 'pipe'] })
|
|
242
|
+
return { installed: true, status: out.trim() }
|
|
243
|
+
} catch {
|
|
244
|
+
return { installed: true, status: '' }
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* 打开 PowerShell 窗口并进入 WSL
|
|
250
|
+
* @param {string} [distro] - 发行版名称(空则用默认)
|
|
251
|
+
* @returns {{ distro: string, action: string }}
|
|
252
|
+
*/
|
|
253
|
+
export function openWsl(distro) {
|
|
254
|
+
requireWindows()
|
|
255
|
+
const wslCmd = distro ? `wsl -d ${distro}` : 'wsl'
|
|
256
|
+
spawnSync('cmd.exe', ['/c', 'start', '"WSL"', 'powershell', '-NoExit', '-Command', wslCmd], { stdio: 'inherit' })
|
|
257
|
+
return { distro: distro || 'default', action: 'opened' }
|
|
258
|
+
}
|