Skip to content

Commit

Permalink
feat: use existing versions if available (#223)
Browse files Browse the repository at this point in the history
* feat: use existing versions if available

* chore: fix lint errors

* feat: add --from-local flag
  • Loading branch information
amphro authored Mar 15, 2021
1 parent 49c9524 commit da27783
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
/package-lock.json
/tmp
/oclif-plugin-update-*.tgz
/.vscode
81 changes: 62 additions & 19 deletions src/commands/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default class UpdateCommand extends Command {

static flags: flags.Input<any> = {
autoupdate: flags.boolean({hidden: true}),
'from-local': flags.boolean({description: 'interactively choose an already installed version'}),
}

private autoupdate!: boolean
Expand All @@ -38,25 +39,52 @@ export default class UpdateCommand extends Command {

if (this.autoupdate) await this.debounce()

cli.action.start(`${this.config.name}: Updating CLI`)
this.channel = args.channel || await this.determineChannel()
await this.config.runHook('preupdate', {channel: this.channel})
const manifest = await this.fetchManifest()
this.currentVersion = await this.determineCurrentVersion()
this.updatedVersion = (manifest as any).sha ? `${manifest.version}-${(manifest as any).sha}` : manifest.version
const reason = await this.skipUpdate()
if (reason) cli.action.stop(reason || 'done')
else await this.update(manifest)
this.debug('tidy')
await this.tidy()
await this.config.runHook('update', {channel: this.channel})

if (flags['from-local']) {
await this.ensureClientDir()
this.debug(`Looking for locally installed versions at ${this.clientRoot}`)

// Do not show known non-local version folder names, bin and current.
const versions = fs.readdirSync(this.clientRoot).filter(dirOrFile => dirOrFile !== 'bin' && dirOrFile !== 'current')
if (versions.length === 0) throw new Error('No locally installed versions found.')

this.log(`Found versions: \n${versions.map(version => ` ${version}`).join('\n')}\n`)

const pinToVersion = await cli.prompt('Enter a version to update to')
if (!versions.includes(pinToVersion)) throw new Error(`Version ${pinToVersion} not found in the locally installed versions.`)

if (!await fs.pathExists(path.join(this.clientRoot, pinToVersion))) {
throw new Error(`Version ${pinToVersion} is not already installed at ${this.clientRoot}.`)
}
cli.action.start(`${this.config.name}: Updating CLI`)
this.debug(`switching to existing version ${pinToVersion}`)
this.updateToExistingVersion(pinToVersion)

this.log()
this.log(`Updating to an already installed version will not update the channel. If autoupdate is enabled, the CLI will eventually be updated back to ${this.channel}.`)
} else {
cli.action.start(`${this.config.name}: Updating CLI`)
await this.config.runHook('preupdate', {channel: this.channel})
const manifest = await this.fetchManifest()
this.currentVersion = await this.determineCurrentVersion()
this.updatedVersion = (manifest as any).sha ? `${manifest.version}-${(manifest as any).sha}` : manifest.version
const reason = await this.skipUpdate()
if (reason) cli.action.stop(reason || 'done')
else await this.update(manifest)
this.debug('tidy')
await this.tidy()
await this.config.runHook('update', {channel: this.channel})
}

this.debug('done')
cli.action.stop()
}

private async fetchManifest(): Promise<IManifest> {
const http: typeof HTTP = require('http-call').HTTP

cli.action.status = 'fetching manifest'
if (!this.config.scopedEnvVarTrue('USE_LEGACY_UPDATE')) {
try {
const newManifestUrl = this.config.s3Url(
Expand Down Expand Up @@ -97,18 +125,15 @@ export default class UpdateCommand extends Command {
}
}

private async update(manifest: IManifest, channel = 'stable') {
const {version, channel: manifestChannel} = manifest
if (manifestChannel) channel = manifestChannel
cli.action.start(`${this.config.name}: Updating CLI from ${color.green(this.currentVersion)} to ${color.green(this.updatedVersion)}${channel === 'stable' ? '' : ' (' + color.yellow(channel) + ')'}`)
const http: typeof HTTP = require('http-call').HTTP
private async downloadAndExtract(output: string, manifest: IManifest, channel: string) {
const {version} = manifest

const filesize = (n: number): string => {
const [num, suffix] = require('filesize')(n, {output: 'array'})
return num.toFixed(1) + ` ${suffix}`
}
await this.ensureClientDir()
const output = path.join(this.clientRoot, this.updatedVersion)

const http: typeof HTTP = require('http-call').HTTP
const gzUrl = manifest.gz || this.config.s3Url(this.config.s3Key('versioned', {
version,
channel,
Expand Down Expand Up @@ -149,13 +174,31 @@ export default class UpdateCommand extends Command {

stream.resume()
await extraction
}

private async update(manifest: IManifest, channel = 'stable') {
const {channel: manifestChannel} = manifest
if (manifestChannel) channel = manifestChannel
cli.action.start(`${this.config.name}: Updating CLI from ${color.green(this.currentVersion)} to ${color.green(this.updatedVersion)}${channel === 'stable' ? '' : ' (' + color.yellow(channel) + ')'}`)

await this.ensureClientDir()
const output = path.join(this.clientRoot, this.updatedVersion)

if (!await fs.pathExists(output)) {
await this.downloadAndExtract(output, manifest, channel)
}

await this.setChannel()
await this.createBin(this.updatedVersion)
await this.touch()
await this.reexec()
}

private async updateToExistingVersion(version: string) {
await this.createBin(version)
await this.touch()
}

private async skipUpdate(): Promise<string | false> {
if (!this.config.binPath) {
const instructions = this.config.scopedEnvVar('UPDATE_INSTRUCTIONS')
Expand Down Expand Up @@ -279,7 +322,7 @@ export default class UpdateCommand extends Command {
.on('error', reject)
.on('close', (status: number) => {
try {
this.exit(status)
if (status > 0) this.exit(status)
} catch (error) {
reject(error)
}
Expand Down

0 comments on commit da27783

Please sign in to comment.