2020-05-11 01:12:35 +02:00
|
|
|
#!/usr/bin/env node
|
|
|
|
|
2021-04-29 17:35:59 +02:00
|
|
|
import chalk from 'chalk'
|
2022-08-01 17:16:35 +02:00
|
|
|
import cp from 'child_process'
|
2021-04-29 17:35:59 +02:00
|
|
|
import inquirer from 'inquirer'
|
2020-05-11 00:53:00 +02:00
|
|
|
|
2022-08-01 17:16:35 +02:00
|
|
|
const VERSION = '1.3.0'
|
|
|
|
|
|
|
|
class ListEntry {
|
|
|
|
name!: string
|
|
|
|
type!: 'package' | 'cask'
|
|
|
|
|
|
|
|
constructor(options: ListEntry) {
|
|
|
|
Object.assign(this, options)
|
|
|
|
}
|
|
|
|
|
|
|
|
toString() {
|
|
|
|
return `${this.type === 'package' ? '📦' : '🍾'} ${this.name}`
|
|
|
|
}
|
|
|
|
|
|
|
|
static parse(line: string): ListEntry {
|
|
|
|
const [type, name] = line.split(' ')
|
|
|
|
if (!name) throw new Error('Could not parse line')
|
|
|
|
if (type === '📦') return new ListEntry({ name, type: 'package' })
|
|
|
|
if (type === '🍾') return new ListEntry({ name, type: 'cask' })
|
|
|
|
throw new Error('Could not parse type')
|
|
|
|
}
|
|
|
|
}
|
2020-11-07 13:22:31 +01:00
|
|
|
|
2020-05-11 00:53:00 +02:00
|
|
|
function checkIfBrewIsInstalled() {
|
|
|
|
try {
|
|
|
|
cp.execSync('brew --version')
|
|
|
|
return true
|
|
|
|
} catch (e) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-01 17:16:35 +02:00
|
|
|
function getListOfPackages(): ListEntry[] {
|
2020-05-11 00:53:00 +02:00
|
|
|
const list = cp.execSync('brew leaves', { encoding: 'utf-8' })
|
2022-08-01 17:16:35 +02:00
|
|
|
return list
|
|
|
|
.trim()
|
|
|
|
.split('\n')
|
|
|
|
.map((line) => new ListEntry({ name: line, type: 'package' }))
|
|
|
|
}
|
|
|
|
|
|
|
|
function getListOfCasks(): ListEntry[] {
|
|
|
|
const list = cp.execSync('brew list --cask -1', { encoding: 'utf-8' })
|
|
|
|
return list
|
|
|
|
.trim()
|
|
|
|
.split('\n')
|
|
|
|
.map((line) => new ListEntry({ name: line, type: 'cask' }))
|
2020-05-11 00:53:00 +02:00
|
|
|
}
|
|
|
|
|
2022-08-01 17:16:35 +02:00
|
|
|
function getList(cask: boolean): ListEntry[] {
|
|
|
|
const list = getListOfPackages()
|
|
|
|
if (cask) list.push(...getListOfCasks())
|
|
|
|
return list
|
|
|
|
}
|
|
|
|
|
|
|
|
function getLoosers(keepers: ListEntry[], leaves: ListEntry[]): ListEntry[] {
|
|
|
|
return leaves.filter((leave) => !keepers.some((keeper) => keeper.name === leave.name))
|
2020-05-11 00:53:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
async function main() {
|
|
|
|
if (!checkIfBrewIsInstalled()) {
|
|
|
|
console.log(chalk.red.underline('Brew not installed'))
|
|
|
|
return
|
|
|
|
}
|
2022-03-20 18:38:56 +01:00
|
|
|
console.log(`${chalk.bold.blue('UnBrew')} - Brew cleanup utility\nVersion: ${VERSION}\n`)
|
2020-05-11 00:53:00 +02:00
|
|
|
|
2022-08-01 17:16:35 +02:00
|
|
|
const { cask } = await inquirer.prompt([
|
|
|
|
{
|
|
|
|
type: 'confirm',
|
|
|
|
name: 'cask',
|
|
|
|
message: `Also consider casks?`,
|
|
|
|
},
|
|
|
|
])
|
|
|
|
|
|
|
|
let initialState = getList(cask)
|
2020-05-11 18:14:32 +02:00
|
|
|
|
2020-05-11 00:53:00 +02:00
|
|
|
const { keepers } = await inquirer.prompt([
|
|
|
|
{
|
|
|
|
type: 'checkbox',
|
2020-05-11 18:14:32 +02:00
|
|
|
message: 'Select packages to keep (all by default)',
|
2020-05-11 00:53:00 +02:00
|
|
|
name: 'keepers',
|
2022-08-01 17:16:35 +02:00
|
|
|
choices: initialState.map((entry) => ({
|
|
|
|
name: entry,
|
2020-05-11 00:53:00 +02:00
|
|
|
checked: true,
|
|
|
|
})),
|
|
|
|
},
|
|
|
|
])
|
|
|
|
|
2022-08-01 17:16:35 +02:00
|
|
|
// Uninstalling
|
|
|
|
let first = true
|
|
|
|
let allUninstalled: ListEntry[] = []
|
|
|
|
while (true) {
|
|
|
|
// Get all to be uninstalled
|
|
|
|
const loosers = getLoosers(keepers, first ? initialState : getList(cask))
|
2020-05-11 00:53:00 +02:00
|
|
|
|
2022-08-01 17:16:35 +02:00
|
|
|
// First time prompt
|
|
|
|
if (first) {
|
|
|
|
if (loosers.length === 0) {
|
|
|
|
console.log(chalk.bold('No package/s selected for deletion.'))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const { confirmed } = await inquirer.prompt([
|
|
|
|
{
|
|
|
|
type: 'confirm',
|
|
|
|
name: 'confirmed',
|
|
|
|
message: `Delelte: ${chalk.bold.blue(loosers.map((l) => l.name).join(', '))} and their dependencies?`,
|
|
|
|
},
|
|
|
|
])
|
|
|
|
|
|
|
|
if (!confirmed) {
|
|
|
|
console.log(chalk.bold.red('Aborted'))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
console.log('🗑 Uninstalling')
|
|
|
|
first = false
|
|
|
|
}
|
2020-05-11 18:14:32 +02:00
|
|
|
|
2022-08-01 17:16:35 +02:00
|
|
|
// Actual uninstalling
|
|
|
|
if (loosers.length === 0) break
|
|
|
|
allUninstalled.push(...loosers)
|
|
|
|
cp.execSync(`brew uninstall ${loosers.map((l) => l.name).join(' ')}`)
|
2020-05-11 01:12:35 +02:00
|
|
|
}
|
2022-08-01 17:16:35 +02:00
|
|
|
|
|
|
|
console.log('✅ Uninstalled: ' + allUninstalled.join(', '))
|
2020-05-11 18:14:32 +02:00
|
|
|
|
2020-05-11 00:53:00 +02:00
|
|
|
console.log('🧽 Cleaning up')
|
|
|
|
cp.execSync(`brew cleanup`)
|
2020-05-11 18:14:32 +02:00
|
|
|
|
2020-05-11 00:53:00 +02:00
|
|
|
console.log(chalk.bold.green('🚀 Done'))
|
|
|
|
}
|
2020-12-29 21:35:49 +01:00
|
|
|
main().finally(() => {
|
2022-08-01 17:16:35 +02:00
|
|
|
console.log(chalk.blue('👋 Bye Bye'))
|
2020-12-29 21:35:49 +01:00
|
|
|
})
|