2022-11-29 22:26:34 -08:00
#!/usr/bin/env zx
2022-12-24 20:48:43 -08:00
const execSync = require('child_process').execSync
2022-11-29 22:26:34 -08:00
2022-12-02 15:07:52 -08:00
// Log symbols
const figuresDefault = {
2022-12-24 20:48:43 -08:00
bullet: '●',
circle: '◯',
cross: '✖',
lozenge: '◆',
play: '▶',
pointer: '❯ ',
square: '◼',
star: '★',
tick: '✔'
}
2022-12-02 15:07:52 -08:00
const figuresFallback = {
2022-12-24 20:48:43 -08:00
bullet: '■',
circle: '□',
cross: '× ',
lozenge: '♦',
play: '►',
pointer: '>',
square: '■',
star: '✶',
tick: '√'
}
2022-12-02 15:07:52 -08:00
function isUnicodeSupported() {
2022-12-24 20:48:43 -08:00
if (process.platform !== 'win32') {
2022-12-02 15:07:52 -08:00
// Linux console (kernel)
2022-12-24 20:48:43 -08:00
return process.env.TERM !== 'linux'
2022-12-02 15:07:52 -08:00
}
return (
Boolean(process.env.CI) ||
// Windows Terminal
Boolean(process.env.WT_SESSION) ||
// ConEmu and cmder
2022-12-24 20:48:43 -08:00
process.env.ConEmuTask === '{cmd::Cmder}' ||
process.env.TERM_PROGRAM === 'vscode' ||
process.env.TERM === 'xterm-256color' ||
process.env.TERM === 'alacritty'
)
2022-12-02 15:07:52 -08:00
}
2022-12-24 20:48:43 -08:00
const figures = isUnicodeSupported() ? figuresDefault : figuresFallback
2022-12-02 15:07:52 -08:00
function log(type, label, msg) {
2022-12-24 20:48:43 -08:00
let icon, message
2023-01-24 09:49:04 -08:00
let fittedLabel = label
while(fittedLabel.length < 14) {
fittedLabel = fittedLabel.length % 2 === 1 ? fittedLabel + ' ' : ' ' + fittedLabel
}
2022-12-24 20:48:43 -08:00
if (type === 'info') {
2023-01-24 09:49:04 -08:00
icon = `${chalk.cyanBright(figures.pointer)} ${chalk.bold.white.bgCyan(' ' + fittedLabel + ' ')}`
2023-01-24 07:54:21 -08:00
message = wrapMessage(msg)
2022-12-24 20:48:43 -08:00
} else if (type === 'star') {
2023-01-24 09:49:04 -08:00
icon = `${chalk.yellow(figures.star)} ${chalk.bold.black.bgYellow(' ' + fittedLabel + ' ')}`
2023-01-24 07:54:21 -08:00
message = wrapMessage(msg)
2022-12-24 20:48:43 -08:00
} else if (type === 'success') {
2023-01-24 09:49:04 -08:00
icon = `${chalk.greenBright(figures.play)} ${chalk.bold.white.bgGreenBright(' ' + fittedLabel + ' ')}`
2023-01-24 07:54:21 -08:00
message = wrapMessage(msg)
2022-12-24 20:48:43 -08:00
} else if (type === 'warn') {
icon = `${chalk.yellowBright(figures.lozenge)} ${chalk.bold.black.bgYellowBright(' WARNING ')}`
2023-01-24 07:54:21 -08:00
message = chalk.yellowBright(wrapMessage(msg))
2022-12-24 20:48:43 -08:00
} else if (type === 'error') {
icon = `${chalk.redBright(figures.cross)} ${chalk.black.bold.bgRedBright(' ERROR ')}`
2023-01-24 07:54:21 -08:00
message = chalk.redBright(wrapMessage(msg))
2022-12-02 15:07:52 -08:00
}
2023-01-24 07:54:21 -08:00
const outputMessage = `${icon} ${message}`
2022-12-24 20:48:43 -08:00
console.log(outputMessage)
2022-12-02 15:07:52 -08:00
}
2023-01-24 07:54:21 -08:00
function locations(substring,string){
var a=[],i=-1;
while((i=string.indexOf(substring,i+1)) >= 0) a.push(i);
return a;
}
function wrapMessage(msg) {
const indexes = locations('`', msg)
2023-01-24 09:59:07 -08:00
if (indexes.length > 3) {
return msg.substring(0, indexes[0]) + chalk.bold.black.bgGray(' ' + msg.substring(indexes[0] + 1, indexes[1] + 1 - indexes[0]) + ' ') + msg.substring(indexes[1] + 1 - indexes[0]) + ' '
2023-01-24 07:54:21 -08:00
} else {
return msg
}
}
2023-01-04 19:45:25 -08:00
function runCommand(spinnerTitle, command) {
2023-01-12 07:02:13 -08:00
execSync(command.includes('sudo') ? `sudo "$(which gum)" spin --spinner dot --title "${spinnerTitle}" -- ${command}` : `gum spin --spinner dot --title "${spinnerTitle}" -- ${command}`, {
2023-01-04 19:45:25 -08:00
stdio: 'inherit',
2023-01-31 22:31:07 -08:00
shell: true,
// Timeout of 10m
timeout: 1000 * 60 * 10
2023-01-04 19:45:25 -08:00
})
}
2023-01-04 21:47:56 -08:00
async function runSilentCommand(command) {
execSync(`${command}`, { stdio: 'inherit', shell: true })
}
2023-01-04 19:45:25 -08:00
function fileExists(pathToFile) {
return fs.existsSync(pathToFile)
}
2022-12-24 20:48:43 -08:00
let installData
2023-01-03 20:39:23 -08:00
let installOrders = {}
2023-01-09 04:00:59 -08:00
let installMeta = {}
2023-01-09 01:31:22 -08:00
let binLinkRan = false
2023-02-15 22:53:42 -08:00
let installOrdersPre = []
let installOrdersPost = []
let installOrdersService = []
let installOrdersGroups = []
let installOrdersPlugins = []
let installOrdersBinLink = []
2022-12-24 20:48:43 -08:00
let brewUpdated, osType, osID, snapRefreshed
2022-11-29 22:26:34 -08:00
2023-01-09 04:08:28 -08:00
// Register the OS platform type
const osPlatformData = os.platform()
const osPlatform = osPlatformData === 'win32' ? 'windows' : osPlatformData
2022-11-29 22:26:34 -08:00
// Download the installation map
async function downloadInstallData() {
2023-04-17 20:56:12 -07:00
const response = await fetch('https://github.com/megabyte-labs/install.doctor/raw/master/software.yml')
2022-11-29 22:26:34 -08:00
if (response.ok) {
2022-12-24 20:48:43 -08:00
const text = await response.text()
return YAML.parse(text)
2022-11-29 22:26:34 -08:00
} else {
2022-12-24 20:48:43 -08:00
log('error', 'Catalog Download', `Failed to download the installation map`)
log('info', 'Catalog Download', `Falling back to local version of software.yml`)
const text = fs.readFileSync(process.env.HOME + '/.local/share/chezmoi/software.yml').toString()
return YAML.parse(text)
2022-11-29 22:26:34 -08:00
}
}
// Creates the installOrders object which maps package managers to arrays of packages to install
2022-12-25 06:00:18 -08:00
let generateInstallOrderCount = 0
2022-12-08 23:57:44 -08:00
async function generateInstallOrders(pkgsToInstall) {
2022-12-25 10:55:58 -08:00
const installerPreference = await OSTypeInstallerKey()
const preferenceOrder = installData.installerPreference[installerPreference]
2022-12-24 20:48:43 -08:00
const logStage = 'Install Orders'
const packagesToInstall = pkgsToInstall
const softwarePackages = installData.softwarePackages
2022-12-25 06:00:18 -08:00
if (generateInstallOrderCount === 0) {
log('info', logStage, `Installer preference category detected as ${installerPreference}`)
log('info', logStage, `Preference order acquired:`)
2023-02-15 22:14:03 -08:00
console.log('Preference order:', preferenceOrder)
2022-12-25 06:00:18 -08:00
}
generateInstallOrderCount++
log('info', logStage, `New packages discovered for processing: ${pkgsToInstall} (${pkgsToInstall.length} items)`)
2022-12-04 21:46:23 -08:00
pkgFor: for (let pkg of packagesToInstall) {
2022-12-24 20:48:43 -08:00
let packageKey
if (softwarePackages[pkg + ':' + osID]) {
packageKey = pkg + ':' + osID
} else if (softwarePackages[pkg + ':' + osType]) {
packageKey = pkg + ':' + osType
2022-11-29 22:26:34 -08:00
} else if (softwarePackages[pkg]) {
2022-12-24 20:48:43 -08:00
packageKey = pkg
2022-11-29 22:26:34 -08:00
} else {
2022-12-24 20:48:43 -08:00
log('warn', logStage, `The package \`${pkg}\` was not found in the installation map`)
2023-01-12 15:47:12 -08:00
console.log('softwarePackages:', softwarePackages)
console.log('pkg:', pkg)
2022-12-24 20:48:43 -08:00
continue
2022-11-29 22:26:34 -08:00
}
2023-02-15 19:33:34 -08:00
let comparesRemaining = preferenceOrder.length
2022-11-29 22:26:34 -08:00
for (let preference of preferenceOrder) {
2023-02-15 19:33:34 -08:00
comparesRemaining--
2022-12-24 20:48:43 -08:00
let currentSelector, doubleScoped, scopedPkgManager, scopedSystem, normalCheck
2022-12-04 21:46:23 -08:00
if (
2022-12-24 20:48:43 -08:00
softwarePackages[packageKey][preference + ':' + osID] ||
softwarePackages[packageKey][preference + ':' + osType] ||
2022-12-04 21:46:23 -08:00
softwarePackages[packageKey][preference]
) {
// Handle the _when attribute
2022-12-24 20:48:43 -08:00
currentSelector = 'when'
2022-12-04 21:46:23 -08:00
doubleScoped =
2022-12-24 20:48:43 -08:00
softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osID] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + osID + ':' + preference] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osType] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + osType + ':' + preference]
scopedPkgManager = softwarePackages[packageKey]['_' + currentSelector + ':' + preference]
2022-12-04 21:46:23 -08:00
scopedSystem =
2022-12-24 20:48:43 -08:00
softwarePackages[packageKey]['_' + currentSelector + ':' + osID] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + osType]
normalCheck = softwarePackages[packageKey]['_' + currentSelector]
2022-12-04 21:46:23 -08:00
if (doubleScoped) {
try {
2022-12-24 20:48:43 -08:00
await $doubleScoped
2022-12-04 21:46:23 -08:00
} catch (e) {
2022-12-24 20:48:43 -08:00
let pref
if (softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osID]) {
pref = preference + ':' + osID
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osType]) {
pref = preference + ':' + osType
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osID + ':' + preference]) {
pref = osID + ':' + preference
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osType + ':' + preference]) {
pref = osType + ':' + preference
2022-12-04 21:46:23 -08:00
}
2023-01-04 20:28:13 -08:00
log('info', 'Filter', `${pkg} is being skipped because of the _when:${pref} condition`)
2023-01-24 06:41:15 -08:00
processPluginOrders(pkg)
2022-12-24 20:48:43 -08:00
continue pkgFor
2022-12-04 21:46:23 -08:00
}
} else if (scopedPkgManager) {
try {
2022-12-24 20:48:43 -08:00
await $scopedPkgManager
2022-12-04 21:46:23 -08:00
} catch (e) {
2022-12-24 20:48:43 -08:00
const pref = preference
2023-01-04 20:28:13 -08:00
log('info', 'Filter', `${pkg} is being skipped because of the _when:${pref} condition`)
2023-01-24 06:41:15 -08:00
processPluginOrders(pkg)
2022-12-24 20:48:43 -08:00
continue pkgFor
2022-12-04 21:46:23 -08:00
}
} else if (scopedSystem) {
try {
2022-12-24 20:48:43 -08:00
await $scopedSystem
2022-12-04 21:46:23 -08:00
} catch (e) {
2022-12-24 20:48:43 -08:00
let pref
if (softwarePackages[packageKey]['_' + currentSelector + ':' + osID]) {
pref = osID
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osType]) {
pref = osType
2022-12-04 21:46:23 -08:00
}
2023-01-04 20:28:13 -08:00
log('info', 'Filter', `${pkg} is being skipped because of the _when:${pref} condition`)
2023-01-24 06:41:15 -08:00
processPluginOrders(pkg)
2022-12-24 20:48:43 -08:00
continue pkgFor
2022-12-04 21:46:23 -08:00
}
} else if (normalCheck) {
try {
2022-12-24 20:48:43 -08:00
await $(normalCheck)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-04 20:28:13 -08:00
log('info', 'Filter', `${pkg} is being skipped because of the _when condition`)
2023-01-24 06:41:15 -08:00
processPluginOrders(pkg)
2022-12-24 20:48:43 -08:00
continue pkgFor
2022-12-04 21:46:23 -08:00
}
}
// Handle the _bin attribute
2022-12-24 20:48:43 -08:00
currentSelector = 'bin'
2022-12-04 21:46:23 -08:00
doubleScoped =
2022-12-24 20:48:43 -08:00
softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osID] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + osID + ':' + preference] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osType] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + osType + ':' + preference]
scopedPkgManager = softwarePackages[packageKey]['_' + currentSelector + ':' + preference]
2022-12-04 21:46:23 -08:00
scopedSystem =
2022-12-24 20:48:43 -08:00
softwarePackages[packageKey]['_' + currentSelector + ':' + osID] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + osType]
normalCheck = softwarePackages[packageKey]['_' + currentSelector]
2022-12-04 21:46:23 -08:00
if (doubleScoped) {
2022-12-24 20:48:43 -08:00
const bin =
typeof doubleScoped === 'string'
? which.sync(doubleScoped, { nothrow: true })
: doubleScoped.map((x) => which.sync(x, { nothrow: true })).every((y) => !!y)
2022-12-04 22:26:27 -08:00
if (bin) {
2022-12-24 20:48:43 -08:00
let pref
if (softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osID]) {
pref = preference + ':' + osID
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osType]) {
pref = preference + ':' + osType
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osID + ':' + preference]) {
pref = osID + ':' + preference
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osType + ':' + preference]) {
pref = osType + ':' + preference
2022-12-04 21:46:23 -08:00
}
2023-01-04 20:28:13 -08:00
log('info', 'Filter', `${bin} already in PATH (via _bin:${pref})`)
2023-01-24 06:41:15 -08:00
processPluginOrders(pkg)
2022-12-24 20:48:43 -08:00
continue pkgFor
2023-01-08 23:14:44 -08:00
} else {
if (preference === 'cask' || preference === 'flatpak') {
installOrdersBinLink.push({ package: packageKey, bin: doubleScoped, preference })
}
2022-12-04 21:46:23 -08:00
}
} else if (scopedPkgManager) {
2022-12-24 20:48:43 -08:00
const bin =
typeof scopedPkgManager === 'string'
? which.sync(scopedPkgManager, { nothrow: true })
: scopedPkgManager.map((x) => which.sync(x, { nothrow: true })).every((y) => !!y)
2022-12-04 22:26:27 -08:00
if (bin) {
2022-12-24 20:48:43 -08:00
const pref = preference
2023-01-04 20:28:13 -08:00
log('info', 'Filter', `${bin} already in PATH (via _bin:${pref})`)
2023-01-24 06:41:15 -08:00
processPluginOrders(pkg)
2022-12-24 20:48:43 -08:00
continue pkgFor
2023-01-08 23:14:44 -08:00
} else {
if (preference === 'cask' || preference === 'flatpak') {
installOrdersBinLink.push({ package: packageKey, bin: scopedPkgManager, preference })
}
2022-12-04 21:46:23 -08:00
}
} else if (scopedSystem) {
2022-12-24 20:48:43 -08:00
const bin =
typeof scopedSystem === 'string'
? which.sync(scopedSystem, { nothrow: true })
: scopedSystem.map((x) => which.sync(x, { nothrow: true })).every((y) => !!y)
2022-12-04 22:26:27 -08:00
if (bin) {
2022-12-24 20:48:43 -08:00
let pref
if (softwarePackages[packageKey]['_' + currentSelector + ':' + osID]) {
pref = osID
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osType]) {
pref = osType
2022-12-04 21:46:23 -08:00
}
2023-01-04 20:28:13 -08:00
log('info', 'Filter', `${bin} already in PATH (via _bin:${pref})`)
2023-01-24 06:41:15 -08:00
processPluginOrders(pkg)
2022-12-24 20:48:43 -08:00
continue pkgFor
2023-01-08 23:14:44 -08:00
} else {
if (preference === 'cask' || preference === 'flatpak') {
installOrdersBinLink.push({ package: packageKey, bin: scopedSystem, preference })
}
2022-12-04 21:46:23 -08:00
}
} else if (normalCheck) {
2022-12-24 20:48:43 -08:00
const bin =
typeof normalCheck === 'string'
? which.sync(normalCheck, { nothrow: true })
: normalCheck.map((x) => which.sync(x, { nothrow: true })).every((y) => !!y)
2022-12-04 22:26:27 -08:00
if (bin) {
2023-01-04 20:28:13 -08:00
log('info', 'Filter', `${bin} already in PATH (via _bin)`)
2023-01-24 06:41:15 -08:00
processPluginOrders(pkg)
2022-12-24 20:48:43 -08:00
continue pkgFor
2023-01-08 23:14:44 -08:00
} else {
if (preference === 'cask' || preference === 'flatpak') {
installOrdersBinLink.push({ package: packageKey, bin: normalCheck, preference })
}
2022-12-04 21:46:23 -08:00
}
}
2022-12-08 23:57:44 -08:00
// Handle the _deps attribute
2022-12-24 20:48:43 -08:00
currentSelector = 'deps'
2022-12-08 23:57:44 -08:00
doubleScoped =
2022-12-24 20:48:43 -08:00
softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osID] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + osID + ':' + preference] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osType] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + osType + ':' + preference]
scopedPkgManager = softwarePackages[packageKey]['_' + currentSelector + ':' + preference]
2022-12-08 23:57:44 -08:00
scopedSystem =
2022-12-24 20:48:43 -08:00
softwarePackages[packageKey]['_' + currentSelector + ':' + osID] ||
softwarePackages[packageKey]['_' + currentSelector + ':' + osType]
normalCheck = softwarePackages[packageKey]['_' + currentSelector]
2023-01-04 20:28:13 -08:00
const dependenciesTag = 'Dependencies'
2022-12-08 23:57:44 -08:00
if (doubleScoped) {
2022-12-24 20:48:43 -08:00
let pref
if (softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osID]) {
2023-01-05 20:21:23 -08:00
pref = '_deps:' + preference + ':' + osID
2023-01-04 20:28:13 -08:00
log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`)
2022-12-25 06:00:18 -08:00
await generateInstallOrders(softwarePackages[packageKey][pref])
2022-12-24 20:48:43 -08:00
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osType]) {
2023-01-05 20:21:23 -08:00
pref = '_deps:' + preference + ':' + osType
2023-01-04 20:28:13 -08:00
log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`)
2022-12-25 06:00:18 -08:00
await generateInstallOrders(softwarePackages[packageKey][pref])
2022-12-24 20:48:43 -08:00
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osID + ':' + preference]) {
2023-01-05 20:21:23 -08:00
pref = '_deps:' + osID + ':' + preference
2023-01-04 20:28:13 -08:00
log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`)
2022-12-25 06:00:18 -08:00
await generateInstallOrders(softwarePackages[packageKey][pref])
2022-12-24 20:48:43 -08:00
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osType + ':' + preference]) {
2023-01-05 20:21:23 -08:00
pref = '_deps:' + osType + ':' + preference
2023-01-04 20:28:13 -08:00
log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`)
2022-12-25 06:00:18 -08:00
await generateInstallOrders(softwarePackages[packageKey][pref])
2022-12-08 23:57:44 -08:00
}
} else if (scopedPkgManager) {
2023-01-05 20:21:23 -08:00
const pref = '_deps:' + preference
2023-01-04 20:28:13 -08:00
log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`)
2022-12-25 06:00:18 -08:00
await generateInstallOrders(softwarePackages[packageKey][pref])
2022-12-08 23:57:44 -08:00
} else if (scopedSystem) {
2022-12-24 20:48:43 -08:00
let pref
if (softwarePackages[packageKey]['_' + currentSelector + ':' + osID]) {
2023-01-05 20:21:23 -08:00
pref = '_deps:' + osID
2023-01-04 20:28:13 -08:00
log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`)
2022-12-25 06:00:18 -08:00
await generateInstallOrders(softwarePackages[packageKey][pref])
2022-12-24 20:48:43 -08:00
} else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osType]) {
2023-01-05 20:21:23 -08:00
pref = '_deps:' + osType
2023-01-04 20:28:13 -08:00
log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`)
2022-12-25 06:00:18 -08:00
await generateInstallOrders(softwarePackages[packageKey][pref])
2022-12-08 23:57:44 -08:00
}
} else if (normalCheck) {
2023-01-04 20:28:13 -08:00
log('info', dependenciesTag, `Installing dependencies for ${packageKey}.deps`)
2022-12-25 06:00:18 -08:00
await generateInstallOrders(softwarePackages[packageKey]['_deps'])
2022-12-08 23:57:44 -08:00
}
2022-12-24 20:48:43 -08:00
if (softwarePackages[packageKey][preference + ':' + osID]) {
2022-12-04 21:46:23 -08:00
await updateInstallMaps(
preference,
softwarePackages[packageKey],
2022-12-24 20:48:43 -08:00
preference + ':' + osID,
2022-12-04 21:46:23 -08:00
pkg,
2022-12-08 21:19:29 -08:00
packageKey,
softwarePackages
2022-12-24 20:48:43 -08:00
)
break
} else if (softwarePackages[packageKey][preference + ':' + osType]) {
2022-12-04 21:46:23 -08:00
await updateInstallMaps(
preference,
softwarePackages[packageKey],
2022-12-24 20:48:43 -08:00
preference + ':' + osType,
2022-12-04 21:46:23 -08:00
pkg,
2022-12-08 21:19:29 -08:00
packageKey,
softwarePackages
2022-12-24 20:48:43 -08:00
)
break
2022-12-04 21:46:23 -08:00
} else if (softwarePackages[packageKey][preference]) {
await updateInstallMaps(
preference,
softwarePackages[packageKey],
preference,
pkg,
2022-12-08 21:19:29 -08:00
packageKey,
softwarePackages
2022-12-24 20:48:43 -08:00
)
break
2023-02-15 19:33:34 -08:00
}
} else {
2023-02-15 19:49:19 -08:00
if (!comparesRemaining) {
2023-02-15 19:33:34 -08:00
log('info', 'No Match', `There was no match found for ${pkg} - it may be an OS-specific package`)
2022-12-04 21:46:23 -08:00
}
2022-11-29 22:26:34 -08:00
}
}
}
2022-12-25 06:00:18 -08:00
if (generateInstallOrderCount === 1) {
return installOrders
} else {
generateInstallOrderCount--
}
2022-11-29 22:26:34 -08:00
}
2023-01-24 06:41:15 -08:00
function processPluginOrders(pkg) {
const pluginMap = installData && installData.softwarePlugins && installData.softwarePlugins[pkg]
if (pluginMap) {
if (pluginMap.cmd && pluginMap.plugins) {
installOrdersPlugins.push({ package: pkg, cmd: pluginMap.cmd, plugins: pluginMap.plugins })
}
}
}
2022-11-29 22:26:34 -08:00
// Update install, pre-hook, and post-hook objects
2022-12-24 20:48:43 -08:00
async function updateInstallMaps(preference, packages, scopedPreference, pkg, packageKey, softwarePackages) {
const preHook = getHook(packages, 'pre', scopedPreference, preference)
2022-11-29 22:26:34 -08:00
if (preHook) {
2023-02-15 22:14:03 -08:00
installOrdersPre = installOrdersPre.concat(typeof preHook === 'string' ? [preHook] : preHook)
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
const postHook = getHook(packages, 'post', scopedPreference, preference)
2022-11-29 22:26:34 -08:00
if (postHook) {
2023-02-15 22:14:03 -08:00
installOrdersPost = installOrdersPost.concat(typeof postHook === 'string' ? [postHook] : postHook)
2022-11-29 22:26:34 -08:00
}
2023-01-08 18:12:24 -08:00
const serviceHook = getHook(packages, 'service', scopedPreference, preference)
if (serviceHook) {
2023-02-15 22:14:03 -08:00
installOrdersService = installOrdersService.concat(typeof serviceHook === 'string' ? [serviceHook] : serviceHook)
2022-12-08 21:19:29 -08:00
}
2023-01-29 19:09:02 -08:00
const groupsHook = getHook(packages, 'groups', scopedPreference, preference)
if (groupsHook) {
2023-02-15 22:14:03 -08:00
installOrdersGroups = installOrdersGroups.concat(typeof groupsHook === 'string' ? [groupsHook] : groupsHook)
2023-01-29 19:09:02 -08:00
}
2023-01-24 06:41:15 -08:00
processPluginOrders(pkg)
2022-11-29 22:26:34 -08:00
if (!installOrders[preference]) {
2022-12-24 20:48:43 -08:00
installOrders[preference] = []
2022-11-29 22:26:34 -08:00
}
2023-01-04 20:28:13 -08:00
log('info', 'Match', `Found a match for the package \`${pkg}\` (${packageKey} via ${scopedPreference})`)
2022-12-24 20:48:43 -08:00
const newPackages = packages[scopedPreference]
2023-01-09 04:37:57 -08:00
const newPkgs = typeof newPackages === 'string' ? [ newPackages ] : newPackages
2023-01-09 04:00:59 -08:00
if (typeof newPackages === 'string') {
installMeta[newPackages] = {
preference,
packages,
scopedPreference,
pkg,
packageKey,
softwarePackages
}
} else {
for (const dataKey in newPackages) {
installMeta[newPackages] = {
preference,
packages,
scopedPreference,
pkg,
packageKey,
softwarePackages
}
}
}
2022-12-25 03:28:08 -08:00
if (preference === 'snap' && softwarePackages[pkg]['_snapClassic'] === true) {
2023-01-09 04:00:59 -08:00
if (!installOrders['snap-classic']) {
installOrders['snap-classic'] = []
2022-12-08 21:19:29 -08:00
}
2023-01-09 04:41:48 -08:00
installOrders['snap-classic'] = installOrders['snap-classic'].concat(newPkgs)
2022-12-08 21:19:29 -08:00
} else {
2022-12-24 20:48:43 -08:00
installOrders[preference] = installOrders[preference].concat(newPkgs)
2022-12-08 21:19:29 -08:00
}
2022-11-29 22:26:34 -08:00
}
// Get pre / post install hooks
function getHook(packages, hook, scopedPreference, preference) {
2022-12-24 20:48:43 -08:00
const hookLabel = '_' + hook + ':'
2022-11-29 22:26:34 -08:00
if (packages[hookLabel + scopedPreference]) {
2022-12-24 20:48:43 -08:00
return packages[hookLabel + scopedPreference]
2022-11-29 22:26:34 -08:00
} else if (packages[hookLabel + preference]) {
2022-12-24 20:48:43 -08:00
return packages[hookLabel + preference]
2022-11-29 22:26:34 -08:00
} else if (packages[hookLabel + osID]) {
2022-12-24 20:48:43 -08:00
return packages
2022-11-29 22:26:34 -08:00
} else if (packages[hookLabel + osType]) {
2022-12-24 20:48:43 -08:00
return packages[hookLabel + osType]
} else if (packages['_' + hook]) {
return packages['_' + hook]
2022-11-29 22:26:34 -08:00
}
}
// Acquire OS type installer key (for the installerPreference data key)
async function OSTypeInstallerKey() {
2022-12-24 08:57:06 -08:00
try {
2022-12-24 20:48:43 -08:00
const apt = which.sync('apt-get', { nothrow: true })
const dnf = which.sync('dnf', { nothrow: true })
const freebsdPkg = which.sync('pkg', { nothrow: true })
const freebsdVersion = which.sync('freebsd-version', { nothrow: true })
const pacman = which.sync('pacman', { nothrow: true })
const yum = which.sync('yum', { nothrow: true })
const zypper = which.sync('zypper', { nothrow: true })
2022-12-24 08:57:06 -08:00
if (apt) {
2023-01-24 23:32:37 -08:00
try {
await $`test -d /etc/ubuntu-advantage`
return 'ubuntu'
} catch (e) {
return 'apt'
}
2022-12-24 08:57:06 -08:00
} else if (dnf || yum) {
2022-12-24 20:48:43 -08:00
return 'dnf'
2022-12-24 08:57:06 -08:00
} else if (pacman) {
2022-12-24 20:48:43 -08:00
return 'pacman'
2022-12-24 08:57:06 -08:00
} else if (zypper) {
2022-12-24 20:48:43 -08:00
return 'zypper'
2022-12-24 08:57:06 -08:00
} else if (freebsdPkg && freebsdVersion) {
2022-12-24 20:48:43 -08:00
return 'freebsd'
2022-12-24 08:57:06 -08:00
} else {
try {
2022-12-24 20:48:43 -08:00
await $`test -d /Applications && test -d /Library`
return 'darwin'
2022-12-24 08:57:06 -08:00
} catch (e) {
2022-12-24 20:48:43 -08:00
return 'windows'
2022-12-24 08:57:06 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 08:57:06 -08:00
} catch (e) {
2022-12-24 20:48:43 -08:00
log('error', 'OS Detection', 'There was an error determining the type of operating system')
2022-12-24 08:57:06 -08:00
console.error(e)
2022-11-29 22:26:34 -08:00
}
}
// Acquire OS type
async function OSType() {
try {
2022-12-24 20:48:43 -08:00
await $`test -d /Applications && test -d /Library`
return 'darwin'
2022-12-04 21:46:23 -08:00
} catch (e) {
2022-11-29 22:26:34 -08:00
try {
2022-12-24 20:48:43 -08:00
await $`test -f /etc/os-release`
return 'linux'
2022-11-29 22:26:34 -08:00
} catch (e) {
2022-12-24 20:48:43 -08:00
return 'windows'
2022-11-29 22:26:34 -08:00
}
}
}
// Acquire release ID (for Linux)
async function releaseID() {
const ID = await $`
if [ -f /etc/os-release ]; then
. /etc/os-release
echo -n $ID
fi
2022-12-24 20:48:43 -08:00
`
return ID.stdout
2022-11-29 22:26:34 -08:00
}
// Post-install hook
async function afterInstall(packageManager) {
2022-12-24 20:48:43 -08:00
const logStage = 'Post-Install Package Manager'
if (packageManager === 'appimage') {
} else if (packageManager === 'ansible') {
log('info', logStage, `Ensuring temporary passwordless sudo privileges used by Ansible are removed`)
const gsed = which.sync('gsed', { nothrow: true })
2022-12-02 15:28:30 -08:00
if (gsed) {
2022-12-24 20:48:43 -08:00
await $`sudo gsed -i '/# TEMPORARY FOR ANSIBLE INSTALL/d' /etc/sudoers`
2022-12-02 15:28:30 -08:00
} else {
2022-12-24 20:48:43 -08:00
await $`sudo sed -i '/# TEMPORARY FOR ANSIBLE INSTALL/d' /etc/sudoers`
2022-12-02 15:28:30 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'apk') {
} else if (packageManager === 'apt') {
2022-12-06 04:53:19 -08:00
try {
2023-01-04 20:05:31 -08:00
runCommand('Running apt-get autoclean', `sudo apt-get autoclean`)
runCommand('Running apt-get autoremove', `sudo apt-get -y autoremove`)
2022-12-06 04:53:19 -08:00
} catch (e) {
2022-12-25 03:05:03 -08:00
log('error', logStage, 'Error cleaning up apt-get')
2022-12-06 04:53:19 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'basher') {
} else if (packageManager === 'binary') {
} else if (packageManager === 'brew' || packageManager === 'cask') {
2023-04-15 16:34:26 -07:00
log('info', logStage, `Ensuring Homebrew cleanup is run`)
await $`brew cleanup`
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'cargo') {
} else if (packageManager === 'choco') {
} else if (packageManager === 'crew') {
} else if (packageManager === 'dnf') {
} else if (packageManager === 'flatpak') {
} else if (packageManager === 'gem') {
} else if (packageManager === 'go') {
} else if (packageManager === 'nix') {
} else if (packageManager === 'npm') {
} else if (packageManager === 'pacman') {
} else if (packageManager === 'pipx') {
} else if (packageManager === 'pkg') {
} else if (packageManager === 'port') {
} else if (packageManager === 'scoop') {
} else if (packageManager === 'script') {
} else if (packageManager === 'snap') {
} else if (packageManager === 'whalebrew') {
} else if (packageManager === 'winget') {
} else if (packageManager === 'yay') {
} else if (packageManager === 'zypper') {
2022-11-29 22:26:34 -08:00
}
}
2022-12-08 23:57:44 -08:00
async function ensurePackage(dep) {
const target = which.sync(dep, { nothrow: true })
if (!target) {
2022-12-08 22:37:26 -08:00
if (osType === 'linux') {
2022-12-24 20:48:43 -08:00
const apk = which.sync('apk', { nothrow: true })
2022-12-25 03:05:03 -08:00
const apt = which.sync('apt-get', { nothrow: true })
2022-12-24 20:48:43 -08:00
const dnf = which.sync('dnf', { nothrow: true })
2023-01-03 19:52:32 -08:00
const pkg = which.sync('pkg', { nothrow: true })
2022-12-24 20:48:43 -08:00
const yum = which.sync('yum', { nothrow: true })
const pacman = which.sync('pacman', { nothrow: true })
const zypper = which.sync('zypper', { nothrow: true })
2022-12-08 22:37:26 -08:00
if (apk) {
2022-12-25 02:03:54 -08:00
await $`sudo apk add ${dep}`
2022-12-08 22:37:26 -08:00
} else if (apt) {
2022-12-25 11:07:19 -08:00
if (updateDone['apt-get'] !== true) {
2022-12-08 22:37:26 -08:00
await beforeInstall('apt-get')
}
2023-01-03 19:52:32 -08:00
try {
log('info', 'apt-get Installation', `Checking if ${dep} is already installed`)
2023-01-09 04:30:16 -08:00
runCommand(
`Checking if ${dep} is already installed via apt-get`,
`dpkg -l ${dep} | grep -E '^ii' > /dev/null`
)
2023-01-04 20:05:31 -08:00
log('info', 'Filter', `${pkg} already installed via apt-get`)
2023-01-03 19:52:32 -08:00
} catch (e) {
2023-01-09 04:30:16 -08:00
runCommand(
`Installing ${dep} via apt-get`,
`sudo apt-get -o DPkg::Options::=--force-confdef install -y ${dep}`
)
2023-01-04 20:05:31 -08:00
log('success', 'Install', `Successfully installed ${pkg} via apt-get`)
2023-01-03 19:52:32 -08:00
}
2022-12-08 22:37:26 -08:00
} else if (dnf) {
2022-12-25 11:07:19 -08:00
if (updateDone['dnf'] !== true) {
2022-12-08 22:37:26 -08:00
await beforeInstall('dnf')
}
2023-01-03 19:52:32 -08:00
try {
log('info', 'dnf Installation', `Checking if ${dep} is already installed`)
2023-02-01 19:08:26 -08:00
await $`rpm -qa | grep '$'"${dep}-" > /dev/null`
2023-01-03 19:52:32 -08:00
} catch (e) {
log('info', 'dnf Installation', `Installing ${dep} since it is not already present on the system`)
await $`sudo dnf install -y ${dep}`
}
2022-12-08 22:37:26 -08:00
} else if (yum) {
2022-12-25 11:07:19 -08:00
if (updateDone['yum'] !== true) {
await beforeInstall('yum')
2022-12-08 22:37:26 -08:00
}
2023-01-03 19:52:32 -08:00
try {
log('info', 'YUM Installation', `Checking if ${dep} is already installed`)
2023-02-01 19:08:26 -08:00
await $`rpm -qa | grep '$'"${dep}-" > /dev/null`
2023-01-03 19:52:32 -08:00
} catch (e) {
log('info', 'YUM Installation', `Installing ${dep} since it is not already present on the system`)
await $`sudo yum install -y ${dep}`
}
2022-12-08 22:37:26 -08:00
} else if (pacman) {
2022-12-25 11:07:19 -08:00
if (updateDone['pacman'] !== true) {
2022-12-08 22:37:26 -08:00
await beforeInstall('pacman')
}
2023-01-03 19:52:32 -08:00
try {
log('info', 'Pacman Installation', `Checking if ${dep} is already installed`)
await $`pacman -Qs ${dep}`
} catch (e) {
log('info', 'Pacman Installation', `Installing ${dep} since it is not already present on the system`)
await $`sudo pacman -Sy ${dep}`
}
2022-12-08 22:37:26 -08:00
} else if (zypper) {
2022-12-25 11:07:19 -08:00
if (updateDone['zypper'] !== true) {
2022-12-08 22:37:26 -08:00
await beforeInstall('zypper')
}
2023-01-03 19:52:32 -08:00
try {
log('info', 'Zypper Installation', `Checking if ${dep} is already installed`)
2023-02-01 19:08:26 -08:00
await $`rpm -qa | grep '$'"${dep}-" > /dev/null`
2023-01-03 19:52:32 -08:00
} catch (e) {
log('info', 'Zypper Installation', `Installing ${dep} since it is not already present on the system`)
await $`sudo zypper install -y ${dep}`
}
} else if (pkg) {
if (updateDone['pkg'] !== true) {
await beforeInstall('pkg')
}
try {
log('info', 'pkg Installation', `Checking if ${dep} is already installed`)
await $`pkg info -Ix ${dep} > /dev/null`
} catch (e) {
log('info', 'pkg Installation', `Installing ${dep} since it is not already present on the system`)
await $`sudo pkg install -y ${dep}`
}
2022-12-08 22:37:26 -08:00
}
} else if (osType === 'darwin') {
if (updateDone['brew'] !== true) {
await beforeInstall('brew')
}
2022-12-08 23:57:44 -08:00
await $`brew install ${dep}`
2022-12-08 22:37:26 -08:00
} else if (osType === 'windows') {
if (updateDone['choco'] !== true) {
await beforeInstall('choco')
}
2022-12-08 23:57:44 -08:00
await `choco install -y ${dep}`
2022-12-08 22:37:26 -08:00
}
}
}
2022-11-29 22:26:34 -08:00
// Pre-install hook
2022-12-08 22:37:26 -08:00
const updateDone = {}
2022-11-29 22:26:34 -08:00
async function beforeInstall(packageManager) {
2022-12-08 22:37:26 -08:00
updateDone[packageManager] = true
2022-12-24 20:48:43 -08:00
const logStage = 'Pre-Install Package Manager'
if (packageManager === 'appimage') {
2023-01-09 04:30:16 -08:00
if (!fileExists(`${process.env.HOME}/Applications`)) {
2023-01-09 03:21:22 -08:00
runSilentCommand(`mkdir -p "${process.env.HOME}/Applications"`)
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'ansible') {
log('info', logStage, `Temporarily enabling passwordless sudo for Ansible role installations`)
await $`echo "$(whoami) ALL=(ALL:ALL) NOPASSWD: ALL # TEMPORARY FOR ANSIBLE INSTALL" | sudo tee -a /etc/sudoers`
2022-12-05 12:15:57 -08:00
log('info', logStage, 'Running Ansible setup task so facts are cached')
2022-12-06 13:04:49 -08:00
const unbuffer = which.sync('unbuffer', { nothrow: true })
let unbufferPrefix = ''
if (unbuffer) {
2022-12-06 14:24:46 -08:00
unbufferPrefix = 'unbuffer'
2022-12-06 13:04:49 -08:00
}
2023-01-09 04:08:28 -08:00
if (osPlatform === 'darwin' || osPlatform === 'linux' || osPlatform === 'windows') {
2023-01-11 22:53:14 -08:00
const capitalOsPlatform = osPlatform.charAt(0).toUpperCase() + osPlatform.slice(1)
await $`ANSIBLE_CONFIG=${process.env.HOME}/.local/share/ansible/ansible.cfg ${unbufferPrefix} ansible 127.0.0.1 -e '{ ansible_connection: "local", ansible_become_user: "${process.env.USER}", ansible_user: "${process.env.USER}", ansible_family: "${capitalOsPlatform}", install_homebrew: False }' -m setup`
2023-01-09 04:08:28 -08:00
} else {
log('warn', 'Ansible', 'Unsupported platform - ' + osPlatform)
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'apk') {
await $`sudo apk update`
} else if (packageManager === 'apt') {
2023-01-04 23:24:36 -08:00
runCommand('Running apt-get update / upgrade', `sudo apt-get update && sudo apt-get upgrade -y`)
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'basher') {
} else if (packageManager === 'binary') {
} else if (packageManager === 'brew' || packageManager === 'cask') {
2022-12-08 21:19:29 -08:00
if (!brewUpdated) {
brewUpdated = true
2023-04-17 23:18:00 -07:00
try {
runCommand('Running brew update', `brew update`)
} catch (e) {
2023-04-17 23:19:42 -07:00
log('error', 'Homebrew', 'Failed running brew update')
2023-04-17 23:18:00 -07:00
}
2022-12-08 21:19:29 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'cargo') {
} else if (packageManager === 'choco') {
} else if (packageManager === 'crew') {
await $`crew update`
} else if (packageManager === 'dnf') {
const dnf = which.sync('dnf', { nothrow: true })
const yum = which.sync('yum', { nothrow: true })
2022-12-04 19:51:47 -08:00
if (dnf) {
2023-01-04 21:12:32 -08:00
runCommand('Running dnf update', `sudo dnf update -y`)
2022-12-04 19:51:47 -08:00
} else if (yum) {
2023-01-04 21:12:32 -08:00
runCommand('Running yum update', `sudo yum update -y`)
2022-12-04 19:51:47 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'flatpak') {
2023-02-01 00:48:57 -08:00
// TODO - figure out why CentOS is failing to update
// and then switch command below for `sudo flatpak update -y`
2023-02-01 13:15:35 -08:00
runCommand('Running flatpak update', `. /etc/os-release; if [ "$ID" != "centos" ]; then sudo flatpak update -y; else echo "Skipping Flatpak update on CentOS"; fi`)
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'gem') {
} else if (packageManager === 'go') {
} else if (packageManager === 'nix') {
2023-01-04 21:12:32 -08:00
runCommand('Running nix-channel --update', `nix-channel --update`)
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'npm') {
} else if (packageManager === 'pacman') {
2023-01-04 21:12:32 -08:00
runCommand('Running pacman update', `sudo pacman -Syu`)
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'pipx') {
} else if (packageManager === 'pkg') {
await $`sudo pkg upgrade`
} else if (packageManager === 'port') {
const port = which.sync('port', { nothrow: true })
2022-12-04 20:12:14 -08:00
if (port) {
2023-01-04 21:12:32 -08:00
runCommand('Running port sync', `sudo port sync`)
2022-12-04 20:12:14 -08:00
} else {
2022-12-24 20:48:43 -08:00
log('error', 'Port Not Installed', 'Skipping sudo port sync step because port is not installed')
2022-12-04 20:12:14 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'scoop') {
2023-01-04 21:12:32 -08:00
runCommand('Running scoop update', `scoop update`)
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'snap' || packageManager === 'snap-classic') {
2022-12-08 21:19:29 -08:00
if (!snapRefreshed) {
snapRefreshed = true
2023-01-04 21:12:32 -08:00
runCommand('Ensuring snap is refreshed', `sudo snap refresh`)
2022-12-08 21:19:29 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'whalebrew') {
if (osType === 'darwin') {
const docker = which.sync('docker', { nothrow: true })
2022-12-02 09:09:59 -08:00
if (!docker) {
2022-12-24 20:48:43 -08:00
await $`brew install --cask docker`
2022-12-02 09:09:59 -08:00
}
try {
2023-01-29 21:09:12 -08:00
await $`sudo -c 'docker run --rm hello-world' - ${process.env.USER}`
2022-12-02 09:09:59 -08:00
} catch (e) {
2022-12-24 20:48:43 -08:00
log('warn', logStage, `The command \`docker run --rm hello-world\` failed`)
2022-12-02 09:09:59 -08:00
try {
2022-12-04 21:46:23 -08:00
log(
2022-12-24 20:48:43 -08:00
'info',
2022-12-04 21:46:23 -08:00
logStage,
2022-12-24 20:48:43 -08:00
'Attempting to open `/Applications/Docker.app` (Docker Desktop for macOS). This should take about 30 seconds.'
)
const promises = [$`test -d /Applications/Docker.app`, $`open /Applications/Docker.app`]
await Promise.all(promises)
const gum = which.sync('gum', { nothrow: true })
2022-12-02 09:09:59 -08:00
if (gum) {
2022-12-24 20:48:43 -08:00
execSync('gum spin --spinner dot --title "Waiting for Docker Desktop to start up.." -- sleep 30', {
stdio: 'inherit',
shell: true
})
2022-12-02 09:09:59 -08:00
} else {
2022-12-24 20:48:43 -08:00
await $`sleep 30`
2022-12-02 09:09:59 -08:00
}
} catch (e) {
2022-12-24 20:48:43 -08:00
log('warn', logStage, `Docker Desktop appears to not be installed!`)
2022-12-02 09:09:59 -08:00
}
}
2022-12-02 09:01:47 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'winget') {
2023-01-04 21:12:32 -08:00
runCommand('Running winget source update', `winget source update`)
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'yay') {
} else if (packageManager === 'zypper') {
2023-01-04 21:12:32 -08:00
runCommand('Running zypper update', `sudo zypper update`)
2022-11-29 22:26:34 -08:00
}
}
async function ensureInstalled(bin, callback) {
2022-12-24 20:48:43 -08:00
const logStage = 'Package Manager Install'
const installed = which.sync(bin, { nothrow: true })
2022-11-29 22:26:34 -08:00
if (installed) {
2022-12-24 20:48:43 -08:00
log('info', logStage, `\`${bin}\` is available`)
2022-11-29 22:26:34 -08:00
} else {
2022-12-24 20:48:43 -08:00
log('warn', logStage, `\`${bin}\` is not installed!`)
2022-11-29 22:26:34 -08:00
if (callback) {
2022-12-24 20:48:43 -08:00
await callback
2022-11-29 22:26:34 -08:00
} else {
2022-12-24 20:48:43 -08:00
log('error', logStage, `There does not appear to be an installation method available for \`${bin}\``)
2022-11-29 22:26:34 -08:00
}
}
}
2022-12-02 09:50:31 -08:00
async function ensurePackageManagerAnsible() {
2022-12-25 02:03:54 -08:00
await $`pipx install ansible-core`
2022-12-25 01:38:17 -08:00
if (osType === 'darwin') {
2022-12-25 02:03:54 -08:00
await $`pipx inject ansible-core PyObjC PyObjC-core`
2022-12-25 01:38:17 -08:00
}
2022-12-25 02:03:54 -08:00
await $`pipx inject ansible-core docker lxml netaddr pexpect python-vagrant pywinrm requests-credssp watchdog`
2022-12-24 20:48:43 -08:00
await $`mkdir -p "$HOME/.cache/megabyte-labs"`
await $`touch "$HOME/.cache/megabyte-labs/ansible-installed"`
log('info', 'Package Manager Install', `Ansible and its supporting packages are now installed via pipx`)
2022-12-02 09:50:31 -08:00
}
2022-11-29 22:26:34 -08:00
// Ensure the package manager is available
2022-12-24 20:48:43 -08:00
let packageManagerInstalled = {}
2022-11-29 22:26:34 -08:00
async function ensurePackageManager(packageManager) {
2023-01-04 20:29:51 -08:00
const logStage = 'Pre-Reqs'
2022-12-24 20:48:43 -08:00
log('info', logStage, `Ensuring \`${packageManager}\` is set up`)
2022-11-29 22:26:34 -08:00
if (packageManagerInstalled[packageManager]) {
2022-12-24 20:48:43 -08:00
return
2022-11-29 22:26:34 -08:00
} else {
2022-12-24 20:48:43 -08:00
packageManagerInstalled[packageManager] = true
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
if (packageManager === 'ansible') {
await ensurePackageManager('pipx')
2022-11-29 22:26:34 -08:00
}
if (
2022-12-24 20:48:43 -08:00
packageManager === 'gem' ||
packageManager === 'go' ||
packageManager === 'npm' ||
packageManager === 'pipx' ||
packageManager === 'whalebrew'
2022-11-29 22:26:34 -08:00
) {
2022-12-24 20:48:43 -08:00
await ensurePackageManager('brew')
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
if (packageManager === 'appimage') {
2022-12-08 22:37:26 -08:00
const zap = which.sync('zap', { nothrow: true })
if (!zap) {
2022-12-24 20:48:43 -08:00
log('info', 'Zap Installation', 'Installing Zap to handle AppImage installation')
2022-12-08 23:57:44 -08:00
await ensurePackage('curl')
2023-01-03 22:54:18 -08:00
await $`sudo curl -sSL --output /usr/local/bin/zap https://github.com/srevinsaju/zap/releases/download/continuous/zap-amd64`
2023-01-04 18:58:31 -08:00
await $`sudo chmod +x /usr/local/bin/zap`
2022-12-08 22:37:26 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'ansible') {
2022-12-02 09:50:31 -08:00
try {
2022-12-24 20:48:43 -08:00
await $`test -f "$HOME/.cache/megabyte-labs/ansible-installed"`
const ansible = which.sync('ansible', { nothrow: true })
2022-12-02 09:50:31 -08:00
if (ansible) {
2022-12-24 20:48:43 -08:00
log('info', logStage, `\`ansible\` and its supporting packages appear to be installed`)
2022-12-02 09:50:31 -08:00
} else {
2022-12-24 20:48:43 -08:00
await ensurePackageManagerAnsible()
2022-12-02 09:50:31 -08:00
}
} catch (e) {
2022-12-24 20:48:43 -08:00
await ensurePackageManagerAnsible()
2022-12-02 09:50:31 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'apk') {
await ensureInstalled('apk', false)
} else if (packageManager === 'apt') {
await ensureInstalled('apt', false)
} else if (packageManager === 'basher') {
2022-12-04 21:46:23 -08:00
await ensureInstalled(
2022-12-24 20:48:43 -08:00
'basher',
2022-12-04 21:46:23 -08:00
$`
2022-11-29 22:26:34 -08:00
# TODO
echo "Bash script that installs basher here"
2022-12-04 21:46:23 -08:00
`
2022-12-24 20:48:43 -08:00
)
} else if (packageManager === 'binary') {
2022-12-08 23:57:44 -08:00
await ensurePackage('curl')
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'bpkg') {
2022-12-04 21:46:23 -08:00
await ensureInstalled(
2022-12-24 20:48:43 -08:00
'bpkg',
2022-12-04 21:46:23 -08:00
$`
2022-11-29 22:26:34 -08:00
# TODO
echo "Bash script that installs bpkg here"
2022-12-04 21:46:23 -08:00
`
2022-12-24 20:48:43 -08:00
)
} else if (packageManager === 'brew' || packageManager === 'cask') {
const brew = which.sync('brew', { nothrow: true })
2022-12-25 04:07:02 -08:00
if (!brew) {
2022-12-04 21:46:23 -08:00
await ensureInstalled(
2022-12-24 20:48:43 -08:00
'brew',
2022-12-04 21:46:23 -08:00
$`
2022-12-02 06:30:38 -08:00
if command -v sudo > /dev/null && sudo -n true; then
echo | bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
else
2022-12-02 16:13:21 -08:00
log('info', logStage, 'Homebrew is not installed. Password may be required.')
2022-12-02 06:30:38 -08:00
bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?"
if [ -n "$BREW_EXIT_CODE" ]; then
if command -v brew > /dev/null; then
2022-12-02 16:13:21 -08:00
log('warn', logStage, 'Homebrew was installed but part of the installation failed. Attempting to fix..')
2022-12-02 06:30:38 -08:00
BREW_DIRS="share/man share/doc share/zsh/site-functions etc/bash_completion.d"
for BREW_DIR in $BREW_DIRS; do
if [ -d "$(brew --prefix)/$BREW_DIR" ]; then
sudo chown -R "$(whoami)" "$(brew --prefix)/$BREW_DIR"
fi
done
brew update --force --quiet
fi
2022-11-29 22:26:34 -08:00
fi
fi
2022-12-04 21:46:23 -08:00
`
2022-12-24 20:48:43 -08:00
)
2022-12-02 06:30:38 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'cargo') {
2022-12-25 04:07:02 -08:00
const cargo = which.sync('cargo', { nothrow: true })
if (!cargo) {
if (osType === 'darwin') {
await $`brew install rustup`
await $`rustup-init`
} else if (osType === 'windows') {
} else {
await ensurePackage('cargo')
}
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'choco') {
2022-12-04 21:46:23 -08:00
await ensureInstalled(
2022-12-24 20:48:43 -08:00
'choco',
2022-12-04 21:46:23 -08:00
$`
2022-11-29 22:26:34 -08:00
powershell "Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))"
2022-12-04 21:46:23 -08:00
`
2022-12-24 20:48:43 -08:00
)
} else if (packageManager === 'crew') {
2022-12-04 21:46:23 -08:00
await ensureInstalled(
2022-12-24 20:48:43 -08:00
'crew',
2022-12-04 21:46:23 -08:00
$`
2022-11-29 22:26:34 -08:00
# TODO Bash script that installs crew here
# Source: https://github.com/chromebrew/chromebrew
curl -Ls git.io/vddgY | bash
2022-12-04 21:46:23 -08:00
`
2022-12-24 20:48:43 -08:00
)
} else if (packageManager === 'dnf') {
const dnf = which.sync('dnf', { nothrow: true })
const yum = which.sync('yum', { nothrow: true })
2022-11-29 22:26:34 -08:00
if (dnf) {
2022-12-24 20:48:43 -08:00
log('info', logStage, `\`dnf\` is available`)
2022-11-29 22:26:34 -08:00
} else if (yum) {
2022-12-24 20:48:43 -08:00
log('info', logStage, `\`yum\` is available`)
2022-11-29 22:26:34 -08:00
} else {
2022-12-24 20:48:43 -08:00
log('error', logStage, `Both \`dnf\` and \`yum\` are not available`)
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'flatpak') {
const flatpak = which.sync('flatpak', { nothrow: true })
2022-11-29 22:26:34 -08:00
if (flatpak) {
2022-12-24 20:48:43 -08:00
log('info', logStage, `\`flatpak\` is available`)
2022-11-29 22:26:34 -08:00
} else {
2022-12-24 20:48:43 -08:00
const apk = which.sync('apk', { nothrow: true })
2022-12-25 03:05:03 -08:00
const apt = which.sync('apt-get', { nothrow: true })
2022-12-24 20:48:43 -08:00
const dnf = which.sync('dnf', { nothrow: true })
const yum = which.sync('yum', { nothrow: true })
const pacman = which.sync('pacman', { nothrow: true })
const zypper = which.sync('zypper', { nothrow: true })
2022-11-29 22:26:34 -08:00
if (apk) {
2023-01-04 19:45:25 -08:00
runCommand('Installing flatpak via apk', 'sudo apk add flatpak')
2022-12-04 21:46:23 -08:00
} else if (apt) {
2023-01-04 19:45:25 -08:00
runCommand('Installing flatpak via apt-get', 'sudo apt-get install -y flatpak')
if (fileExists('/usr/bin/gnome-shell')) {
2023-01-09 04:30:16 -08:00
runCommand(
'Installing gnome-software-plugin-flatpak via apt-get',
'sudo apt-get install -y gnome-software-plugin-flatpak'
)
2023-01-04 19:45:25 -08:00
}
if (fileExists('/usr/bin/plasmashell')) {
runCommand('Installing plasmashell via apt-get', 'sudo apt-get install -y plasmashell')
}
2022-12-04 21:46:23 -08:00
} else if (dnf) {
2022-12-24 20:48:43 -08:00
await $`sudo dnf install -y flatpak`
2022-12-04 21:46:23 -08:00
} else if (yum) {
2022-12-24 20:48:43 -08:00
await $`sudo yum install -y flatpak`
2022-11-29 22:26:34 -08:00
} else if (pacman) {
2022-12-24 20:48:43 -08:00
await $`sudo pacman -Sy flatpak`
2022-11-29 22:26:34 -08:00
} else if (zypper) {
2022-12-24 20:48:43 -08:00
await $`sudo zypper install -y flatpak`
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
log('info', logStage, `\`flatpak\` was installed. It may require a reboot to function correctly.`)
2022-11-29 22:26:34 -08:00
}
2023-01-24 22:05:08 -08:00
const flatpakPost = which.sync('flatpak', { nothrow: true })
if (flatpakPost) {
await $`sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo`
} else {
log('error', logStage, `\`flatpak\` failed to install!`)
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'gem') {
2023-01-03 23:05:17 -08:00
const gem = which.sync('gem', { nothrow: true })
if (!gem) {
await ensureInstalled('gem', $`brew install ruby`)
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'go') {
2023-01-03 23:05:17 -08:00
const go = which.sync('go', { nothrow: true })
if (!go) {
await ensureInstalled('go', $`brew install go`)
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'nix') {
2022-12-04 21:46:23 -08:00
await ensureInstalled(
2022-12-24 20:48:43 -08:00
'nix',
2022-12-04 21:46:23 -08:00
$`
2022-11-29 22:26:34 -08:00
if [ -d /Applications ] && [ -d /Library ]; then
sh <(curl -L https://nixos.org/nix/install)
else
sh <(curl -L https://nixos.org/nix/install) --daemon
fi
2022-12-04 21:46:23 -08:00
`
2022-12-24 20:48:43 -08:00
)
} else if (packageManager === 'npm') {
2022-12-25 11:07:19 -08:00
const npm = which.sync('npm', { nothrow: true })
const node = which.sync('node', { nothrow: true })
const volta = which.sync('volta', { nothrow: true })
2022-11-29 22:26:34 -08:00
if (npm && node && volta) {
2022-12-24 20:48:43 -08:00
log('info', logStage, `\`npm\`, \`node\`, and \`volta\` are available`)
2022-11-29 22:26:34 -08:00
} else {
if (!volta) {
2022-12-24 20:48:43 -08:00
await $`brew install volta`
2022-11-29 22:26:34 -08:00
}
await $`
if [ -z "$VOLTA_HOME" ]; then
volta setup
fi
export PATH="$VOLTA_HOME/bin:$PATH"
volta install node
2022-12-24 20:48:43 -08:00
`
2022-11-29 22:26:34 -08:00
}
2022-12-25 02:19:44 -08:00
log('info', logStage, 'Ensuring Volt has Node.js runtime available')
2023-04-26 08:01:48 -07:00
await $`if ! volta list 2>&1 | grep 'runtime node' > /dev/null; then volta install node; fi`
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'pacman') {
await ensureInstalled('pacman', false)
} else if (packageManager === 'pipx') {
2022-12-25 11:07:19 -08:00
const pipx = which.sync('pipx', { nothrow: true })
if (!pipx) {
await ensureInstalled('pipx', $`brew install pipx`)
await $`pipx ensurepath`
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'pkg') {
await ensureInstalled('pkg', false)
} else if (packageManager === 'port') {
2022-12-05 12:25:46 -08:00
const port = which.sync('port', { nothrow: true })
if (!port) {
log('info', logStage, `Installing ${packageManager}`)
await ensureInstalled(
2022-12-24 20:48:43 -08:00
'port',
2022-12-05 12:25:46 -08:00
$`
sudo mkdir -p /opt/mports
cd /opt/mports
2022-12-05 21:42:36 -08:00
sudo rm -rf macports-base
2022-12-05 12:25:46 -08:00
sudo git clone https://github.com/macports/macports-base.git
cd macports-base
sudo git checkout v2.8.0
2022-12-06 10:20:31 -08:00
sudo bash --noprofile --norc -c './configure --enable-readline && make && make install && make distclean'
sudo port selfupdate
2022-12-05 12:25:46 -08:00
`
2022-12-24 20:48:43 -08:00
)
2022-12-05 12:25:46 -08:00
log('info', logStage, `${packageManager} is now installed`)
} else {
2022-12-24 20:48:43 -08:00
log('info', logStage, `\`port\` is available`)
2022-12-05 12:25:46 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'scoop') {
2022-12-04 21:46:23 -08:00
await ensureInstalled(
2022-12-24 20:48:43 -08:00
'scoop',
2022-12-04 21:46:23 -08:00
$`
2022-11-29 22:26:34 -08:00
powershell 'Set-ExecutionPolicy RemoteSigned -Scope CurrentUser'
powershell 'irm get.scoop.sh | iex
2022-12-04 21:46:23 -08:00
`
2022-12-24 20:48:43 -08:00
)
} else if (packageManager === 'snap') {
const apk = which.sync('apk', { nothrow: true })
const apt = which.sync('apt-get', { nothrow: true })
const dnf = which.sync('dnf', { nothrow: true })
const yum = which.sync('yum', { nothrow: true })
const pacman = which.sync('pacman', { nothrow: true })
const zypper = which.sync('zypper', { nothrow: true })
2022-12-04 21:46:23 -08:00
if (apt) {
2023-01-04 20:16:11 -08:00
if (fileExists('/etc/apt/preferences.d/nosnap.pref')) {
$`sudo mv /etc/apt/preferences.d/nosnap.pref /etc/apt/nosnap.pref.bak`
}
runCommand('Ensuring snapd is installed', `sudo apt-get install -y snapd`)
2022-12-04 21:46:23 -08:00
// TODO Following may be required on Kali -> https://snapcraft.io/docs/installing-snap-on-kali
// systemctl enable --now snapd apparmor
2023-01-31 19:37:22 -08:00
runCommand('Enabling snapd service', `sudo systemctl enable snapd`)
runCommand('Starting snapd service', `sudo systemctl start snapd`)
2022-12-04 21:46:23 -08:00
} else if (dnf) {
2023-01-04 20:16:11 -08:00
runCommand('Ensuring snapd is installed', `sudo dnf install -y snapd`)
if (!fileExists('/snap')) {
await $`sudo ln -s /var/lib/snapd/snap /snap`
}
2023-01-31 19:37:22 -08:00
runCommand('Enabling snapd service', `sudo systemctl enable snapd`)
runCommand('Starting snapd service', `sudo systemctl start snapd`)
2022-12-04 21:46:23 -08:00
} else if (yum) {
2023-01-04 20:18:00 -08:00
runCommand('Ensuring snapd is installed', 'sudo yum install -y snapd')
2023-01-04 20:16:11 -08:00
await $`sudo systemctl enable --now snapd.socket`
if (!fileExists('/snap')) {
$`sudo ln -s /var/lib/snapd/snap /snap`
}
2022-12-04 21:46:23 -08:00
} else if (pacman) {
2023-01-04 20:16:11 -08:00
$`if [ -f /etc/arch-release ]; then sudo git clone https://aur.archlinux.org/snapd.git /usr/local/src/snapd && cd /usr/local/src/snapd && sudo makepkg -si; else sudo pacman -S snapd && sudo systemctl enable --now snapd.socket && if [ ! -d /snap ]; then sudo ln -s /var/lib/snapd/snap /snap; fi; fi`
2022-12-04 21:46:23 -08:00
} else if (zypper) {
// TODO See https://snapcraft.io/docs/installing-snap-on-opensuse
await $`
2022-11-29 22:26:34 -08:00
echo "TODO - Bash script that installs snap w/ zypper"
2022-12-24 20:48:43 -08:00
`
2022-12-04 21:46:23 -08:00
}
2022-12-24 20:48:43 -08:00
const snap = which.sync('snap', { nothrow: true })
2022-12-04 21:46:23 -08:00
if (snap) {
2023-01-24 17:01:33 -08:00
runCommand('Check info for core snap package', `sudo snap info core`)
2023-01-04 19:58:08 -08:00
runCommand('Ensuring snap core is installed', `sudo snap install core`)
2022-12-08 21:19:29 -08:00
} else {
2022-12-24 20:48:43 -08:00
log('warn', logStage, 'Snap installation sequence completed but the snap bin is still not available')
2022-12-04 21:46:23 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'script') {
} else if (packageManager === 'whalebrew') {
await ensureInstalled('whalebrew', $`brew install whalebrew`)
} else if (packageManager === 'winget') {
2022-12-04 21:46:23 -08:00
await ensureInstalled(
2022-12-24 20:48:43 -08:00
'winget',
2022-12-04 21:46:23 -08:00
$`
2022-11-29 22:26:34 -08:00
echo "TODO - Script that installs winget here"
2022-12-04 21:46:23 -08:00
`
2022-12-24 20:48:43 -08:00
)
} else if (packageManager === 'yay') {
const yay = which.sync('yay', { nothrow: true })
await $`sudo pacman -S --needed base-devel git`
2022-11-29 22:26:34 -08:00
await $`
if [ -d /usr/local/src ]; then
git clone https://aur.archlinux.org/yay.git /usr/local/src/yay
cd /usr/local/src/yay
makepkg -si
fi
2022-12-24 20:48:43 -08:00
`
} else if (packageManager === 'zypper') {
await ensureInstalled('zypper', false)
2022-11-29 22:26:34 -08:00
}
}
// Installs a list of packages via the specified package manager
async function installPackageList(packageManager, packages) {
2022-12-24 20:48:43 -08:00
const logStage = 'Package Install'
2022-11-29 22:26:34 -08:00
try {
2022-12-24 20:48:43 -08:00
if (packageManager === 'appimage') {
2022-12-08 22:37:26 -08:00
for (let pkg of packages) {
try {
2023-01-08 21:20:41 -08:00
if (pkg.substring(0, 4) === 'http') {
2022-12-24 20:48:43 -08:00
log('info', 'AppImage Install', `Installing ${pkg} from its URL`)
2023-01-24 16:51:15 -08:00
runCommand('Installing ${pkg} via zap', `zap install --select-first -q --from ${pkg}`)
2023-01-09 03:34:43 -08:00
} else if ((pkg.match(/\//g) || []).length === 1) {
2022-12-24 20:48:43 -08:00
log('info', 'AppImage Install', `Installing ${pkg} from a GitHub Release`)
2023-01-24 16:51:15 -08:00
runCommand('Installing ${pkg} via zap', `zap install --select-first -q --github --from ${pkg}`)
2022-12-08 22:37:26 -08:00
} else {
2022-12-24 20:48:43 -08:00
log('info', 'AppImage Install', `Installing ${pkg} using the AppImage Catalog`)
2023-01-24 16:51:15 -08:00
runCommand('Installing ${pkg} via zap', `zap install --select-first -q ${pkg}`)
2022-12-08 22:37:26 -08:00
}
2023-01-04 20:57:52 -08:00
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-08 22:37:26 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error using Zap to install ${pkg}`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-08 22:37:26 -08:00
}
}
2023-01-09 05:38:35 -08:00
log('warn', 'Install', 'Zap installs might fail - this is expected. Waiting on fixes to Zap upstream project')
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'ansible') {
2022-12-02 15:15:45 -08:00
for (let pkg of packages) {
2022-12-02 16:44:43 -08:00
try {
2022-12-06 13:04:49 -08:00
const unbuffer = which.sync('unbuffer', { nothrow: true })
let unbufferPrefix = ''
if (unbuffer) {
2022-12-06 14:24:46 -08:00
unbufferPrefix = 'unbuffer'
2022-12-06 13:04:49 -08:00
}
2023-01-09 16:06:45 -08:00
const verboseMode = process.env.DEBUG_MODE === 'true' ? 'vv' : ''
2023-01-09 04:46:44 -08:00
if (osPlatform === 'darwin' || osPlatform === 'linux' || osPlatform === 'windows') {
2023-01-12 12:19:28 -08:00
const capitalOsPlatform = osPlatform.charAt(0).toUpperCase() + osPlatform.slice(1)
await $`ANSIBLE_CONFIG=${process.env.HOME}/.local/share/ansible/ansible.cfg ansible 127.0.0.1 -v${verboseMode} -e '{ ansible_connection: "local", ansible_become_user: "root", ansible_user: "${process.env.USER}", ansible_family: "${capitalOsPlatform}", install_homebrew: False }' -m include_role -a name=${pkg}`
2023-01-09 04:46:44 -08:00
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
} else {
log('warn', 'Ansible', 'Unsupported platform - ' + osPlatform)
}
2022-12-02 16:44:43 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with Ansible`)
2022-12-02 16:44:43 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'apk') {
2022-12-02 15:15:45 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:05:31 -08:00
runCommand('Installing ${pkg} via apk', `sudo apk add ${pkg}`)
2023-01-04 20:57:52 -08:00
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-02 17:39:29 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with apk`)
2023-01-08 21:30:07 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-12-02 15:15:45 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'apt') {
2022-12-02 15:15:45 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-09 04:30:16 -08:00
runCommand(
`Installing ${pkg} via ${packageManager}`,
`sudo apt-get -o DPkg::Options::=--force-confdef install -y ${pkg}`
)
2023-01-04 20:57:52 -08:00
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-02 17:39:29 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with apt-get`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-12-02 15:15:45 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'basher') {
2022-12-04 19:51:47 -08:00
for (let pkg of packages) {
try {
2022-12-24 20:48:43 -08:00
await $`basher install ${pkg}`
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with basher`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-04 19:51:47 -08:00
}
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'binary') {
2022-12-08 22:37:26 -08:00
for (let pkg of packages) {
try {
2023-01-09 04:30:16 -08:00
const bins = installData.softwarePackages.filter((x) => x.appimage === pkg)
2023-01-09 04:00:59 -08:00
if (bins && bins[0]) {
const binName = bins[0]['_bin']
await $`TMP="$(mktemp)" && curl -sSL ${pkg} > "$TMP" && sudo mv "$TMP" /usr/local/src/${binName} && chmod +x /usr/local/src/${binName}`
}
2022-12-08 22:37:26 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing the binary release for ${pkg}`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-08 22:37:26 -08:00
}
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'brew') {
2022-12-02 15:15:45 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `brew install ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-02 17:39:29 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with brew`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-12-02 15:15:45 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'cask') {
2022-12-02 15:15:45 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `brew install --cask ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with Homebrew Cask`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-12-02 15:15:45 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'cargo') {
2022-12-02 06:40:47 -08:00
for (const pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `cargo install ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-02 17:39:29 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with Cargo`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'choco') {
2022-12-02 15:15:45 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `choco install -y ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-02 17:39:29 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with Chocolatey`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-12-02 15:15:45 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'crew') {
} else if (packageManager === 'dnf') {
const dnf = which.sync('dnf', { nothrow: true })
const yum = which.sync('yum', { nothrow: true })
2023-01-03 20:39:23 -08:00
for (let pkg of packages) {
if (dnf) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `sudo dnf install -y ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-02 17:39:29 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with dnf`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2023-01-03 20:39:23 -08:00
} else if (yum) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `sudo yum install -y ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with yum`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-12-02 15:15:45 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'flatpak') {
2022-12-02 06:40:47 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `sudo flatpak install -y flathub ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with flatpak`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'gem') {
2022-12-02 06:40:47 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `gem install ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-02 17:39:29 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with gem`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'go') {
2022-12-02 06:40:47 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `go install ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with go`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'nix') {
} else if (packageManager === 'npm') {
2022-12-02 06:40:47 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `volta install ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with volta`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'pacman') {
2022-12-02 15:15:45 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `sudo pacman -Sy --noconfirm --needed ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with pacman`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-12-02 15:15:45 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'pipx') {
2022-12-02 06:40:47 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `pipx install ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with pipx`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-11-29 22:26:34 -08:00
}
2023-04-19 16:53:21 -07:00
} else if (packageManager === 'pkg-darwin') {
for (let pkg of packages) {
try {
runCommand(`Installing ${pkg} via ${packageManager}`, `TMP="$(mktemp)" && curl -sSL "${pkg}" > "$TMP" && sudo installer -pkg "$TMP" -target /`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
} catch (e) {
log('error', 'Install', `There was an error installing ${pkg} with the system installer`)
console.error(e)
}
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'port') {
const port = which.sync('port', { nothrow: true })
2022-12-04 19:39:40 -08:00
if (port) {
for (let pkg of packages) {
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `sudo port install ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with port`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-04 19:39:40 -08:00
}
2022-12-02 17:39:29 -08:00
}
2022-12-04 19:39:40 -08:00
} else {
2022-12-04 21:46:23 -08:00
log(
2022-12-24 20:48:43 -08:00
'error',
'Port Not Installed',
2022-12-04 21:46:23 -08:00
`Unable to install with port because it is not installed. Skipping installation of ${packages}`
2022-12-24 20:48:43 -08:00
)
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'scoop') {
2022-12-02 06:40:47 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `scoop install ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with scoop`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'snap') {
2022-12-02 06:40:47 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `sudo snap install ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with snap`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'script') {
2022-12-08 22:37:26 -08:00
for (let pkg of packages) {
try {
2023-01-08 23:14:44 -08:00
await $`bash -c ${pkg}`
2022-12-24 20:48:43 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error running the script installation method for ${pkg}`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-08 22:37:26 -08:00
}
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'snap-classic') {
2022-12-08 21:19:29 -08:00
for (let pkg of packages) {
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `sudo snap install --classic ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-24 20:48:43 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with snap in classic mode`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-08 21:19:29 -08:00
}
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'whalebrew') {
2022-12-02 06:40:47 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `whalebrew install ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with whalebrew`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'winget') {
2022-12-04 19:51:47 -08:00
for (let pkg of packages) {
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `winget install ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with winget`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-04 19:51:47 -08:00
}
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'yay') {
2022-12-02 06:40:47 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `yay -Sy --noconfirm --needed ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with yay`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-11-29 22:26:34 -08:00
}
2022-12-24 20:48:43 -08:00
} else if (packageManager === 'zypper') {
2022-12-02 15:15:45 -08:00
for (let pkg of packages) {
2022-12-02 17:39:29 -08:00
try {
2023-01-04 20:57:52 -08:00
runCommand(`Installing ${pkg} via ${packageManager}`, `sudo zypper install -y ${pkg}`)
log('success', 'Install', `${pkg} successfully installed via ${packageManager}`)
2022-12-04 21:46:23 -08:00
} catch (e) {
2023-01-09 05:05:00 -08:00
log('error', 'Install', `There was an error installing ${pkg} with zypper`)
2023-01-04 20:57:52 -08:00
console.error(e)
2022-12-02 17:39:29 -08:00
}
2022-12-02 15:15:45 -08:00
}
2022-11-29 22:26:34 -08:00
}
} catch (e) {
2022-12-24 20:48:43 -08:00
log('error', logStage, `Possibly encountered an error while installing via \`${packageManager}\``)
log('info', logStage, `Proceeding with the installation..`)
2022-11-29 22:26:34 -08:00
}
}
2023-01-29 19:09:02 -08:00
async function addUserGroup(group) {
const logStage = 'Users / Groups'
log('info', logStage, `Ensuring the ${group} group / user is added`)
if (osType === 'linux') {
const useradd = which.sync('useradd', { nothrow: true })
2023-04-19 00:06:59 -07:00
const usermod = which.sync('usermod', { nothrow: true })
if (useradd && usermod) {
2023-01-29 19:09:02 -08:00
runCommand(`Adding the ${group} user / group`, `sudo useradd ${group}`)
2023-04-19 00:06:59 -07:00
runCommand(`Adding the ${process.env.USER} user to the ${group} group`, `sudo usermod -a -G ${group} ${process.env.USER}`)
2023-01-29 19:09:02 -08:00
} else {
2023-04-19 00:06:59 -07:00
log('error', logStage, `The useradd and / or usermod command is unavailable`)
2023-01-29 19:09:02 -08:00
}
} else if (osType === 'darwin') {
2023-04-19 00:06:59 -07:00
runCommand(`Creating the ${group} group`, `sudo dscl . create /Groups/${group}`)
runCommand(`Ensuring the ${group} group has a GID`, `if [[ "$(sudo dscl . read /Groups/$GROUP gid 2>&1)" == *'No such key'* ]]; then MAX_ID_GROUP="$(dscl . -list /Groups gid | awk '{print $2}' | sort -ug | tail -1)"; GROUP_ID="$((MAX_ID_GROUP+1))"; sudo dscl . create /Groups/${group} gid "$GROUP_ID"; fi`)
runCommand(`Adding the ${group} user`, `sudo dscl . create /Users/${group}`)
runCommand(`Ensuring the ${group} user has a PrimaryGroupID`, `if [[ "$(sudo dscl . read /Users/${group} PrimaryGroupID 2>&1)" == *'No such key'* ]]; then sudo dscl . create /Users/${group} PrimaryGroupID 20; fi`)
runCommand(`Ensuring the ${group} user has a UniqueID`, `if [[ "$(sudo dscl . read /Users/${group} UniqueID 2>&1)" == *'No such key'* ]]; then MAX_ID_USER="$(dscl . -list /Users UniqueID | awk '{print $2}' | sort -ug | tail -1)"; USER_ID="$((MAX_ID_USER+1))"; sudo dscl . create /Users/${group} UniqueID "$USERID"; fi`)
runCommand(`Adding the ${group} user to the ${group} group`, `sudo dseditgroup -o edit -t user -a ${group} ${group}`)
runCommand(`Adding the ${process.env.USER} user to the ${group} group`, `sudo dseditgroup -o edit -t user -a ${process.env.USER} ${group}`)
2023-01-29 19:09:02 -08:00
} else if (osType === 'windows') {
log('warn', logStage, `Windows support not yet added`)
} else {
log('warn', logStage, `Unknown operating system type`)
}
}
2023-01-08 18:12:24 -08:00
async function updateService(service) {
const logStage = 'Service Service'
2022-12-24 20:48:43 -08:00
if (osType === 'linux') {
2023-01-08 18:12:24 -08:00
const systemctl = which.sync('systemctl', { nothrow: true })
2023-01-29 19:09:02 -08:00
const brew = which.sync('brew', { nothrow: true })
2023-01-08 18:12:24 -08:00
if (systemctl) {
2022-12-08 21:19:29 -08:00
try {
2023-01-08 21:30:07 -08:00
runCommand(`Starting / enabling ${service} with systemctl`, `sudo systemctl enable --now ${service}`)
log('success', logStage, `Started / enabled the ${service} service`)
2022-12-08 21:19:29 -08:00
} catch (e) {
2023-01-29 19:09:02 -08:00
log('info', logStage, `There was an error starting / enabling the ${service} service with systemd`)
try {
if (brew) {
runCommand(`Starting / enabling ${service} with Homebrew`, `brew services start ${service}`)
log('success', logStage, `Started / enabled the ${service} service with Homebrew`)
} else {
log('error', logStage, `Unable to start service with systemd and Homebrew is not available`)
}
} catch (err) {
log('error', logStage, `Unable to start service with both systemd and Homebrew`)
log('info', logStage, `systemd error`)
console.error(e)
log('info', logStage, `brew services error`)
console.error(e)
}
2022-12-08 21:19:29 -08:00
}
} else {
2022-12-24 20:48:43 -08:00
log(
'warn',
logStage,
`The systemctl command is not available so applications with services cannot be started / enabled`
)
2022-12-08 21:19:29 -08:00
}
2022-12-24 08:44:38 -08:00
} else if (osType === 'darwin') {
const brew = which.sync('brew', { nothrow: true })
if (brew) {
try {
2023-01-08 21:30:07 -08:00
runCommand(`Starting / enabling ${service} with Homebrew`, `brew services start ${service}`)
log('success', logStage, `Started / enabled the ${service} service with Homebrew`)
2022-12-24 08:48:46 -08:00
} catch (e) {
2022-12-24 20:48:43 -08:00
log('error', logStage, `There was an error starting / enabling the ${service} Homebrew service`)
2022-12-24 08:48:46 -08:00
console.error(e)
2022-12-24 08:44:38 -08:00
}
} else {
2022-12-24 20:48:43 -08:00
log('warn', logStage, `Homebrew is not available - skipping service start command`)
2022-12-24 08:44:38 -08:00
}
2022-12-08 21:19:29 -08:00
}
}
2023-01-04 17:31:03 -08:00
/**
2023-01-09 04:30:16 -08:00
* Filter that resolves when all asynchronous filter actions are done
*/
2023-01-04 17:31:03 -08:00
const asyncFilter = async (arr, predicate) => {
2023-01-09 04:30:16 -08:00
const results = await Promise.all(arr.map(predicate))
2023-01-04 17:31:03 -08:00
2023-01-09 04:30:16 -08:00
return arr.filter((_v, index) => results[index])
2023-01-04 17:31:03 -08:00
}
2023-01-03 20:39:23 -08:00
async function pruneInstallOrders(installOrders) {
const newOrders = Object.assign({}, installOrders)
2023-01-04 21:17:32 -08:00
log('info', 'Filter', 'Removing packages from installOrders that are already installed')
2023-01-04 19:04:55 -08:00
for (const pkgManager in installOrders) {
2023-01-04 21:17:32 -08:00
log('info', 'Filter', `Filtering the ${pkgManager} installOrders`)
2023-02-15 22:14:03 -08:00
console.log('List to be filtered:', newOrders[pkgManager])
2023-01-09 03:34:43 -08:00
if (pkgManager === 'appimage') {
newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => {
try {
2023-01-09 04:34:45 -08:00
await runSilentCommand(`zap list | grep "${pkg}" > /dev/null`)
2023-01-09 03:34:43 -08:00
return false
} catch (e) {
return true
}
})
} else if (pkgManager === 'apt') {
2023-01-04 19:45:25 -08:00
newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => {
2023-01-03 20:39:23 -08:00
try {
2023-01-04 22:02:52 -08:00
await runSilentCommand(`dpkg -l ${pkg} | grep -E '^ii' > /dev/null`)
2023-01-04 19:45:25 -08:00
return false
2023-01-04 20:09:38 -08:00
} catch (e) {
return true
2023-01-03 20:39:23 -08:00
}
})
2023-01-03 21:28:46 -08:00
} else if (pkgManager === 'brew') {
2023-01-04 19:52:42 -08:00
let newVal = newOrders[pkgManager]
2023-02-15 22:17:29 -08:00
const pkgTmp = '/tmp/brew-list-install-doctor'
runCommand(`Populating temporary file with list of Homebrew packages`, `brew list > ${pkgTmp}`)
2023-01-04 20:20:38 -08:00
for (const pkg of newOrders[pkgManager]) {
2023-01-03 21:28:46 -08:00
try {
2023-02-15 22:17:29 -08:00
await $`cat ${pkgTmp} | grep '^${pkg}$'`
2023-01-09 04:30:16 -08:00
newVal = newVal.filter((x) => x === pkg)
2023-01-03 21:28:46 -08:00
} catch (e) {
2023-01-03 23:33:00 -08:00
// Do nothing
2023-01-03 21:28:46 -08:00
}
2023-01-03 23:33:00 -08:00
}
2023-01-04 19:52:42 -08:00
newOrders[pkgManager] = newVal
2023-01-03 20:39:23 -08:00
} else if (pkgManager === 'dnf') {
const dnf = which.sync('dnf', { nothrow: true })
2023-01-04 19:45:25 -08:00
newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => {
2023-01-03 20:39:23 -08:00
try {
if (dnf) {
2023-02-01 19:08:26 -08:00
await runSilentCommand(`rpm -qa | grep '$'"${pkg}-" > /dev/null`)
2023-01-03 20:39:23 -08:00
} else {
2023-02-01 19:08:26 -08:00
await runSilentCommand(`rpm -qa | grep '$'"${pkg}-" > /dev/null`)
2023-01-03 20:39:23 -08:00
}
2023-01-04 19:45:25 -08:00
return false
2023-01-04 20:09:38 -08:00
} catch (e) {
return true
2023-01-03 20:39:23 -08:00
}
})
} else if (pkgManager === 'flatpak') {
2023-01-08 18:35:05 -08:00
const flatpakInstallation = await $`flatpak --installations`
2023-01-08 23:17:09 -08:00
const flatpakDir = flatpakInstallation.stdout.replace('\n', '')
2023-01-05 22:46:14 -08:00
newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => {
try {
2023-01-08 21:30:07 -08:00
await runSilentCommand(`test -d ${flatpakDir}/app/${pkg}`)
2023-01-05 22:46:14 -08:00
return false
} catch (e) {
return true
}
})
2023-01-05 22:33:56 -08:00
newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => {
2023-01-03 20:39:23 -08:00
try {
2023-01-04 22:02:52 -08:00
await runSilentCommand(`flatpak info ${pkg} > /dev/null`)
2023-01-04 19:45:25 -08:00
return false
2023-01-05 22:22:47 -08:00
} catch (e) {
return true
2023-01-03 20:39:23 -08:00
}
})
} else if (pkgManager === 'pacman') {
2023-01-04 19:45:25 -08:00
newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => {
2023-01-03 20:39:23 -08:00
try {
2023-01-05 22:33:56 -08:00
await runSilentCommand(`pacman -Qs ${pkg} > /dev/null`)
2023-01-04 21:47:56 -08:00
return false
} catch (e) {
return true
}
})
2023-01-04 22:02:52 -08:00
} else if (pkgManager === 'snap' || pkgManager === 'snap-classic') {
2023-01-04 21:47:56 -08:00
newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => {
try {
2023-01-04 22:02:52 -08:00
await runSilentCommand(`snap list ${pkg} | grep ${pkg} > /dev/null`)
2023-01-04 19:45:25 -08:00
return false
2023-01-04 20:09:38 -08:00
} catch (e) {
return true
2023-01-03 20:39:23 -08:00
}
})
}
2023-01-04 20:09:38 -08:00
log('info', 'Filter', `Finished filtering ${pkgManager}`)
2023-02-15 22:14:03 -08:00
console.log('Filtered list:', newOrders[pkgManager])
2023-01-03 20:39:23 -08:00
}
return newOrders
}
2023-01-08 20:39:29 -08:00
async function installPlugins(pluginData) {
2023-01-08 23:25:38 -08:00
if (pluginData.cmd && pluginData.plugins && pluginData.plugins.length) {
for (const plugin of pluginData.plugins) {
try {
const pluginCmd = pluginData.cmd.replace(/{PLUGIN}/g, plugin)
2023-01-08 23:43:44 -08:00
runCommand(`Installing ${pluginData.package} plugin - ${plugin}`, pluginCmd)
2023-01-08 23:25:38 -08:00
log('success', 'Plugin', `Successfully installed ${pluginData.package} plugin - ${plugin}`)
} catch (e) {
log('error', 'Plugin', `Failed to install ${pluginData.package} plugin - ${plugin}`)
console.error(e)
}
2023-01-08 20:39:29 -08:00
}
}
}
2023-01-08 23:14:44 -08:00
async function linkBin(installOrdersBinLink) {
let flatpakInstallation, flatpakDir
2023-01-08 23:26:28 -08:00
const softwarePackages = installData.softwarePackages
2023-01-08 23:14:44 -08:00
const flatpak = which.sync('flatpak', { nothrow: true })
if (flatpak) {
flatpakInstallation = await $`flatpak --installations`
2023-01-08 23:43:44 -08:00
flatpakDir = flatpakInstallation.stdout.replace('\n', '')
2023-01-08 23:14:44 -08:00
}
for (const binLink of installOrdersBinLink) {
const pkg = softwarePackages[binLink.package][binLink.preference]
2023-01-09 04:30:16 -08:00
if (typeof pkg === 'string') {
if (!which.sync(binLink.bin, { nothrow: true })) {
2023-01-09 02:10:20 -08:00
if (binLink.preference === 'flatpak' && flatpak) {
try {
2023-01-09 04:30:16 -08:00
runCommand(
`Adding bin link for ${pkg} (${binLink.bin})`,
2023-01-24 16:09:53 -08:00
`bash -c 'test -d ${flatpakDir}/app/${pkg} && mkdir -p "${process.env.HOME}/.local/bin/flatpak" && echo "flatpak run ${pkg} \\\$*" > "${process.env.HOME}/.local/bin/flatpak/${binLink.bin}" && chmod +x "${process.env.HOME}/.local/bin/flatpak/${binLink.bin}"'`
2023-01-09 04:30:16 -08:00
)
2023-01-09 02:10:20 -08:00
log('success', 'Bin', `Linked ~/.local/bin/flatpak/${binLink.bin} to the ${pkg} Flatpak`)
} catch (e) {
log('warn', 'Bin', `Expected flatpak directory not available - ${flatpakDir}/app/${pkg}`)
}
} else if (binLink.preference === 'cask') {
try {
2023-01-09 04:30:16 -08:00
const caskWhen = softwarePackages[binLink.package]['_when:cask']
2023-03-26 23:33:56 -07:00
const caskDir = caskWhen.replace('! test -d ', '')
2023-01-09 02:10:20 -08:00
if (fileExists(caskDir)) {
2023-01-09 04:30:16 -08:00
runCommand(
`Adding shortcut bin link for ${binLink.package}`,
2023-01-24 16:09:53 -08:00
`bash -c 'mkdir -p "${process.env.HOME}/.local/bin/cask" && echo "open ${caskDir} \\\$*" > "${process.env.HOME}/.local/bin/cask/${binLink.bin}" && chmod +x "${process.env.HOME}/.local/bin/cask/${binLink.bin}"'`
2023-01-09 04:30:16 -08:00
)
2023-01-09 02:10:20 -08:00
} else {
log('warn', 'Bin', `Expected Homebrew cask directory not found - ${pkg}`)
}
} catch (e) {
log('warn', 'Bin', `Error creating bin shortcut link for ${pkg}`)
2023-01-09 00:16:59 -08:00
}
2023-01-08 23:14:44 -08:00
}
2023-01-09 02:10:20 -08:00
} else {
log('info', 'Bin', `Link already exists for ${binLink.package}`)
2023-01-08 23:14:44 -08:00
}
} else {
2023-01-09 02:10:20 -08:00
log('info', 'Bin', `Skipping ${binLink.package} because there was more than one _bin value`)
2023-01-08 23:14:44 -08:00
}
}
}
2022-11-29 22:26:34 -08:00
// main process
2022-12-08 23:57:44 -08:00
async function installSoftware(pkgsToInstall) {
2022-12-24 20:48:43 -08:00
osType = await OSType()
osID = osType
if (osType === 'linux') {
osID = await releaseID()
2022-12-04 21:46:23 -08:00
}
2022-12-24 20:48:43 -08:00
log('info', 'Catalog Download', `Fetching the latest version of the installation map`)
installData = await downloadInstallData()
2023-01-04 21:17:32 -08:00
log('info', 'Filter', `Calculating the install orders`)
2022-12-24 20:48:43 -08:00
await generateInstallOrders(pkgsToInstall ? pkgsToInstall : process.argv.slice(3))
const packageManagers = Object.keys(installOrders)
2023-02-01 09:20:19 -08:00
packageManagers.length && log('info', 'Pre-Reqs', `Ensuring any package managers that will be used are installed / configured`)
2022-11-29 22:26:34 -08:00
for (const packageManager of packageManagers) {
2022-12-24 20:48:43 -08:00
await ensurePackageManager(packageManager)
2022-11-29 22:26:34 -08:00
}
2022-12-24 08:57:06 -08:00
try {
for (const key in installOrders) {
2022-12-24 20:48:43 -08:00
installOrders[key] = [...new Set(installOrders[key])]
2022-12-24 08:57:06 -08:00
}
2023-01-04 21:17:32 -08:00
log('info', 'Install', `The install orders were generated:`)
2022-12-24 08:57:06 -08:00
} catch (e) {
2023-01-04 21:17:32 -08:00
log('error', 'Filter', `There was an error reducing the duplicates in the install orders`)
2022-12-24 08:57:06 -08:00
console.error(e)
2022-12-24 08:44:38 -08:00
}
2023-01-03 20:39:23 -08:00
installOrders = await pruneInstallOrders(installOrders)
2023-02-15 22:14:03 -08:00
console.log('Install orders:', installOrders)
2023-02-01 09:20:19 -08:00
packageManagers.length && log('info', 'Pre-Reqs', `Running package manager pre-installation steps`)
2022-11-29 22:26:34 -08:00
for (const packageManager of packageManagers) {
2022-12-24 20:48:43 -08:00
await beforeInstall(packageManager)
2022-11-29 22:26:34 -08:00
}
2023-02-01 09:20:19 -08:00
installOrdersPre.length && log('info', 'Pre-Install', `Running package-specific pre-installation steps`)
2022-11-29 22:26:34 -08:00
for (const script of installOrdersPre) {
2022-12-24 20:48:43 -08:00
await $`${script}`
2022-11-29 22:26:34 -08:00
}
2023-02-04 01:19:31 -08:00
installOrdersGroups.length && log('info', 'Users / Groups', `Adding groups / users`)
for (const group of installOrdersGroups) {
await addUserGroup(group)
}
2023-02-01 09:20:19 -08:00
packageManagers.length && log('info', 'Install', `Installing the packages`)
2022-11-29 22:26:34 -08:00
for (const packageManager of packageManagers) {
2022-12-24 20:48:43 -08:00
const asyncOrders = []
asyncOrders.push(installPackageList(packageManager, installOrders[packageManager]))
await Promise.all(asyncOrders)
2022-11-29 22:26:34 -08:00
}
2023-02-01 09:20:19 -08:00
installOrdersService.length && log('info', 'Post-Install', `Running package-specific post-installation steps`)
2023-01-08 18:12:24 -08:00
for (const service of installOrdersService) {
await updateService(service)
2022-12-08 21:19:29 -08:00
}
2023-01-09 01:31:22 -08:00
if (!binLinkRan) {
binLinkRan = true
log('info', 'Bin', 'Linking bin aliases to their installed packages')
await linkBin(installOrdersBinLink)
for (const script of installOrdersPost) {
2023-03-27 00:36:57 -07:00
try {
await $`${script}`
} catch(e) {
log('info', 'Post-Install Hook', 'Encountered error while running post-install hook')
}
2023-01-09 01:31:22 -08:00
}
}
2023-02-01 09:20:19 -08:00
installOrdersPlugins.length && log('info', 'Plugin', 'Installing package-specific plugins')
2023-01-08 20:39:29 -08:00
for (const plugin of installOrdersPlugins) {
await installPlugins(plugin)
}
2023-02-01 09:20:19 -08:00
packageManagers.length && log('info', 'Post-Install', `Running package manager post-installation steps`)
2022-11-29 22:26:34 -08:00
for (const packageManager of packageManagers) {
2022-12-24 20:48:43 -08:00
await afterInstall(packageManager)
2022-11-29 22:26:34 -08:00
}
2023-01-04 21:17:32 -08:00
log('success', 'Complete', `Done!`)
2022-11-29 22:26:34 -08:00
}
// Start the main process
2022-12-24 20:48:43 -08:00
await installSoftware(false)