-
Notifications
You must be signed in to change notification settings - Fork 308
/
manifest.ts
125 lines (100 loc) · 4.21 KB
/
manifest.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import {Args, Command, Plugin, ux, Flags, Interfaces} from '@oclif/core'
import * as fs from 'fs-extra'
import * as path from 'path'
import * as os from 'os'
import * as semver from 'semver'
import {exec, ShellString, ExecOptions} from 'shelljs'
async function fileExists(filePath: string): Promise<boolean> {
try {
await fs.access(filePath)
return true
} catch {
return false
}
}
export default class Manifest extends Command {
static description = 'generates plugin manifest json'
static args = {
path: Args.string({description: 'path to plugin', default: '.'}),
}
static flags = {
jit: Flags.boolean({
allowNo: true,
summary: 'append commands from JIT plugins in manifest',
default: true,
}),
}
async run(): Promise<void> {
const {flags} = await this.parse(Manifest)
try {
fs.unlinkSync('oclif.manifest.json')
} catch {}
const {args} = await this.parse(Manifest)
const root = path.resolve(args.path)
const packageJson = fs.readJSONSync('package.json') as { oclif: { jitPlugins: Record<string, string> } }
let jitPluginManifests: Interfaces.Manifest[] = []
if (flags.jit && packageJson.oclif?.jitPlugins) {
this.debug('jitPlugins: %s', packageJson.oclif.jitPlugins)
const tmpDir = os.tmpdir()
const promises = Object.entries(packageJson.oclif.jitPlugins).map(async ([jitPlugin, version]) => {
const pluginDir = jitPlugin.replace('/', '-').replace('@', '')
const repo = this.executeCommand(`npm view ${jitPlugin}@latest repository --json`)
const stdout = JSON.parse(repo.stdout)
const repoUrl = stdout.url.replace(`${stdout.type}+`, '')
const fullPath = path.join(tmpDir, pluginDir)
if (await fileExists(fullPath)) await fs.remove(fullPath)
const versions = JSON.parse(this.executeCommand(`npm view ${jitPlugin}@latest versions --json`).stdout)
const maxSatisfying = semver.maxSatisfying(versions, version)
this.cloneRepo(repoUrl, fullPath, maxSatisfying)
this.executeCommand('yarn', {cwd: fullPath})
this.executeCommand('yarn tsc', {cwd: fullPath})
const plugin = new Plugin({root: fullPath, type: 'jit', ignoreManifest: true, errorOnManifestCreate: true})
await plugin.load()
return plugin.manifest
})
ux.action.start('Generating JIT plugin manifests')
jitPluginManifests = await Promise.all(promises)
ux.action.stop()
}
let plugin = new Plugin({root, type: 'core', ignoreManifest: true, errorOnManifestCreate: true})
if (!plugin) throw new Error('plugin not found')
await plugin.load(true)
if (!plugin.valid) {
const p = require.resolve('@oclif/plugin-legacy', {paths: [process.cwd()]})
const {PluginLegacy} = require(p)
plugin = new PluginLegacy(this.config, plugin)
await plugin.load()
}
if (process.env.OCLIF_NEXT_VERSION) {
plugin.manifest.version = process.env.OCLIF_NEXT_VERSION
}
const dotfile = plugin.pjson.files.find((f: string) => f.endsWith('.oclif.manifest.json'))
const file = path.join(plugin.root, `${dotfile ? '.' : ''}oclif.manifest.json`)
for (const manifest of jitPluginManifests) {
plugin.manifest.commands = {...plugin.manifest.commands, ...manifest.commands}
}
fs.writeFileSync(file, JSON.stringify(plugin.manifest, null, 2))
this.log(`wrote manifest to ${file}`)
}
private cloneRepo(repoUrl: string, fullPath: string, tag: string | semver.SemVer | null): void {
try {
this.executeCommand(`git clone --branch ${tag} ${repoUrl} ${fullPath} --depth 1`)
} catch {
try {
this.executeCommand(`git clone --branch v${tag} ${repoUrl} ${fullPath} --depth 1`)
} catch {
throw new Error(`Unable to clone repo ${repoUrl} with tag ${tag}`)
}
}
}
private executeCommand(command: string, options?: ExecOptions): ShellString {
const debugString = options?.cwd ? `executing command: ${command} in ${options.cwd}` : `executing command: ${command}`
this.debug(debugString)
const result = exec(command, {...options, silent: true, async: false})
if (result.code !== 0) {
this.error(result.stderr)
}
this.debug(result.stdout)
return result
}
}