@wwkit/opm 1.0.1
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 +381 -0
- package/bin/index.js +9 -0
- package/docs/managers/apt.md +45 -0
- package/docs/managers/brew.md +92 -0
- package/docs/managers/bun.md +50 -0
- package/docs/managers/cft.md +57 -0
- package/docs/managers/composer.md +96 -0
- package/docs/managers/config.md +32 -0
- package/docs/managers/dnf.md +46 -0
- package/docs/managers/node.md +49 -0
- package/docs/managers/npm.md +100 -0
- package/docs/managers/nvm.md +34 -0
- package/docs/managers/php.md +48 -0
- package/docs/managers/phpenv.md +34 -0
- package/docs/managers/pip.md +98 -0
- package/docs/managers/python.md +53 -0
- package/docs/managers/uv.md +27 -0
- package/docs/opm.html +570 -0
- package/docs/packages/opencode.md +41 -0
- package/package.json +51 -0
- package/scripts/postinstall.js +7 -0
- package/src/binaries/base.js +508 -0
- package/src/binaries/cft/index.js +35 -0
- package/src/binaries/depchecker.js +172 -0
- package/src/binaries/exefinder.js +110 -0
- package/src/binaries/platform.js +17 -0
- package/src/cli/doc.js +335 -0
- package/src/cli/groups/config.js +78 -0
- package/src/cli/groups/ensure.js +96 -0
- package/src/cli/groups/homebrew.js +73 -0
- package/src/cli/groups/nvm.js +73 -0
- package/src/cli/groups/package.js +514 -0
- package/src/cli/groups/phpenv.js +89 -0
- package/src/cli/groups/uv.js +73 -0
- package/src/cli/groups/version-manager.js +186 -0
- package/src/cli/helpers/args.js +49 -0
- package/src/cli/index.js +129 -0
- package/src/config.js +133 -0
- package/src/config.json5 +158 -0
- package/src/formatter.js +13 -0
- package/src/harnesses/base.js +205 -0
- package/src/harnesses/opencode/clear.js +239 -0
- package/src/harnesses/opencode/db.js +39 -0
- package/src/harnesses/opencode/index.js +46 -0
- package/src/harnesses/opencode/sqlite.js +200 -0
- package/src/index.js +46 -0
- package/src/managers/apt.js +377 -0
- package/src/managers/base.js +167 -0
- package/src/managers/brew.js +374 -0
- package/src/managers/bun.js +342 -0
- package/src/managers/composer.js +280 -0
- package/src/managers/dnf.js +370 -0
- package/src/managers/http.js +432 -0
- package/src/managers/node.js +150 -0
- package/src/managers/npm.js +473 -0
- package/src/managers/php.js +157 -0
- package/src/managers/pip.js +555 -0
- package/src/managers/python.js +180 -0
- package/src/managers/runtime.js +309 -0
- package/src/managers/winget.js +268 -0
- package/src/presets.js +24 -0
- package/src/proxy-presets.js +12 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 包管理命令组
|
|
3
|
+
*
|
|
4
|
+
* 一组相似命令(npm/pip)的共享路由:同一套 action 分发,仅底层管理器不同。
|
|
5
|
+
* 新增包管理器:实现 src/managers/base.js 接口后在此 MANAGERS 注册。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { parseFlags } from '../helpers/args.js'
|
|
9
|
+
import { NpmManager } from '../../managers/npm.js'
|
|
10
|
+
import { PipManager } from '../../managers/pip.js'
|
|
11
|
+
import { DnfManager } from '../../managers/dnf.js'
|
|
12
|
+
import { AptManager } from '../../managers/apt.js'
|
|
13
|
+
import { BrewManager } from '../../managers/brew.js'
|
|
14
|
+
import { ComposerManager } from '../../managers/composer.js'
|
|
15
|
+
import { BunManager } from '../../managers/bun.js'
|
|
16
|
+
import { WingetManager } from '../../managers/winget.js'
|
|
17
|
+
import { NodeManager } from '../../managers/node.js'
|
|
18
|
+
import { PhpManager } from '../../managers/php.js'
|
|
19
|
+
import { PythonManager } from '../../managers/python.js'
|
|
20
|
+
import { getPresets } from '../../presets.js'
|
|
21
|
+
import { getActiveProxy } from '../../config.js'
|
|
22
|
+
import { output } from '../../formatter.js'
|
|
23
|
+
|
|
24
|
+
const MANAGERS = {
|
|
25
|
+
npm: () => new NpmManager(),
|
|
26
|
+
pip: () => new PipManager(),
|
|
27
|
+
dnf: () => new DnfManager(),
|
|
28
|
+
apt: () => new AptManager(),
|
|
29
|
+
brew: () => new BrewManager(),
|
|
30
|
+
composer: () => new ComposerManager(),
|
|
31
|
+
bun: () => new BunManager(),
|
|
32
|
+
winget: () => new WingetManager(),
|
|
33
|
+
node: () => new NodeManager(),
|
|
34
|
+
php: () => new PhpManager(),
|
|
35
|
+
python: () => new PythonManager(),
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const MANAGER_DESC = {
|
|
39
|
+
npm: 'npm package manager',
|
|
40
|
+
pip: 'pip package manager',
|
|
41
|
+
dnf: 'dnf package manager',
|
|
42
|
+
apt: 'apt package manager',
|
|
43
|
+
brew: 'brew package manager (Homebrew)',
|
|
44
|
+
composer: 'composer package manager (PHP)',
|
|
45
|
+
bun: 'bun package manager (Bun runtime)',
|
|
46
|
+
winget: 'winget package manager (Windows)',
|
|
47
|
+
node: 'node version manager (via nvm)',
|
|
48
|
+
php: 'php version manager (via phpenv)',
|
|
49
|
+
python: 'python version manager (via uv)',
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const ACTIONS = {
|
|
53
|
+
version: { desc: 'Show manager version' },
|
|
54
|
+
installed: { desc: 'Check if the manager itself is installed' },
|
|
55
|
+
registry: { desc: 'Query or set registry/mirror address' },
|
|
56
|
+
search: { desc: 'Check if a package is available in the source' },
|
|
57
|
+
view: { desc: 'Check if a package is already installed' },
|
|
58
|
+
info: { desc: 'Show package details' },
|
|
59
|
+
versions: { desc: 'List all available versions of a package' },
|
|
60
|
+
list: { desc: 'List all installed packages' },
|
|
61
|
+
outdated: { desc: 'List outdated packages' },
|
|
62
|
+
install: { desc: 'Install a package' },
|
|
63
|
+
uninstall: { desc: 'Uninstall a package' },
|
|
64
|
+
upgrade: { desc: 'Upgrade a package' },
|
|
65
|
+
cache: { desc: 'Clean cache' },
|
|
66
|
+
help: { desc: 'Show help for this manager' },
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export class PackageGroup {
|
|
70
|
+
/**
|
|
71
|
+
* @param {string} managerName - 管理器名称(npm/pip)
|
|
72
|
+
*/
|
|
73
|
+
constructor(managerName) {
|
|
74
|
+
this.name = managerName
|
|
75
|
+
this.desc = MANAGER_DESC[managerName] || `${managerName} package manager`
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async run(argv) {
|
|
79
|
+
const [action, ...rest] = argv
|
|
80
|
+
|
|
81
|
+
if (!action || action === '-h' || action === '--help' || action === 'help') {
|
|
82
|
+
this.printHelp()
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!ACTIONS[action]) {
|
|
87
|
+
console.error(`Unknown action: ${action}`)
|
|
88
|
+
this.printHelp()
|
|
89
|
+
process.exit(1)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const manager = MANAGERS[this.name]()
|
|
93
|
+
const parsed = parseFlags(rest)
|
|
94
|
+
const global = parsed.flags.global === 'true' || parsed.flags.g === 'true'
|
|
95
|
+
let proxy = parsed.flags.proxy || parsed.flags.p || ''
|
|
96
|
+
if (proxy === 'true') proxy = ''
|
|
97
|
+
if (!proxy) proxy = getActiveProxy()
|
|
98
|
+
|
|
99
|
+
await this._dispatch(manager, action, parsed, { global, proxy })
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async _dispatch(manager, action, parsed, opts) {
|
|
103
|
+
const { positional } = parsed
|
|
104
|
+
|
|
105
|
+
switch (action) {
|
|
106
|
+
case 'version': {
|
|
107
|
+
const result = await manager.getVersion()
|
|
108
|
+
output((result.version || '').replace(/^v/, ''))
|
|
109
|
+
break
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
case 'installed': {
|
|
113
|
+
const result = await manager.getVersion()
|
|
114
|
+
output({ name: result.name, installed: result.installed, ...(result.version ? { version: result.version } : {}), ...(result.hint ? { hint: result.hint } : {}) })
|
|
115
|
+
break
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
case 'registry': {
|
|
119
|
+
if (positional[0] === 'set') {
|
|
120
|
+
const url = positional[1]
|
|
121
|
+
if (!url) {
|
|
122
|
+
console.error(`Usage: opm ${this.name} registry set <url|preset>`)
|
|
123
|
+
process.exit(1)
|
|
124
|
+
}
|
|
125
|
+
const result = await manager.setRegistry(url)
|
|
126
|
+
output(result)
|
|
127
|
+
} else if (positional[0] === 'presets') {
|
|
128
|
+
const presets = getPresets(this.name)
|
|
129
|
+
const items = Object.entries(presets).map(([name, url]) => ({ name, url }))
|
|
130
|
+
output(items)
|
|
131
|
+
} else {
|
|
132
|
+
const result = await manager.getRegistry()
|
|
133
|
+
output(result)
|
|
134
|
+
}
|
|
135
|
+
break
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
case 'search': {
|
|
139
|
+
const name = positional[0]
|
|
140
|
+
const version = positional[1]
|
|
141
|
+
if (!name) {
|
|
142
|
+
console.error(`Usage: opm ${this.name} search <name> [version]`)
|
|
143
|
+
process.exit(1)
|
|
144
|
+
}
|
|
145
|
+
const result = await manager.searchPackage(name, version, { proxy: opts.proxy })
|
|
146
|
+
output(result)
|
|
147
|
+
break
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
case 'view': {
|
|
151
|
+
const name = positional[0]
|
|
152
|
+
if (!name) {
|
|
153
|
+
console.error(`Usage: opm ${this.name} view <name> [-g]`)
|
|
154
|
+
process.exit(1)
|
|
155
|
+
}
|
|
156
|
+
const result = await manager.isInstalled(name, { global: !!opts.global })
|
|
157
|
+
output(result)
|
|
158
|
+
break
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
case 'info': {
|
|
162
|
+
const name = positional[0]
|
|
163
|
+
if (!name) {
|
|
164
|
+
console.error(`Usage: opm ${this.name} info <name>`)
|
|
165
|
+
process.exit(1)
|
|
166
|
+
}
|
|
167
|
+
const result = await manager.packageInfo(name, { proxy: opts.proxy })
|
|
168
|
+
output(result)
|
|
169
|
+
break
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
case 'versions': {
|
|
173
|
+
const name = positional[0]
|
|
174
|
+
if (!name) {
|
|
175
|
+
console.error(`Usage: opm ${this.name} versions <name>`)
|
|
176
|
+
process.exit(1)
|
|
177
|
+
}
|
|
178
|
+
const result = await manager.packageVersions(name, { proxy: opts.proxy })
|
|
179
|
+
output(result)
|
|
180
|
+
break
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
case 'list': {
|
|
184
|
+
const result = await manager.listInstalled({ global: !!opts.global })
|
|
185
|
+
output(result)
|
|
186
|
+
break
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
case 'outdated': {
|
|
190
|
+
const result = await manager.listOutdated({ global: !!opts.global, proxy: opts.proxy })
|
|
191
|
+
output(result)
|
|
192
|
+
break
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
case 'install': {
|
|
196
|
+
const name = positional[0]
|
|
197
|
+
const version = positional[1]
|
|
198
|
+
if (!name) {
|
|
199
|
+
console.error(`Usage: opm ${this.name} install <name> [version]`)
|
|
200
|
+
process.exit(1)
|
|
201
|
+
}
|
|
202
|
+
const result = await manager.install(name, version, { global: !!opts.global, proxy: opts.proxy })
|
|
203
|
+
output(result)
|
|
204
|
+
break
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
case 'uninstall': {
|
|
208
|
+
const name = positional[0]
|
|
209
|
+
if (!name) {
|
|
210
|
+
console.error(`Usage: opm ${this.name} uninstall <name>`)
|
|
211
|
+
process.exit(1)
|
|
212
|
+
}
|
|
213
|
+
const result = await manager.uninstall(name, { global: !!opts.global })
|
|
214
|
+
output(result)
|
|
215
|
+
break
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
case 'upgrade': {
|
|
219
|
+
const name = positional[0]
|
|
220
|
+
if (!name) {
|
|
221
|
+
console.error(`Usage: opm ${this.name} upgrade <name>`)
|
|
222
|
+
process.exit(1)
|
|
223
|
+
}
|
|
224
|
+
const result = await manager.upgrade(name, { global: !!opts.global, proxy: opts.proxy })
|
|
225
|
+
output(result)
|
|
226
|
+
break
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
case 'cache': {
|
|
230
|
+
if (positional[0] !== 'clean') {
|
|
231
|
+
console.error(`Usage: opm ${this.name} cache clean`)
|
|
232
|
+
process.exit(1)
|
|
233
|
+
}
|
|
234
|
+
const result = await manager.cleanCache()
|
|
235
|
+
output(result)
|
|
236
|
+
break
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
default:
|
|
240
|
+
console.error(`Unknown action: ${action}`)
|
|
241
|
+
process.exit(1)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
printHelp() {
|
|
246
|
+
console.log(`
|
|
247
|
+
Usage: opm ${this.name} <action> [args] [options]
|
|
248
|
+
|
|
249
|
+
Actions:
|
|
250
|
+
version Show ${this.name} version
|
|
251
|
+
installed Check if ${this.name} itself is installed
|
|
252
|
+
registry Show active registry (from opm config)
|
|
253
|
+
registry set <url|preset> Set active registry (writes opm config)
|
|
254
|
+
registry presets List available mirror presets
|
|
255
|
+
search <name> [version] Check package availability in source
|
|
256
|
+
view <name> [-g] Check if package is installed (local or global)
|
|
257
|
+
info <name> Show package details
|
|
258
|
+
versions <name> List all available versions
|
|
259
|
+
list [-g] List all installed packages
|
|
260
|
+
outdated [-g] List outdated packages
|
|
261
|
+
install <name> [version] Install a package
|
|
262
|
+
uninstall <name> Uninstall a package
|
|
263
|
+
upgrade <name> Upgrade a package to latest
|
|
264
|
+
cache clean Clean cache
|
|
265
|
+
help Show this help
|
|
266
|
+
|
|
267
|
+
Options:
|
|
268
|
+
-g, --global Global operation (npm: global node_modules; pip: system Python)
|
|
269
|
+
-p, --proxy <url> Proxy address (search/info/versions/outdated/install/upgrade);
|
|
270
|
+
overrides config proxy.active when provided
|
|
271
|
+
-h, --help Show this help
|
|
272
|
+
|
|
273
|
+
Examples:
|
|
274
|
+
opm ${this.name} registry
|
|
275
|
+
opm ${this.name} registry set <preset|url>
|
|
276
|
+
opm ${this.name} search <name>
|
|
277
|
+
opm ${this.name} view <name>
|
|
278
|
+
opm ${this.name} info <name>
|
|
279
|
+
opm ${this.name} versions <name>
|
|
280
|
+
opm ${this.name} list
|
|
281
|
+
opm ${this.name} outdated
|
|
282
|
+
opm ${this.name} install <name>
|
|
283
|
+
opm ${this.name} uninstall <name>
|
|
284
|
+
opm ${this.name} upgrade <name>
|
|
285
|
+
opm ${this.name} cache clean
|
|
286
|
+
`)
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* 运行时版本管理器元数据(node / php / python)
|
|
292
|
+
* 由 RuntimeGroup 据此生成一致的帮助文本。
|
|
293
|
+
*/
|
|
294
|
+
const RUNTIME_META = {
|
|
295
|
+
node: {
|
|
296
|
+
label: 'Node.js',
|
|
297
|
+
tool: 'nvm',
|
|
298
|
+
versionsHint: 'nvm ls-remote',
|
|
299
|
+
listHint: 'nvm ls',
|
|
300
|
+
useHint: 'nvm use',
|
|
301
|
+
currentHint: 'nvm current',
|
|
302
|
+
defaultHint: 'nvm alias default',
|
|
303
|
+
latest: 'LTS',
|
|
304
|
+
installExample: '20',
|
|
305
|
+
useExample: '20',
|
|
306
|
+
searchExample: 'v20.20.2',
|
|
307
|
+
uninstallExample: '18',
|
|
308
|
+
},
|
|
309
|
+
php: {
|
|
310
|
+
label: 'PHP',
|
|
311
|
+
tool: 'phpenv',
|
|
312
|
+
versionsHint: 'phpenv install --list',
|
|
313
|
+
listHint: 'phpenv versions',
|
|
314
|
+
useHint: 'phpenv global',
|
|
315
|
+
currentHint: 'phpenv version',
|
|
316
|
+
defaultHint: 'phpenv global',
|
|
317
|
+
latest: '',
|
|
318
|
+
installExample: '8.3',
|
|
319
|
+
useExample: '8.3',
|
|
320
|
+
searchExample: '8.3.13',
|
|
321
|
+
uninstallExample: '8.2',
|
|
322
|
+
},
|
|
323
|
+
python: {
|
|
324
|
+
label: 'Python',
|
|
325
|
+
tool: 'uv',
|
|
326
|
+
versionsHint: 'uv python list',
|
|
327
|
+
listHint: 'uv python list --only-installed',
|
|
328
|
+
useHint: 'uv python pin',
|
|
329
|
+
currentHint: 'python --version',
|
|
330
|
+
defaultHint: '~/.python-version',
|
|
331
|
+
latest: '',
|
|
332
|
+
installExample: '3.12',
|
|
333
|
+
useExample: '3.12',
|
|
334
|
+
searchExample: '3.12.4',
|
|
335
|
+
uninstallExample: '3.11',
|
|
336
|
+
},
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* 运行时命令组 — 在 PackageGroup(registry/search/info/versions/list/install/...)
|
|
341
|
+
* 基础上增加 use/current/default 三个版本管理专属 action。
|
|
342
|
+
* node / php / python 共用同一实现,仅顶层命令名与帮助元数据不同。
|
|
343
|
+
*/
|
|
344
|
+
export class RuntimeGroup extends PackageGroup {
|
|
345
|
+
constructor(managerName) {
|
|
346
|
+
super(managerName)
|
|
347
|
+
this.meta = RUNTIME_META[managerName]
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
async run(argv) {
|
|
351
|
+
const [action, ...rest] = argv
|
|
352
|
+
|
|
353
|
+
if (!action || action === '-h' || action === '--help' || action === 'help') {
|
|
354
|
+
this.printHelp()
|
|
355
|
+
return
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const runtimeActions = new Set(['use', 'current', 'default', 'installed', 'dir', 'install', 'upgrade', 'search', 'versions'])
|
|
359
|
+
if (runtimeActions.has(action)) {
|
|
360
|
+
const manager = MANAGERS[this.name]()
|
|
361
|
+
const parsed = parseFlags(rest)
|
|
362
|
+
let proxy = parsed.flags.proxy || parsed.flags.p || ''
|
|
363
|
+
if (proxy === 'true') proxy = ''
|
|
364
|
+
if (!proxy) proxy = getActiveProxy()
|
|
365
|
+
await this._dispatch(manager, action, parsed, { global: false, proxy })
|
|
366
|
+
return
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return super.run(argv)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async _dispatch(manager, action, parsed, opts) {
|
|
373
|
+
const { positional } = parsed
|
|
374
|
+
|
|
375
|
+
switch (action) {
|
|
376
|
+
case 'installed': {
|
|
377
|
+
const result = await manager.getVersion()
|
|
378
|
+
const toolInstalled = manager.cfg.isInstalled()
|
|
379
|
+
output({
|
|
380
|
+
name: result.name,
|
|
381
|
+
installed: result.installed,
|
|
382
|
+
...(result.version ? { version: result.version } : {}),
|
|
383
|
+
...(result.hint ? { hint: result.hint } : {}),
|
|
384
|
+
tool: { name: this.meta.tool, installed: toolInstalled },
|
|
385
|
+
})
|
|
386
|
+
break
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
case 'use': {
|
|
390
|
+
const version = positional[0]
|
|
391
|
+
if (!version) {
|
|
392
|
+
console.error(`Usage: opm ${this.name} use <version>`)
|
|
393
|
+
process.exit(1)
|
|
394
|
+
}
|
|
395
|
+
const result = await manager.useVersion(version, { proxy: opts.proxy })
|
|
396
|
+
output(result)
|
|
397
|
+
break
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
case 'current': {
|
|
401
|
+
const result = await manager.currentVersion()
|
|
402
|
+
output(result)
|
|
403
|
+
break
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
case 'default': {
|
|
407
|
+
const version = positional[0]
|
|
408
|
+
if (!version) {
|
|
409
|
+
console.error(`Usage: opm ${this.name} default <version>`)
|
|
410
|
+
process.exit(1)
|
|
411
|
+
}
|
|
412
|
+
const result = await manager.setDefault(version)
|
|
413
|
+
output(result)
|
|
414
|
+
break
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
case 'dir': {
|
|
418
|
+
const install = manager.getInstallDir ? manager.getInstallDir() : ''
|
|
419
|
+
output({
|
|
420
|
+
name: this.name,
|
|
421
|
+
install,
|
|
422
|
+
})
|
|
423
|
+
break
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
case 'install': {
|
|
427
|
+
const version = positional[0] || (manager.getDefaultVersion ? manager.getDefaultVersion() : '')
|
|
428
|
+
if (!version) {
|
|
429
|
+
console.error(`Usage: opm ${this.name} install <version>`)
|
|
430
|
+
process.exit(1)
|
|
431
|
+
}
|
|
432
|
+
const result = await manager.install(this.name, version, { proxy: opts.proxy })
|
|
433
|
+
output(result)
|
|
434
|
+
break
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
case 'upgrade': {
|
|
438
|
+
const result = await manager.upgrade(this.name, { proxy: opts.proxy })
|
|
439
|
+
output(result)
|
|
440
|
+
break
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
case 'search': {
|
|
444
|
+
const version = positional[0]
|
|
445
|
+
if (!version) {
|
|
446
|
+
console.error(`Usage: opm ${this.name} search <version>`)
|
|
447
|
+
process.exit(1)
|
|
448
|
+
}
|
|
449
|
+
const result = await manager.searchPackage(this.name, version, { proxy: opts.proxy })
|
|
450
|
+
output(result)
|
|
451
|
+
break
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
case 'versions': {
|
|
455
|
+
const result = await manager.packageVersions(this.name, { proxy: opts.proxy })
|
|
456
|
+
output(result)
|
|
457
|
+
break
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
default:
|
|
461
|
+
return super._dispatch(manager, action, parsed, opts)
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* 依据元数据生成一致的运行时帮助文本
|
|
467
|
+
*/
|
|
468
|
+
printHelp() {
|
|
469
|
+
const { label, tool, versionsHint, listHint, useHint, currentHint, defaultHint, latest, installExample, useExample, searchExample, uninstallExample } = this.meta
|
|
470
|
+
const latestLabel = latest ? ` install latest ${latest}` : ''
|
|
471
|
+
const installDesc = `Install a ${label} version (e.g. ${installExample}${latest ? `, --lts` : ''})`
|
|
472
|
+
console.log(`
|
|
473
|
+
Usage: opm ${this.name} <action> [args] [options]
|
|
474
|
+
|
|
475
|
+
Actions:
|
|
476
|
+
version Show current ${label} version
|
|
477
|
+
installed Check if ${label} is installed (and its version manager ${tool})
|
|
478
|
+
registry Show active ${label} dist/source mirror (from opm config)
|
|
479
|
+
registry set <url|preset> Set active ${label} mirror (writes opm config)
|
|
480
|
+
registry presets List available mirror presets
|
|
481
|
+
search <version> Check if a ${label} version is available for download
|
|
482
|
+
view <version> Check if a ${label} version is installed
|
|
483
|
+
versions List all available ${label} versions (${versionsHint})
|
|
484
|
+
list List installed ${label} versions (${listHint})
|
|
485
|
+
install [version] ${installDesc} (default: config defaultVersion)
|
|
486
|
+
uninstall <version> Uninstall a ${label} version
|
|
487
|
+
upgrade ${latest ? 'Install latest ' + latest : 'Install latest'} ${label}
|
|
488
|
+
use <version> Switch to a ${label} version (${useHint})
|
|
489
|
+
current Show current active ${label} version (${currentHint})
|
|
490
|
+
default <version> Set default ${label} version (${defaultHint})
|
|
491
|
+
dir Show ${label} install directory
|
|
492
|
+
help Show this help
|
|
493
|
+
|
|
494
|
+
Options:
|
|
495
|
+
-p, --proxy <url> Proxy address (search/versions/install/upgrade/use)
|
|
496
|
+
-h, --help Show this help
|
|
497
|
+
|
|
498
|
+
Examples:
|
|
499
|
+
opm ${this.name} current
|
|
500
|
+
opm ${this.name} install ${installExample}
|
|
501
|
+
opm ${this.name} use ${useExample}
|
|
502
|
+
opm ${this.name} default ${useExample}
|
|
503
|
+
opm ${this.name} dir
|
|
504
|
+
opm ${this.name} list
|
|
505
|
+
opm ${this.name} versions
|
|
506
|
+
opm ${this.name} search ${searchExample}
|
|
507
|
+
opm ${this.name} view ${searchExample}
|
|
508
|
+
opm ${this.name} uninstall ${uninstallExample}
|
|
509
|
+
opm ${this.name} upgrade
|
|
510
|
+
`)
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export { MANAGERS, ACTIONS }
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* phpenv 命令组 — 管理 phpenv 自身
|
|
3
|
+
*
|
|
4
|
+
* phpenv 是常规二进制(~/.phpenv/bin/phpenv),通过 git clone 安装;
|
|
5
|
+
* install = git clone phpenv + git clone php-build plugin + 写 shell profile;
|
|
6
|
+
* upgrade = git pull(含 php-build 插件);uninstall = rm -rf ~/.phpenv。
|
|
7
|
+
* registry 是 phpenv 的 git 镜像地址(official / gitee)。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { execSync } from 'node:child_process'
|
|
11
|
+
import fs from 'node:fs'
|
|
12
|
+
import path from 'node:path'
|
|
13
|
+
import os from 'node:os'
|
|
14
|
+
import { ToolManagerGroup } from './version-manager.js'
|
|
15
|
+
import { Shell } from '@wwkit/shared'
|
|
16
|
+
import { getActiveRegistry } from '../../config.js'
|
|
17
|
+
import { installPhpenv } from '../../managers/php.js'
|
|
18
|
+
|
|
19
|
+
const shell = new Shell()
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 获取 phpenv 根目录
|
|
23
|
+
* @returns {string}
|
|
24
|
+
*/
|
|
25
|
+
function getPhpenvRoot() {
|
|
26
|
+
return process.env.PHPENV_ROOT || path.join(os.homedir(), '.phpenv')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 获取 phpenv 二进制路径
|
|
31
|
+
* @returns {string}
|
|
32
|
+
*/
|
|
33
|
+
function getPhpenvBin() {
|
|
34
|
+
return path.join(getPhpenvRoot(), 'bin', 'phpenv')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class PhpenvGroup extends ToolManagerGroup {
|
|
38
|
+
constructor() {
|
|
39
|
+
super({
|
|
40
|
+
name: 'phpenv',
|
|
41
|
+
desc: 'phpenv version manager (manage phpenv itself)',
|
|
42
|
+
needsBash: true,
|
|
43
|
+
isInstalled: () => fs.existsSync(getPhpenvBin()),
|
|
44
|
+
getPath: () => getPhpenvRoot(),
|
|
45
|
+
versionCmd: () => `${getPhpenvBin()} --version`,
|
|
46
|
+
parseVersion: (out) => {
|
|
47
|
+
const m = out.trim().match(/phpenv\s+([\d.]+)/)
|
|
48
|
+
return m ? m[1] : out.trim()
|
|
49
|
+
},
|
|
50
|
+
install: () => installPhpenv(),
|
|
51
|
+
upgrade: () => {
|
|
52
|
+
execSync(`cd "${getPhpenvRoot()}" && git remote set-url origin "${getActiveRegistry('phpenv')}" && git pull --tags`, {
|
|
53
|
+
stdio: 'inherit',
|
|
54
|
+
shell: shell.resolveBash(),
|
|
55
|
+
})
|
|
56
|
+
const pluginsDir = path.join(getPhpenvRoot(), 'plugins', 'php-build')
|
|
57
|
+
if (fs.existsSync(pluginsDir)) {
|
|
58
|
+
execSync(`cd "${pluginsDir}" && git pull`, { stdio: 'inherit', shell: shell.resolveBash() })
|
|
59
|
+
}
|
|
60
|
+
return { action: 'upgraded' }
|
|
61
|
+
},
|
|
62
|
+
uninstall: () => {
|
|
63
|
+
fs.rmSync(getPhpenvRoot(), { recursive: true, force: true })
|
|
64
|
+
return { action: 'uninstalled', hint: 'Remove PHPENV_ROOT/init line from shell profile manually' }
|
|
65
|
+
},
|
|
66
|
+
usage: 'opm phpenv <action> [args] [options]',
|
|
67
|
+
actions: [
|
|
68
|
+
['version', 'Show phpenv version'],
|
|
69
|
+
['installed', 'Check if phpenv is installed'],
|
|
70
|
+
['registry', 'Show active phpenv git mirror (from opm config)'],
|
|
71
|
+
['registry set <url|preset>', 'Set active phpenv git mirror (writes opm config)'],
|
|
72
|
+
['registry presets', 'List available mirror presets'],
|
|
73
|
+
['install', 'Install phpenv (git clone + php-build plugin + shell profile)'],
|
|
74
|
+
['upgrade', 'Update phpenv and php-build plugin (git pull)'],
|
|
75
|
+
['uninstall', 'Remove phpenv (~/.phpenv)'],
|
|
76
|
+
['dir', 'Show phpenv install directory'],
|
|
77
|
+
['help', 'Show this help'],
|
|
78
|
+
],
|
|
79
|
+
examples: [
|
|
80
|
+
'opm phpenv version',
|
|
81
|
+
'opm phpenv installed',
|
|
82
|
+
'opm phpenv registry set gitee',
|
|
83
|
+
'opm phpenv install',
|
|
84
|
+
'opm phpenv upgrade',
|
|
85
|
+
'opm phpenv dir',
|
|
86
|
+
],
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* uv 命令组 — 管理 uv 自身
|
|
3
|
+
*
|
|
4
|
+
* uv 是 Astral 出品的快速 Python 包/版本管理器(Rust 实现)。
|
|
5
|
+
* 安装方式:curl 安装脚本(非 git clone);
|
|
6
|
+
* upgrade = uv self update;uninstall = rm 二进制 + 数据目录。
|
|
7
|
+
* uv 无镜像源,故无 registry action。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { execSync, spawnSync } from 'node:child_process'
|
|
11
|
+
import fs from 'node:fs'
|
|
12
|
+
import path from 'node:path'
|
|
13
|
+
import os from 'node:os'
|
|
14
|
+
import { ToolManagerGroup } from './version-manager.js'
|
|
15
|
+
import { installUv, getUvBin } from '../../managers/python.js'
|
|
16
|
+
|
|
17
|
+
const UV_INSTALL_URL = 'https://astral.sh/uv/install.sh'
|
|
18
|
+
const UV_INSTALL_PS_URL = 'https://astral.sh/uv/install.ps1'
|
|
19
|
+
|
|
20
|
+
export class UvGroup extends ToolManagerGroup {
|
|
21
|
+
constructor() {
|
|
22
|
+
super({
|
|
23
|
+
name: 'uv',
|
|
24
|
+
desc: 'uv version manager (manage uv itself)',
|
|
25
|
+
hasRegistry: false,
|
|
26
|
+
isInstalled: () => {
|
|
27
|
+
try {
|
|
28
|
+
execSync(`${getUvBin()} --version`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] })
|
|
29
|
+
return true
|
|
30
|
+
} catch {
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
getPath: () => getUvBin(),
|
|
35
|
+
versionCmd: () => `${getUvBin()} --version`,
|
|
36
|
+
parseVersion: (out) => out.trim(),
|
|
37
|
+
install: () => installUv(),
|
|
38
|
+
upgrade: () => {
|
|
39
|
+
execSync(`${getUvBin()} self update`, { stdio: 'inherit' })
|
|
40
|
+
return { action: 'upgraded' }
|
|
41
|
+
},
|
|
42
|
+
uninstall: () => {
|
|
43
|
+
const bin = getUvBin()
|
|
44
|
+
if (bin !== 'uv' && fs.existsSync(bin)) {
|
|
45
|
+
fs.rmSync(bin, { force: true })
|
|
46
|
+
}
|
|
47
|
+
const dataDir = path.join(os.homedir(), '.local', 'share', 'uv')
|
|
48
|
+
if (fs.existsSync(dataDir)) {
|
|
49
|
+
fs.rmSync(dataDir, { recursive: true, force: true })
|
|
50
|
+
}
|
|
51
|
+
return { action: 'uninstalled', hint: 'Remove ~/.local/bin from PATH manually if needed' }
|
|
52
|
+
},
|
|
53
|
+
usage: 'opm uv <action> [options]',
|
|
54
|
+
actions: [
|
|
55
|
+
['version', 'Show uv version'],
|
|
56
|
+
['installed', 'Check if uv is installed'],
|
|
57
|
+
['install', 'Install uv (curl installer from astral.sh)'],
|
|
58
|
+
['upgrade', 'Update uv (uv self update)'],
|
|
59
|
+
['uninstall', 'Remove uv (~/.local/bin/uv + ~/.local/share/uv)'],
|
|
60
|
+
['dir', 'Show uv install directory'],
|
|
61
|
+
['help', 'Show this help'],
|
|
62
|
+
],
|
|
63
|
+
examples: [
|
|
64
|
+
'opm uv version',
|
|
65
|
+
'opm uv installed',
|
|
66
|
+
'opm uv install',
|
|
67
|
+
'opm uv upgrade',
|
|
68
|
+
'opm uv dir',
|
|
69
|
+
'opm uv uninstall',
|
|
70
|
+
],
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
}
|