Skip to content

Commit

Permalink
feat: reset --reinstall --hard (#777)
Browse files Browse the repository at this point in the history
* feat: reset --reinstall --hard

* chore: code review

* fix: show linked plugin version

* chore: missing arrow, reinstall 'hearder'

---------

Co-authored-by: Eric Willhoit <[email protected]>
  • Loading branch information
mdonnalley and iowillhoit authored Jan 31, 2024
1 parent fcb046f commit 27504a2
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 6 deletions.
77 changes: 73 additions & 4 deletions src/commands/plugins/reset.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,89 @@
import {Command} from '@oclif/core'
/* eslint-disable no-await-in-loop */
import {Command, Flags} from '@oclif/core'
import chalk from 'chalk'
import {rm} from 'node:fs/promises'
import {join} from 'node:path'

import Plugins from '../../plugins.js'

export default class Reset extends Command {
static flags = {
hard: Flags.boolean({
summary: 'Delete node_modules and package manager related files in addition to uninstalling plugins.',
}),
reinstall: Flags.boolean({
summary: 'Reinstall all plugins after uninstalling.',
}),
}

static summary = 'Remove all user-installed and linked plugins.'

async run(): Promise<void> {
const {flags} = await this.parse(Reset)
const plugins = new Plugins(this.config)
const userPlugins = await plugins.list()

this.log(`Uninstalling ${userPlugins.length} plugin${userPlugins.length === 0 ? '' : 's'}`)
this.log(`Found ${userPlugins.length} plugin${userPlugins.length === 0 ? '' : 's'}:`)
for (const plugin of userPlugins) {
this.log(`• ${plugin.name} ${chalk.dim(`(${plugin.type})`)}`)
this.log(
`- ${plugin.name} ${chalk.dim(this.config.plugins.get(plugin.name)?.version)} ${chalk.dim(`(${plugin.type})`)}`,
)
}

await Promise.all(userPlugins.map(async (plugin) => plugins.uninstall(plugin.name)))
if (flags.hard) {
const filesToDelete = [
join(this.config.dataDir, 'node_modules'),
join(this.config.dataDir, 'package.json'),
join(this.config.dataDir, 'yarn.lock'),
join(this.config.dataDir, 'package-lock.json'),
]

this.log('✅ Removed the following files:')
for (const file of filesToDelete) {
this.log(`- ${file}`)
}

await Promise.all(filesToDelete.map((file) => rm(file, {force: true, recursive: true})))

for (const plugin of userPlugins) {
this.log(`✅ ${plugin.type === 'link' ? 'Unlinked' : 'Uninstalled'} ${plugin.name}`)
}
} else {
// These need to run sequentially so as to avoid write conflicts to the package.json
for (const plugin of userPlugins) {
try {
await plugins.uninstall(plugin.name)
this.log(`✅ ${plugin.type === 'link' ? 'Unlinked' : 'Uninstalled'} ${plugin.name}`)
} catch {
this.warn(`Failed to uninstall ${plugin.name}`)
}
}
}

if (flags.reinstall) {
this.log('Reinstall flag passed:')
// These need to run sequentially so as to avoid write conflicts to the package.json
for (const plugin of userPlugins) {
if (plugin.type === 'link') {
try {
const newPlugin = await plugins.link(plugin.root, {install: false})
const newVersion = chalk.dim(`-> ${newPlugin.version}`)
this.log(`✅ Relinked ${plugin.name} ${newVersion}`)
} catch {
this.warn(`Failed to relink ${plugin.name}`)
}
}

if (plugin.type === 'user') {
try {
const newPlugin = await plugins.install(plugin.name, {tag: plugin.tag})
const newVersion = chalk.dim(`-> ${newPlugin.version}`)
this.log(`✅ Reinstalled ${plugin.name}@${plugin.tag} ${newVersion}`)
} catch {
this.warn(`Failed to reinstall ${plugin.name}`)
}
}
}
}
}
}
6 changes: 4 additions & 2 deletions src/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,16 @@ export default class Plugins {
}
}

async link(p: string, {install}: {install: boolean}): Promise<void> {
async link(p: string, {install}: {install: boolean}): Promise<Interfaces.Config> {
const c = await Config.load(resolve(p))
ux.action.start(`${this.config.name}: linking plugin ${c.name}`)

this.isValidPlugin(c)

// refresh will cause yarn.lock to install dependencies, including devDeps
if (install) await this.refresh({all: false, prod: false}, c.root)
await this.add({name: c.name, root: c.root, type: 'link'})

return c
}

async list(): Promise<(Interfaces.PJSON.PluginTypes.Link | Interfaces.PJSON.PluginTypes.User)[]> {
Expand Down

0 comments on commit 27504a2

Please sign in to comment.