mirror of
https://github.com/cupcakearmy/unbrew.git
synced 2024-12-21 23:56:29 +00:00
add support for cask
This commit is contained in:
parent
689776d975
commit
9e892cb06e
16
CHANGELOG.md
Normal file
16
CHANGELOG.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.3.0] - 2022-08-01
|
||||
|
||||
### Added
|
||||
|
||||
- Support for casks.
|
||||
|
||||
### Security
|
||||
|
||||
- Update dependencies.
|
10
package.json
10
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "unbrew",
|
||||
"description": "brew cleanup utility",
|
||||
"version": "1.2.4",
|
||||
"version": "1.3.0",
|
||||
"author": {
|
||||
"name": "Niccolo Borgioli",
|
||||
"email": "hi@nicco.io",
|
||||
@ -32,11 +32,11 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"chalk": "^5.0.1",
|
||||
"inquirer": "^8.2.1"
|
||||
"inquirer": "^8.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/inquirer": "^8.2.0",
|
||||
"@types/node": "^16.11.26",
|
||||
"typescript": "^4.6.2"
|
||||
"@types/inquirer": "^8.2.1",
|
||||
"@types/node": "^16.11.47",
|
||||
"typescript": "^4.7.4"
|
||||
}
|
||||
}
|
||||
|
80
pnpm-lock.yaml
generated
80
pnpm-lock.yaml
generated
@ -1,38 +1,38 @@
|
||||
lockfileVersion: 5.3
|
||||
lockfileVersion: 5.4
|
||||
|
||||
specifiers:
|
||||
'@types/inquirer': ^8.2.0
|
||||
'@types/node': ^16.11.26
|
||||
'@types/inquirer': ^8.2.1
|
||||
'@types/node': ^16.11.47
|
||||
chalk: ^5.0.1
|
||||
inquirer: ^8.2.1
|
||||
typescript: ^4.6.2
|
||||
inquirer: ^8.2.4
|
||||
typescript: ^4.7.4
|
||||
|
||||
dependencies:
|
||||
chalk: 5.0.1
|
||||
inquirer: 8.2.1
|
||||
inquirer: 8.2.4
|
||||
|
||||
devDependencies:
|
||||
'@types/inquirer': 8.2.0
|
||||
'@types/node': 16.11.26
|
||||
typescript: 4.6.2
|
||||
'@types/inquirer': 8.2.1
|
||||
'@types/node': 16.11.47
|
||||
typescript: 4.7.4
|
||||
|
||||
packages:
|
||||
|
||||
/@types/inquirer/8.2.0:
|
||||
resolution: {integrity: sha512-BNoMetRf3gmkpAlV5we+kxyZTle7YibdOntIZbU5pyIfMdcwy784KfeZDAcuyMznkh5OLa17RVXZOGA5LTlkgQ==}
|
||||
/@types/inquirer/8.2.1:
|
||||
resolution: {integrity: sha512-wKW3SKIUMmltbykg4I5JzCVzUhkuD9trD6efAmYgN2MrSntY0SMRQzEnD3mkyJ/rv9NLbTC7g3hKKE86YwEDLw==}
|
||||
dependencies:
|
||||
'@types/through': 0.0.30
|
||||
rxjs: 7.5.5
|
||||
rxjs: 7.5.6
|
||||
dev: true
|
||||
|
||||
/@types/node/16.11.26:
|
||||
resolution: {integrity: sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ==}
|
||||
/@types/node/16.11.47:
|
||||
resolution: {integrity: sha512-fpP+jk2zJ4VW66+wAMFoBJlx1bxmBKx4DUFf68UHgdGCOuyUTDlLWqsaNPJh7xhNDykyJ9eIzAygilP/4WoN8g==}
|
||||
dev: true
|
||||
|
||||
/@types/through/0.0.30:
|
||||
resolution: {integrity: sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==}
|
||||
dependencies:
|
||||
'@types/node': 16.11.26
|
||||
'@types/node': 16.11.47
|
||||
dev: true
|
||||
|
||||
/ansi-escapes/4.3.2:
|
||||
@ -97,8 +97,8 @@ packages:
|
||||
restore-cursor: 3.1.0
|
||||
dev: false
|
||||
|
||||
/cli-spinners/2.6.1:
|
||||
resolution: {integrity: sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==}
|
||||
/cli-spinners/2.7.0:
|
||||
resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
@ -108,7 +108,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
/clone/1.0.4:
|
||||
resolution: {integrity: sha1-2jCcwmPfFZlMaIypAheco8fNfH4=}
|
||||
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
||||
engines: {node: '>=0.8'}
|
||||
dev: false
|
||||
|
||||
@ -124,7 +124,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
/defaults/1.0.3:
|
||||
resolution: {integrity: sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=}
|
||||
resolution: {integrity: sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==}
|
||||
dependencies:
|
||||
clone: 1.0.4
|
||||
dev: false
|
||||
@ -134,7 +134,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
/escape-string-regexp/1.0.5:
|
||||
resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=}
|
||||
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
dev: false
|
||||
|
||||
@ -174,8 +174,8 @@ packages:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
dev: false
|
||||
|
||||
/inquirer/8.2.1:
|
||||
resolution: {integrity: sha512-pxhBaw9cyTFMjwKtkjePWDhvwzvrNGAw7En4hottzlPvz80GZaMZthdDU35aA6/f5FRZf3uhE057q8w1DE3V2g==}
|
||||
/inquirer/8.2.4:
|
||||
resolution: {integrity: sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
dependencies:
|
||||
ansi-escapes: 4.3.2
|
||||
@ -188,10 +188,11 @@ packages:
|
||||
mute-stream: 0.0.8
|
||||
ora: 5.4.1
|
||||
run-async: 2.4.1
|
||||
rxjs: 7.5.5
|
||||
rxjs: 7.5.6
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
through: 2.3.8
|
||||
wrap-ansi: 7.0.0
|
||||
dev: false
|
||||
|
||||
/is-fullwidth-code-point/3.0.0:
|
||||
@ -244,7 +245,7 @@ packages:
|
||||
bl: 4.1.0
|
||||
chalk: 4.1.2
|
||||
cli-cursor: 3.1.0
|
||||
cli-spinners: 2.6.1
|
||||
cli-spinners: 2.7.0
|
||||
is-interactive: 1.0.0
|
||||
is-unicode-supported: 0.1.0
|
||||
log-symbols: 4.1.0
|
||||
@ -253,7 +254,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
/os-tmpdir/1.0.2:
|
||||
resolution: {integrity: sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=}
|
||||
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
@ -279,10 +280,10 @@ packages:
|
||||
engines: {node: '>=0.12.0'}
|
||||
dev: false
|
||||
|
||||
/rxjs/7.5.5:
|
||||
resolution: {integrity: sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==}
|
||||
/rxjs/7.5.6:
|
||||
resolution: {integrity: sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==}
|
||||
dependencies:
|
||||
tslib: 2.3.1
|
||||
tslib: 2.4.0
|
||||
|
||||
/safe-buffer/5.2.1:
|
||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||
@ -326,7 +327,7 @@ packages:
|
||||
dev: false
|
||||
|
||||
/through/2.3.8:
|
||||
resolution: {integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=}
|
||||
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
|
||||
dev: false
|
||||
|
||||
/tmp/0.0.33:
|
||||
@ -336,26 +337,35 @@ packages:
|
||||
os-tmpdir: 1.0.2
|
||||
dev: false
|
||||
|
||||
/tslib/2.3.1:
|
||||
resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==}
|
||||
/tslib/2.4.0:
|
||||
resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
|
||||
|
||||
/type-fest/0.21.3:
|
||||
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/typescript/4.6.2:
|
||||
resolution: {integrity: sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==}
|
||||
/typescript/4.7.4:
|
||||
resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==}
|
||||
engines: {node: '>=4.2.0'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/util-deprecate/1.0.2:
|
||||
resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=}
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
dev: false
|
||||
|
||||
/wcwidth/1.0.1:
|
||||
resolution: {integrity: sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=}
|
||||
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
|
||||
dependencies:
|
||||
defaults: 1.0.3
|
||||
dev: false
|
||||
|
||||
/wrap-ansi/7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
dev: false
|
||||
|
125
src/index.ts
125
src/index.ts
@ -1,10 +1,31 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import cp from 'child_process'
|
||||
import chalk from 'chalk'
|
||||
import cp from 'child_process'
|
||||
import inquirer from 'inquirer'
|
||||
|
||||
const VERSION = '1.2.3'
|
||||
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')
|
||||
}
|
||||
}
|
||||
|
||||
function checkIfBrewIsInstalled() {
|
||||
try {
|
||||
@ -15,13 +36,30 @@ function checkIfBrewIsInstalled() {
|
||||
}
|
||||
}
|
||||
|
||||
function getListOfLeaves(): string[] {
|
||||
function getListOfPackages(): ListEntry[] {
|
||||
const list = cp.execSync('brew leaves', { encoding: 'utf-8' })
|
||||
return list.trim().split('\n')
|
||||
return list
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map((line) => new ListEntry({ name: line, type: 'package' }))
|
||||
}
|
||||
|
||||
function getLoosers(keepers: string[], leaves = getListOfLeaves()): string[] {
|
||||
return leaves.filter((leave) => !keepers.includes(leave))
|
||||
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' }))
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
async function main() {
|
||||
@ -31,49 +69,64 @@ async function main() {
|
||||
}
|
||||
console.log(`${chalk.bold.blue('UnBrew')} - Brew cleanup utility\nVersion: ${VERSION}\n`)
|
||||
|
||||
let leaves: string[]
|
||||
let loosers: string[]
|
||||
const { cask } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'cask',
|
||||
message: `Also consider casks?`,
|
||||
},
|
||||
])
|
||||
|
||||
let initialState = getList(cask)
|
||||
|
||||
leaves = getListOfLeaves()
|
||||
const { keepers } = await inquirer.prompt([
|
||||
{
|
||||
type: 'checkbox',
|
||||
message: 'Select packages to keep (all by default)',
|
||||
name: 'keepers',
|
||||
choices: leaves.map((leave) => ({
|
||||
name: leave,
|
||||
choices: initialState.map((entry) => ({
|
||||
name: entry,
|
||||
checked: true,
|
||||
})),
|
||||
},
|
||||
])
|
||||
|
||||
loosers = getLoosers(keepers, leaves)
|
||||
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.join(' '))}`,
|
||||
},
|
||||
])
|
||||
// Uninstalling
|
||||
let first = true
|
||||
let allUninstalled: ListEntry[] = []
|
||||
while (true) {
|
||||
// Get all to be uninstalled
|
||||
const loosers = getLoosers(keepers, first ? initialState : getList(cask))
|
||||
|
||||
if (!confirmed) {
|
||||
console.log(chalk.bold.red('Aborted'))
|
||||
return
|
||||
// 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
|
||||
}
|
||||
|
||||
// Actual uninstalling
|
||||
if (loosers.length === 0) break
|
||||
allUninstalled.push(...loosers)
|
||||
cp.execSync(`brew uninstall ${loosers.map((l) => l.name).join(' ')}`)
|
||||
}
|
||||
|
||||
console.log('🗑 Uninstalling')
|
||||
const allLoosers: string[] = []
|
||||
while (loosers.length) {
|
||||
allLoosers.push(...loosers)
|
||||
const joinedLoosers = loosers.join(' ')
|
||||
cp.execSync(`brew uninstall ${joinedLoosers}`)
|
||||
loosers = getLoosers(keepers)
|
||||
}
|
||||
console.log('✅ Uninstalled: ' + allLoosers.join(', '))
|
||||
console.log('✅ Uninstalled: ' + allUninstalled.join(', '))
|
||||
|
||||
console.log('🧽 Cleaning up')
|
||||
cp.execSync(`brew cleanup`)
|
||||
@ -81,5 +134,5 @@ async function main() {
|
||||
console.log(chalk.bold.green('🚀 Done'))
|
||||
}
|
||||
main().finally(() => {
|
||||
console.log(chalk.blue('Bye Bye 👋'))
|
||||
console.log(chalk.blue('👋 Bye Bye'))
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user