diff --git a/home/.chezmoiscripts/universal/run_after_10-install.sh.tmpl b/home/.chezmoiscripts/universal/run_after_10-install.sh.tmpl index 78fd6110..99a16386 100644 --- a/home/.chezmoiscripts/universal/run_after_10-install.sh.tmpl +++ b/home/.chezmoiscripts/universal/run_after_10-install.sh.tmpl @@ -47,12 +47,14 @@ if command -v install-program > /dev/null; then if command -v unbuffer > /dev/null; then logg info 'Running unbuffer install-program' unbuffer install-program {{ $softwareList }} + logg info 'Running unbuffer installx' + unbuffer installx {{ $softwareList }} else logg info 'Running install-program without unbuffer' install-program {{ $softwareList }} + logg info 'Running installx' + installx {{ $softwareList }} fi - # TODO - Figure out how to configure no logs to print to ~/.ansible.log -- should be printing to the value specified in the ansible.cfg - rm -rf "$HOME/.ansible.log" else logg error 'zx is not available' fi diff --git a/home/.chezmoiscripts/universal/run_before_05-system.sh.tmpl b/home/.chezmoiscripts/universal/run_before_05-system.sh.tmpl index da66b8fc..304b5633 100644 --- a/home/.chezmoiscripts/universal/run_before_05-system.sh.tmpl +++ b/home/.chezmoiscripts/universal/run_before_05-system.sh.tmpl @@ -654,12 +654,25 @@ installBrewPackages() { logg success 'Finished installing auxilary Homebrew packages' } +ensureMacportsInstalled() { + if [ -d /Applications ] && [ -d /System ]; then + if ! command -v port > /dev/null; then + logg info 'Ensuring /opt/mports/macports-base is removed' && sudo rm -rf /opt/mports/macports-base + logg info 'Cloning source for macports to /opt/mports/macports-base' && sudo git clone --branch v2.8.0 --depth 1 https://github.com/macports/macports-base.git /opt/mports/macports-base + cd /opt/mports/macports-base + logg info 'Building macports' && sudo bash --noprofile --norc -c './configure --enable-readline && make && make install && make distclean' + logg info 'Running sudo port selfupdate' && sudo port selfupdate + fi + fi +} + if [ -n "$DEBUG" ] || [ -n "$DEBUG_MODE" ]; then logg info 'The DEBUG or DEBUG_MODE environment variable is set so preliminary system tweaks will be run synchronously' allocateSwap configureGPG disableDStoreFileCreation enableDarkTransparentMode + ensureMacportsInstalled ensureUserGroup increaseMapCount installBrewPackages @@ -676,6 +689,7 @@ else configureGPG & disableDStoreFileCreation & enableDarkTransparentMode & + ensureMacportsInstalled & ensureUserGroup & increaseMapCount & installBrewPackages & diff --git a/home/dot_config/shell/exports.sh.tmpl b/home/dot_config/shell/exports.sh.tmpl index 9e456b97..821456aa 100644 --- a/home/dot_config/shell/exports.sh.tmpl +++ b/home/dot_config/shell/exports.sh.tmpl @@ -185,6 +185,9 @@ export CURLOPT_ACCEPT_ENCODING=true ### Dagu export DAGU_HOME="${XDG_CONFIG_HOME:-$HOME/.config}/dagu" +### Debian +export DEBIAN_FRONTEND=noninteractive + ### Desk export DESK_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/desk" export DESK_DESKS_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/desk/desks" @@ -225,6 +228,10 @@ if command -v flatpak > /dev/null; then export XDG_DATA_DIRS="${XDG_CONFIG_HOME:-$HOME/.local/share}/flatpak/exports/share:$FLATPAK_INSTALLATIONS/exports/share:$XDG_DATA_DIRS" fi +### FreeBSD +export ASSUME_ALWAYS_YES="yes" +export DEFAULT_ALWAYS_YES="yes" + ### fzf if command -v fd > /dev/null; then export FZF_DEFAULT_COMMAND='fd --type f --strip-cwd-prefix --hidden --follow --exclude .git' diff --git a/home/dot_local/bin/executable_installx b/home/dot_local/bin/executable_installx index 2e6ebdf8..ef5f98d6 100644 --- a/home/dot_local/bin/executable_installx +++ b/home/dot_local/bin/executable_installx @@ -1,12 +1,27 @@ #!/usr/bin/env zx import osInfo from 'linux-os-info' +// $.verbose = false + let installOrder, osArch, osId, osType, pkgs, sysType +const cacheDir = os.homedir() + '/.cache/installx' async function getOsInfo() { return osInfo({ mode: 'sync' }) } +async function runSilentCommand(command) { + require('child_process').execSync(`${command}`, { stdio: 'inherit', shell: true }) + } + +async function runScript(key, script) { + fs.writeFileSync(`${cacheDir}/${key}`, script) + const file = await $`cat ${cacheDir}/${key} | grep "^# @file" | sed 's/^# @file //'` + const brief = await $`cat ${cacheDir}/${key} | grep "^# @brief" | sed 's/^# @brief //'` + fs.writeFileSync(`${cacheDir}/${key}-glow`, "# " + file.stdout + "\n> " + brief.stdout + "\n```sh\n" + script + "\n```") + runSilentCommand(`glow "${cacheDir}/${key}-glow" && bash "${cacheDir}/${key}"`) +} + function getPkgData(pref, pkg, installer) { if (installer) { if (pkg[`${pref}:${installer}:${osId}:${osArch}`]) { @@ -79,36 +94,6 @@ async function getSystemType() { } } -async function getBrewFormulas() { - await $`brew list -1 > brew-list` - return fs.readFileSync('./brew-list').toString().split('\n') -} - -async function getGems() { - await $`gem query --local > gem-list` - return fs.readFileSync('./gem-list').toString().split('\n').map(x => x.split(' ')[0]) -} - -async function getVoltaInstalls() { - await $`volta list --format plain > volta-list` - return fs.readFileSync('./volta-list').toString().split('\n').filter(x => x).map(x => x.split(' ')[1].split('@')[0]) -} - -async function getCrates() { - await $`cargo install --list | awk '/^[[:alnum:]]/ {print $1}' > cargo-list` - return fs.readFileSync('./cargo-list').toString().split('\n') -} - -async function getPipxPackages() { - await $`pipx list --short > pipx-list` - return fs.readFileSync('./pipx-list').toString().split('\n').map(x => x.split(' ')[0]) -} - -async function getPips() { - await $`pip3 list > pip-list` - return fs.readFileSync('./pip-list').toString().split('\n').map(x => x.split(' ')[0]) -} - function expandDeps(keys) { for (const i of keys) { for (const pref of installOrder[sysType]) { @@ -130,64 +115,144 @@ function expandDeps(keys) { async function bundleInstall(brews, casks) { const lines = [] for (const cask of casks) { - lines.push(`cask "${cask}"`) + lines.push(`cask "${cask.cask}"`) } for (const brew of brews) { - lines.push(`brew "${brew}"`) + lines.push(`brew "${brew.brew}"`) } fs.writeFileSync('Brewfile', lines.join('\n')) await $`brew bundle --file Brewfile` } +async function forEachSeries(iterable) { + for (const x of iterable) { + await x + } +} + async function installPackages(pkgInstructions) { const combined = {} const promises = [] for (const option of installOrder[sysType]) { - combined[option] = pkgInstructions.filter(x => x.installType === option) + const instructions = pkgInstructions.filter(x => x.installType === option) + if (instructions.length) { + combined[option] = instructions + } } - if (combined.brew || combined.cask) { + if ((combined.brew && combined.brew.length) || (combined.cask && combined.cask.length)) { promises.push(bundleInstall(combined.brew ? combined.brew : [], combined.cask ? combined.cask : [])) } - if (combined.cargo) { - for (const pkg of combined.cargo) { - promises.push($`cargo install ${pkg}`) + for (const key of Object.keys(combined)) { + switch(key) { + case 'ansible': + promises.push(forEachSeries(combined[key].flatMap(x => x.installList.flatMap(i => $`${key} 127.0.0.1 -v${process.env.DEBUG && 'vv'} -e '{ ansible_connection: "local", ansible_become_user: "root", ansible_user: "${process.env.USER}", ansible_family: "${osId.charAt(0).toUpperCase() + osId.slice(1)}", install_homebrew: False }' -m include_role -a name=${i}`)))) + case 'apk': + promises.push($`sudo ${key} add ${combined[key].flatMap(x => x.installList).split(' ')}`) + case 'appimage': + promises.push(...combined[key].flatMap(x => x.installList.flatMap(i => { + if (x.substring(0, 4) === 'http') { + return $`zap install --select-first -q --from ${i}` + } else if ((x.match(/\//g) || []).length === 1) { + return $`zap install --select-first -q --github --from ${i}` + } else { + return $`zap install --select-first -q ${i}` + } + }))) + case 'apt': + promises.push($`DEBIAN_FRONTEND=noninteractive sudo apt-get -o DPkg::Options::=--force-confdef install -y ${combined[key].flatMap(x => x.installList).split(' ')}`) + case 'basher': + case 'baulk': + case 'cargo': + case 'crew': + case 'gem': + case 'go': + case 'npm': + case 'pip': + case 'pipx': + case 'scoop': // Maybe needs forEachSeries + case 'winget': // Maybe needs forEachSeries + promises.push(...combined[key].flatMap(x => x.installList.flatMap(i => $`${key} install ${i}`))) + break; + case 'binary': + // TODO + promises.push(...combined[key].flatMap(x => x.installList.flatMap(i => $`TMP="$(mktemp)" && curl -sSL ${i} > "$TMP" && sudo mv "$TMP" /usr/local/src/${x._bin} && chmod +x /usr/local/src/${x._bin}`))) + case 'brew': + case 'cask': // Handled above + break; + case 'choco': + promises.push($`${key} install -y ${combined[key].flatMap(x => x.installList).split(' ')}`) + case 'dnf': + case 'yum': + case 'zypper': + promises.push($`sudo ${key} install -y ${combined[key].flatMap(x => x.installList).split(' ')}`) + break; + case 'emerge': + case 'pkg_add': + promises.push($`sudo ${key} ${combined[key].flatMap(x => x.installList).split(' ')}`) + break; + case 'eopkg': + case 'pkg-freebsd': + case 'pkg-termux': + case 'pkgin': + case 'port': + case 'snap': // TODO - snap testing.. combine with snap-classic and add appropriate logic + promises.push($`sudo ${key === 'pkg-freebsd' || key === 'pkg-termux' ? 'pkg' : key} install ${combined[key].flatMap(x => x.installList).split(' ')}`) + break; + case 'flatpak': + promises.push(forEachSeries(combined[key].flatMap(x => x.installList.flatMap(i => $`sudo ${key} install -y flathub ${i}`)))) + break; + case 'github': // TODO + break; + case 'nix-env': // TODO + case 'nix-pkg': // TODO + case 'nix-shell': // TODO + break; + case 'pacman': + promises.push($`sudo ${key} -Sy --noconfirm --needed ${combined[key].flatMap(x => x.installList).split(' ')}`) + break; + case 'pkg-darwin': + break; + case 'sbopkg': // TODO + break; + case 'script': + promises.push(...combined[key].flatMap(x => x.installList.map(i => $`${i}`))) + break; + case 'snap-classic': + promises.push($`sudo snap install --classic ${combined[key].flatMap(x => x.installList).split(' ')}`) + break; + case 'whalebrew': // TODO + break; + case 'xbps': + promises.push($`sudo xbps-install -S ${combined[key].flatMap(x => x.installList).split(' ')}`) + break; + case 'yay': + promises.push($`yay -Sy --noconfirm --needed ${combined[key].flatMap(x => x.installList).split(' ')}`) + break; + default: + console.log(`Unable to find install key instructions for ${key}`) } } - if (combined.go) { - for (const pkg of combined.go) { - promises.push($`go install ${pkg}`) - } + await Promise.all(promises) +} + +async function acquireManagerList(type, command) { + if (fs.existsSync(`${cacheDir}/${type}`)) { + setTimeout(() => { + require('child_process').execSync(`${command} > ${cacheDir}/${type}`) + }, 0) + } else { + require('child_process').execSync(`${command} > ${cacheDir}/${type}`) } - if (combined.npm) { - for (const pkg of combined.npm) { - promises.push($`volta install ${pkg}`) - } - } - if (combined.pacman) { - const pacmanPkgs = combined.pacman.map(x => ) - promises.push($`sudo pacman -Sy --noconfirm --needed ${combined.pacman.map}`) - } - if (combined.pipx) { - for (const pkg of combined.pipx) { - promises.push($`pipx install ${pkg}`) - } - } - console.log(combinedInstructions) + return fs.readFileSync(`${cacheDir}/${type}`).toString().split('\n') } async function main() { - cd(await $`mktemp -d`) + await $`mkdir -p ${cacheDir}` const initData = await Promise.all([ getOsInfo(), getSoftwareDefinitions(), - getSystemType(), - getBrewFormulas(), - getGems(), - getVoltaInstalls(), - getCrates(), - getPipxPackages(), - getPips() + getSystemType() ]) osArch = initData[0].arch osId = process.platform === 'win32' ? 'win32' : (process.platform === 'linux' ? initData[0].id : process.platform) @@ -195,17 +260,25 @@ async function main() { pkgs = initData[1].softwarePackages sysType = initData[2] installOrder = initData[1].installerPreference + const lists = [ + acquireManagerList('brew', `brew list -1`), + acquireManagerList('cargo', `cargo install --list | awk '/^[[:alnum:]]/ {print $1}'`), + acquireManagerList('gem', `gem list | awk '{print $1}'`), + acquireManagerList('npm', `volta list --format plain | awk '{print $2}' | sed 's/@.*//'`), + acquireManagerList('pip3', `pip3 list | awk '{print $1}'`), + acquireManagerList('pipx', `pipx list --short | awk '{print $1}'`) + ] const managerLists = { - brew: initData[3], - cargo: initData[6], - gem: initData[4], - npm: initData[5], - pip: initData[8], - pipx: initData[7] + brew: lists[0], + cargo: lists[1], + gem: lists[2], + npm: lists[3], + pip3: lists[4], + pipx: lists[5] } - const installKeys = argv._ - const installInstructions = Object.keys(pkgs) - .filter(i => expandDeps(installKeys).includes(i)) + const installKeys = Object.keys(pkgs) + .filter(i => expandDeps(argv._).includes(i)) + const installData = installKeys .map(i => { for (const pref of installOrder[sysType]) { const installKey = getPkgData(pref, pkgs[i], false) @@ -228,6 +301,7 @@ async function main() { } }) .filter(x => x.installKey) + const installInstructions = installData .filter(x => { // Filter out packages already installed by by package managers return Object.keys(managerLists).includes(x.installType) @@ -255,8 +329,12 @@ async function main() { return whenField ? whenCheck : true }) await installPackages(installInstructions) - //.filter(x => x.installKey) - console.log('install instructions', installInstructions) + const postScripts = installData + .flatMap(x => { + const postField = getPkgData('_post', x, x.installType) + return (postField && runScript(x.listKey, x[postField])) || Promise.resolve() + }) + await Promise.all(postScripts) } main() diff --git a/software.yml b/software.yml index 2359d783..1ca2c6b7 100644 --- a/software.yml +++ b/software.yml @@ -3224,7 +3224,7 @@ softwarePackages: if command -v termux-setup-storage > /dev/null; then apt install termux-api fi - pip: ntfy[emoji,matrix,pid,slack] + pip3: ntfy[emoji,matrix,pid,slack] makeself: _bin: makeself _github: https://github.com/megastep/makeself @@ -3539,7 +3539,7 @@ softwarePackages: nix-env: nixpkgs.clipboard-jh scoop: clipboard snap: clipboard - xbps-install: clipboard + xbps: clipboard yay: clipboard editly: _bin: editly @@ -3653,7 +3653,7 @@ softwarePackages: _name: Polybar apt: polybar pacman: polybar - xbps-install: polybar + xbps: polybar zypper: polybar pkg-freebsd: polybar dnf: polybar @@ -3666,7 +3666,7 @@ softwarePackages: emerge: app-shells/hstr apk: hstr pkg-freebsd: hstr - xbps-install: hstr + xbps: hstr brew: hstr port: histr nix-env: hstr @@ -4862,7 +4862,7 @@ softwarePackages: pacman: fzf pkgin: fzf pkg-freebsd: fzf - pkg-openbsd: fzf + pkg_add: fzf port: fzf xbps: fzf zypper: fzf @@ -5178,7 +5178,7 @@ softwarePackages: pacman: zola pkgin: zola pkg-freebsd: zola - pkg-openbsd: zola + pkg_add: zola port: zola scoop: zola snap: zola @@ -6953,7 +6953,7 @@ softwarePackages: pkg-termux: lsd port: lsd scoop: lsd - xbps-install: lsd + xbps: lsd zypper: lsd lxc: _bin: lxc @@ -8706,7 +8706,7 @@ softwarePackages: brew: neofetch nix-env: neofetch eopkg: neofetch - xbps-install: neofetch + xbps: neofetch zypper: neofetch scoop: neofetch neovide: @@ -9981,7 +9981,7 @@ softwarePackages: nix: restic pacman: restic pkg-freebsd: restic - pkg-openbsd: restic + pkg_add: restic port: restic scoop: restic zypper: restic @@ -10649,7 +10649,7 @@ softwarePackages: nix: nixpkgs.shellcheck pacman: shellcheck pkg-freebsd: shellcheck - pkg-openbsd: shellcheck + pkg_add: shellcheck port: shellcheck scoop: shellcheck snap: shellcheck @@ -11414,7 +11414,7 @@ softwarePackages: pacman: just nix-env: nixpkgs.just eopkg: just - xbps-install: just + xbps: just pkg-freebsd: just apk: just dnf: just @@ -11658,7 +11658,7 @@ softwarePackages: pacman: vhs port: vhs scoop: vhs - xbps-install: vhs + xbps: vhs soft-serve: _bin: soft _desc: A tasty, self-hostable Git server for the command line @@ -13724,7 +13724,7 @@ softwarePackages: pkg_add: pick port: pick yay: pick - xbps-install: pick + xbps: pick nve: _bin: nve _github: https://github.com/ehmicky/nve @@ -13905,7 +13905,7 @@ softwarePackages: port: task emerge: task pacman: task - xbps-install: task + xbps: task zypper: taskwarrior boringtun: _bin: boringtun-cli @@ -14254,7 +14254,7 @@ softwarePackages: nix: yank pacman: yank pkg-freebsd: yank - pkg-openbsd: yank + pkg_add: yank port: yank scoop: win32yank zypper: yank