From e8167f13b7e51be0577e6b338e571add0a5faed3 Mon Sep 17 00:00:00 2001 From: Brian Zalewski <59970525+ProfessorManhattan@users.noreply.github.com> Date: Mon, 27 May 2024 11:15:03 +0000 Subject: [PATCH] Many changes --- .../taskfiles/security/Taskfile-yubikey.yml | 2 +- .../universal/run_after_10-install.sh.tmpl | 48 +- .../run_after_20-post-install.sh.tmpl | 6 +- .../executable_post-gitlab-runner.sh | 0 .../disabled}/executable_post-vscodium.sh | 0 home/Cloud/symlink_User.tmpl | 2 +- home/dot_config/hammerspoon/init.lua | 2 + home/dot_config/shell/exports.sh.tmpl | 2 +- home/dot_config/shell/macos.sh.tmpl | 3 + home/dot_config/shell/p10k.zsh | 105 +- home/dot_config/shell/profile.sh.tmpl | 2 +- home/dot_local/bin/executable_add-usergroup | 2 + .../bin/executable_compress-image.tmpl | 2 +- home/dot_local/bin/executable_get-secret | 70 + .../bin/executable_install-program-edit | 1882 ----------------- home/dot_local/bin/executable_installx | 15 +- home/dot_local/bin/executable_update-system | 2 + .../bin/post-installx/executable_post-aqua.sh | 14 - .../post-installx/executable_post-atuin.sh | 8 +- .../post-installx/executable_post-blocky.sh | 2 + .../post-installx/executable_post-clamav.sh | 8 +- .../executable_post-cloudflared.sh | 2 + .../executable_post-docker-desktop.sh | 19 +- .../executable_post-easyengine.sh | 13 +- .../post-installx/executable_post-endlessh.sh | 4 + .../post-installx/executable_post-envchain.sh | 16 +- .../post-installx/executable_post-fail2ban.sh | 2 + .../bin/post-installx/executable_post-fig.sh | 9 +- .../post-installx/executable_post-firefox.sh | 6 +- .../executable_post-github-runner.sh | 9 +- .../executable_post-gitomatic.sh | 2 + .../executable_post-google-chrome.sh | 6 +- .../post-installx/executable_post-juicefs.sh | 2 + .../post-installx/executable_post-keybase.sh | 2 + .../bin/post-installx/executable_post-mise.sh | 2 + .../post-installx/executable_post-netdata.sh | 7 +- .../post-installx/executable_post-nginx.sh | 31 +- .../bin/post-installx/executable_post-ntfy.sh | 2 + .../post-installx/executable_post-plymouth.sh | 26 +- .../post-installx/executable_post-postfix.sh | 17 +- .../post-installx/executable_post-privoxy.sh | 2 + .../post-installx/executable_post-rclone.sh | 195 +- .../post-installx/executable_post-rkhunter.sh | 2 + .../post-installx/executable_post-samba.sh | 58 +- .../post-installx/executable_post-sftpgo.sh | 7 + .../post-installx/executable_post-tabby.sh | 2 + .../executable_post-tailscale.sh | 32 +- .../post-installx/executable_post-tfenv.sh | 10 - .../executable_post-timeshift.sh | 2 + .../bin/post-installx/executable_post-tor.sh | 4 +- .../bin/post-installx/executable_post-vim.sh | 2 + .../executable_post-virtualbox.sh | 2 + .../post-installx/executable_post-vmware.sh | 14 +- .../post-installx/executable_post-volta.sh | 8 + .../post-installx/executable_post-vscode.sh | 2 + .../bin/post-installx/executable_post-warp.sh | 6 +- .../post-installx/executable_post-wazuh.sh | 7 +- .../executable_post-wireguard-tools.sh | 3 +- software.yml | 321 +-- 59 files changed, 614 insertions(+), 2419 deletions(-) rename home/{dot_local/bin/post-installx => .chezmoiscripts_disabled/disabled}/executable_post-gitlab-runner.sh (100%) rename home/{dot_local/bin/post-installx => .chezmoiscripts_disabled/disabled}/executable_post-vscodium.sh (100%) create mode 100644 home/dot_config/hammerspoon/init.lua create mode 100644 home/dot_local/bin/executable_get-secret delete mode 100644 home/dot_local/bin/executable_install-program-edit delete mode 100644 home/dot_local/bin/post-installx/executable_post-aqua.sh delete mode 100644 home/dot_local/bin/post-installx/executable_post-tfenv.sh diff --git a/.config/taskfiles/security/Taskfile-yubikey.yml b/.config/taskfiles/security/Taskfile-yubikey.yml index 8483130d..3964a576 100644 --- a/.config/taskfiles/security/Taskfile-yubikey.yml +++ b/.config/taskfiles/security/Taskfile-yubikey.yml @@ -319,5 +319,5 @@ tasks: A new method is detailed here: https://www.yubico.com/blog/github-now-supports-ssh-security-keys/ It may be worth migrating to that approach. cmds: - - brew services start yubikey-agent + - brew services restart yubikey-agent - yubikey-agent -setup diff --git a/home/.chezmoiscripts/universal/run_after_10-install.sh.tmpl b/home/.chezmoiscripts/universal/run_after_10-install.sh.tmpl index 8caa66b7..f11b42cc 100644 --- a/home/.chezmoiscripts/universal/run_after_10-install.sh.tmpl +++ b/home/.chezmoiscripts/universal/run_after_10-install.sh.tmpl @@ -7,58 +7,18 @@ {{ includeTemplate "universal/profile" }} {{ includeTemplate "universal/logg" }} -{{- $softwareGroup := nospace (cat "_" .host.softwareGroup) }} -{{- $softwareList := list (index .softwareGroups $softwareGroup | toString | replace "[" "" | replace "]" "") | uniq | join " " }} - -if command -v install-program > /dev/null; then +if command -v installx > /dev/null; then if command -v zx > /dev/null; then - logg info 'Installing packages defined in .chezmoidata.yaml under the .softwareGroups key' - logg info 'Installing: {{ $softwareList }}' - # Ask for the administrator password upfront - logg info 'A sudo password may be required for some of the installations' - sudo echo "Sudo access granted." - export DEBIAN_FRONTEND=noninteractive - export HOMEBREW_NO_ENV_HINTS=true - export HOMEBREW_NO_ANALYTICS=1 - if ! command -v gcc-11; then - if command -v gcc; then - logg info 'gcc-11 command missing. Symlinking to gcc' - sudo ln -s "$(which gcc)" /usr/local/bin/gcc-11 - else - logg warn 'gcc either needs to be added to the PATH or it is missing' - fi - fi - if [ -f "$HOME/.bashrc" ]; then - . "$HOME/.bashrc" - else - logg warn 'No ~/.bashrc file to import before running install-program' - fi - export LC_ALL="en_US.UTF-8" - logg info 'Printing environment variables for GO' - env | grep GO - logg info 'Printing environment variables for Java' - env | grep JAVA - env | grep SDKMAN - if ! command -v unbuffer > /dev/null; then - if command -v brew > /dev/null; then - logg info 'Ensuring expect is installed for the unbuffer command' && brew install --quiet expect - fi - fi if command -v unbuffer > /dev/null; then - # install-program was refactored into installx - # logg info 'Running unbuffer install-program' - # unbuffer install-program {{ $softwareList }} logg info 'Running unbuffer installx' - unbuffer installx {{ $softwareList }} + unbuffer installx --all else - logg info 'Running install-program without unbuffer' - install-program {{ $softwareList }} logg info 'Running installx' - installx {{ $softwareList }} + installx --all fi else logg error 'zx is not available' fi else - logg error 'install-program is not in the PATH. It should be located in ~/.local/bin.' + logg error 'installx is not in the PATH. It should be located in ~/.local/bin.' fi diff --git a/home/.chezmoiscripts/universal/run_after_20-post-install.sh.tmpl b/home/.chezmoiscripts/universal/run_after_20-post-install.sh.tmpl index 5b54843e..f7e58255 100644 --- a/home/.chezmoiscripts/universal/run_after_20-post-install.sh.tmpl +++ b/home/.chezmoiscripts/universal/run_after_20-post-install.sh.tmpl @@ -15,7 +15,7 @@ bashItPlugins() { ### Ensure Powerline is installed if ! command -v powerline > /dev/null; then logg info 'Installing powerline via install-program' - install-program powerline > /dev/null + installx powerline fi ### Include Bash It @@ -380,7 +380,7 @@ enableAutoUpdateDarwin() { logg info 'Loading /Library/LaunchDaemons/com.apple.automatedupdates.plist' if sudo launchctl list | grep 'com.apple.automatedupdates' > /dev/null; then logg info 'Unloading previous com.apple.automatedupdates configuration' - sudo launchctl unload /Library/LaunchDaemons/clamdscan.plist + sudo launchctl unload /Library/LaunchDaemons/com.apple.automatedupdates.plist fi sudo launchctl load -w /Library/LaunchDaemons/com.apple.automatedupdates.plist else @@ -395,6 +395,8 @@ enableAutoUpdateDarwin() { fi } +# Temporary next line for debugging +export DEBUG=true if [ -n "$DEBUG" ] || [ -n "$DEBUG_MODE" ]; then logg info 'The DEBUG or DEBUG_MODE environment variable is set so the post-install tasks will be run synchronously' bashItPlugins diff --git a/home/dot_local/bin/post-installx/executable_post-gitlab-runner.sh b/home/.chezmoiscripts_disabled/disabled/executable_post-gitlab-runner.sh similarity index 100% rename from home/dot_local/bin/post-installx/executable_post-gitlab-runner.sh rename to home/.chezmoiscripts_disabled/disabled/executable_post-gitlab-runner.sh diff --git a/home/dot_local/bin/post-installx/executable_post-vscodium.sh b/home/.chezmoiscripts_disabled/disabled/executable_post-vscodium.sh similarity index 100% rename from home/dot_local/bin/post-installx/executable_post-vscodium.sh rename to home/.chezmoiscripts_disabled/disabled/executable_post-vscodium.sh diff --git a/home/Cloud/symlink_User.tmpl b/home/Cloud/symlink_User.tmpl index 84ddec22..2a50e192 100644 --- a/home/Cloud/symlink_User.tmpl +++ b/home/Cloud/symlink_User.tmpl @@ -1,3 +1,3 @@ {{- if and (or (and (stat (joinPath .host.home ".config" "age" "chezmoi.txt")) (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "CLOUDFLARE_R2_ID"))) (env "CLOUDFLARE_R2_ID")) (or (and (stat (joinPath .host.home ".config" "age" "chezmoi.txt")) (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "CLOUDFLARE_R2_SECRET"))) (env "CLOUDFLARE_R2_SECRET")) (ne .user.cloudflare.r2 "") -}} -{{ .host.home }}/.local/mnt/s3 +/{{- if eq .host.distro.id "darwin" -}}Volumes{{- else -}}mnt{{- end -}}/User {{- end -}} \ No newline at end of file diff --git a/home/dot_config/hammerspoon/init.lua b/home/dot_config/hammerspoon/init.lua new file mode 100644 index 00000000..6f70c27d --- /dev/null +++ b/home/dot_config/hammerspoon/init.lua @@ -0,0 +1,2 @@ +-- Defeat copy / paste blockers (Source: https://www.hammerspoon.org/go/) +hs.hotkey.bind({"cmd", "alt"}, "V", function() hs.eventtap.keyStrokes(hs.pasteboard.getContents()) end) diff --git a/home/dot_config/shell/exports.sh.tmpl b/home/dot_config/shell/exports.sh.tmpl index 0662de75..1ecbd757 100644 --- a/home/dot_config/shell/exports.sh.tmpl +++ b/home/dot_config/shell/exports.sh.tmpl @@ -6,7 +6,7 @@ # the default Install Doctor configurations. ### Language / Fonts -export LANG="en_US" +export LANG="en_US.UTF-8" export LC_ALL="en_US.UTF-8" ### Licensing diff --git a/home/dot_config/shell/macos.sh.tmpl b/home/dot_config/shell/macos.sh.tmpl index f091b685..d9156c40 100644 --- a/home/dot_config/shell/macos.sh.tmpl +++ b/home/dot_config/shell/macos.sh.tmpl @@ -29,6 +29,9 @@ osascript -e "tell application \"Terminal\" to set the font name of window 1 to osascript -e "tell application \"Terminal\" to set the font size of window 1 to 12" # TODO - Add anti-aliasing +# Hammerspoon +defaults write org.hammerspoon.Hammerspoon MJConfigFile "~/.config/hammerspoon/init.lua" + # Keep-alive: update existing `sudo` time stamp until `.macos` has finished while true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null & diff --git a/home/dot_config/shell/p10k.zsh b/home/dot_config/shell/p10k.zsh index c2f6798a..2a0272f2 100644 --- a/home/dot_config/shell/p10k.zsh +++ b/home/dot_config/shell/p10k.zsh @@ -1,8 +1,8 @@ -# Generated by Powerlevel10k configuration wizard on 2023-08-04 at 00:33 EDT. -# Based on romkatv/powerlevel10k/config/p10k-classic.zsh. -# Wizard options: nerdfont-complete + powerline, large icons, classic, unicode, darkest, -# 24h time, vertical separators, sharp heads, flat tails, 1 line, compact, many icons, -# concise, transient_prompt, instant_prompt=quiet. +# Generated by Powerlevel10k configuration wizard on 2024-05-27 at 07:04 EDT. +# Based on romkatv/powerlevel10k/config/p10k-classic.zsh, checksum 2750. +# Wizard options: nerdfont-v3 + powerline, large icons, classic, unicode, darkest, +# 24h time, vertical separators, flat heads, flat tails, 1 line, compact, many icons, +# concise, instant_prompt=quiet. # Type `p10k configure` to generate another config. # # Config for Powerlevel10k with classic powerline prompt style. Type `p10k configure` to generate @@ -84,6 +84,7 @@ context # user@hostname # nordvpn # nordvpn connection status, linux only (https://nordvpn.com/) # ranger # ranger shell (https://github.com/ranger/ranger) + # yazi # yazi shell (https://github.com/sxyazi/yazi) nnn # nnn shell (https://github.com/jarun/nnn) # lf # lf shell (https://github.com/gokcehan/lf) # xplr # xplr shell (https://github.com/sayanarijit/xplr) @@ -100,6 +101,7 @@ # todo # todo items (https://github.com/todotxt/todo.txt-cli) timewarrior # timewarrior tracking status (https://timewarrior.net/) taskwarrior # taskwarrior task count (https://taskwarrior.org/) + per_directory_history # Oh My Zsh per-directory-history local/global indicator # cpu_arch # CPU architecture time # current time # ip # ip address and bandwidth usage for a specified network interface @@ -111,7 +113,7 @@ ) # Defines character set used by powerlevel10k. It's best to let `p10k configure` set it for you. - typeset -g POWERLEVEL9K_MODE=nerdfont-complete + typeset -g POWERLEVEL9K_MODE=nerdfont-v3 # When set to `moderate`, some icons will have an extra space after them. This is meant to avoid # icon overlap when using non-monospace fonts. When set to `none`, spaces are not added. typeset -g POWERLEVEL9K_ICON_PADDING=moderate @@ -174,9 +176,9 @@ # For example: POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(os_icon context_joined) # The right end of left prompt. - typeset -g POWERLEVEL9K_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL='\uE0B0' + typeset -g POWERLEVEL9K_LEFT_PROMPT_LAST_SEGMENT_END_SYMBOL='' # The left end of right prompt. - typeset -g POWERLEVEL9K_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL='\uE0B2' + typeset -g POWERLEVEL9K_RIGHT_PROMPT_FIRST_SEGMENT_START_SYMBOL='' # The left end of left prompt. typeset -g POWERLEVEL9K_LEFT_PROMPT_FIRST_SEGMENT_START_SYMBOL='' # The right end of right prompt. @@ -242,7 +244,7 @@ .java-version .perl-version .php-version - .tool-version + .tool-versions .shorten_folder_marker .svn .terraform @@ -428,11 +430,17 @@ res+=" ${modified}wip" fi - # ⇣42 if behind the remote. - (( VCS_STATUS_COMMITS_BEHIND )) && res+=" ${clean}⇣${VCS_STATUS_COMMITS_BEHIND}" - # ⇡42 if ahead of the remote; no leading space if also behind the remote: ⇣42⇡42. - (( VCS_STATUS_COMMITS_AHEAD && !VCS_STATUS_COMMITS_BEHIND )) && res+=" " - (( VCS_STATUS_COMMITS_AHEAD )) && res+="${clean}⇡${VCS_STATUS_COMMITS_AHEAD}" + if (( VCS_STATUS_COMMITS_AHEAD || VCS_STATUS_COMMITS_BEHIND )); then + # ⇣42 if behind the remote. + (( VCS_STATUS_COMMITS_BEHIND )) && res+=" ${clean}⇣${VCS_STATUS_COMMITS_BEHIND}" + # ⇡42 if ahead of the remote; no leading space if also behind the remote: ⇣42⇡42. + (( VCS_STATUS_COMMITS_AHEAD && !VCS_STATUS_COMMITS_BEHIND )) && res+=" " + (( VCS_STATUS_COMMITS_AHEAD )) && res+="${clean}⇡${VCS_STATUS_COMMITS_AHEAD}" + elif [[ -n $VCS_STATUS_REMOTE_BRANCH ]]; then + # Tip: Uncomment the next line to display '=' if up to date with the remote. + # res+=" ${clean}=" + fi + # ⇠42 if behind the push remote. (( VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" ${clean}⇠${VCS_STATUS_PUSH_COMMITS_BEHIND}" (( VCS_STATUS_PUSH_COMMITS_AHEAD && !VCS_STATUS_PUSH_COMMITS_BEHIND )) && res+=" " @@ -571,7 +579,7 @@ ###############[ asdf: asdf version manager (https://github.com/asdf-vm/asdf) ]############### # Default asdf color. Only used to display tools for which there is no color override (see below). # Tip: Override this parameter for ${TOOL} with POWERLEVEL9K_ASDF_${TOOL}_FOREGROUND. - # typeset -g POWERLEVEL9K_ASDF_FOREGROUND=66 + typeset -g POWERLEVEL9K_ASDF_FOREGROUND=66 # There are four parameters that can be used to hide asdf tools. Each parameter describes # conditions under which a tool gets hidden. Parameters can hide tools but not unhide them. If at @@ -722,6 +730,12 @@ typeset -g POWERLEVEL9K_RANGER_FOREGROUND=178 # Custom icon. # typeset -g POWERLEVEL9K_RANGER_VISUAL_IDENTIFIER_EXPANSION='⭐' + + ####################[ yazi: yazi shell (https://github.com/sxyazi/yazi) ]##################### + # Yazi shell color. + typeset -g POWERLEVEL9K_YAZI_FOREGROUND=178 + # Custom icon. + # typeset -g POWERLEVEL9K_YAZI_VISUAL_IDENTIFIER_EXPANSION='⭐' ######################[ nnn: nnn shell (https://github.com/jarun/nnn) ]####################### # Nnn shell color. @@ -798,9 +812,8 @@ # Text and color for insert vi mode. typeset -g POWERLEVEL9K_VI_INSERT_MODE_STRING= typeset -g POWERLEVEL9K_VI_MODE_INSERT_FOREGROUND=66 - # Custom icon. - # typeset -g POWERLEVEL9K_RANGER_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_VI_MODE_VISUAL_IDENTIFIER_EXPANSION='⭐' ######################################[ ram: free RAM ]####################################### # RAM color. @@ -882,6 +895,19 @@ # Custom icon. # typeset -g POWERLEVEL9K_TASKWARRIOR_VISUAL_IDENTIFIER_EXPANSION='⭐' + ######[ per_directory_history: Oh My Zsh per-directory-history local/global indicator ]####### + # Color when using local/global history. + typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_LOCAL_FOREGROUND=135 + typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_GLOBAL_FOREGROUND=130 + + # Tip: Uncomment the next two lines to hide "local"/"global" text and leave just the icon. + # typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_LOCAL_CONTENT_EXPANSION='' + # typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_GLOBAL_CONTENT_EXPANSION='' + + # Custom icon. + # typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_LOCAL_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_PER_DIRECTORY_HISTORY_GLOBAL_VISUAL_IDENTIFIER_EXPANSION='⭐' + ################################[ cpu_arch: CPU architecture ]################################ # CPU architecture color. typeset -g POWERLEVEL9K_CPU_ARCH_FOREGROUND=172 @@ -1351,7 +1377,7 @@ #[ aws: aws profile (https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) ]# # Show aws only when the command you are typing invokes one of these tools. # Tip: Remove the next line to always show aws. - typeset -g POWERLEVEL9K_AWS_SHOW_ON_COMMAND='aws|awless|terraform|pulumi|terragrunt' + typeset -g POWERLEVEL9K_AWS_SHOW_ON_COMMAND='aws|awless|cdk|terraform|pulumi|terragrunt' # POWERLEVEL9K_AWS_CLASSES is an array with even number of elements. The first element # in each pair defines a pattern against which the current AWS profile gets matched. @@ -1399,10 +1425,39 @@ # Show azure only when the command you are typing invokes one of these tools. # Tip: Remove the next line to always show azure. typeset -g POWERLEVEL9K_AZURE_SHOW_ON_COMMAND='az|terraform|pulumi|terragrunt' + + # POWERLEVEL9K_AZURE_CLASSES is an array with even number of elements. The first element + # in each pair defines a pattern against which the current azure account name gets matched. + # More specifically, it's P9K_CONTENT prior to the application of context expansion (see below) + # that gets matched. If you unset all POWERLEVEL9K_AZURE_*CONTENT_EXPANSION parameters, + # you'll see this value in your prompt. The second element of each pair in + # POWERLEVEL9K_AZURE_CLASSES defines the account class. Patterns are tried in order. The + # first match wins. + # + # For example, given these settings: + # + # typeset -g POWERLEVEL9K_AZURE_CLASSES=( + # '*prod*' PROD + # '*test*' TEST + # '*' OTHER) + # + # If your current azure account is "company_test", its class is TEST because "company_test" + # doesn't match the pattern '*prod*' but does match '*test*'. + # + # You can define different colors, icons and content expansions for different classes: + # + # typeset -g POWERLEVEL9K_AZURE_TEST_FOREGROUND=28 + # typeset -g POWERLEVEL9K_AZURE_TEST_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_AZURE_TEST_CONTENT_EXPANSION='> ${P9K_CONTENT} <' + typeset -g POWERLEVEL9K_AZURE_CLASSES=( + # '*prod*' PROD # These values are examples that are unlikely + # '*test*' TEST # to match your needs. Customize them as needed. + '*' OTHER) + # Azure account name color. - typeset -g POWERLEVEL9K_AZURE_FOREGROUND=32 + typeset -g POWERLEVEL9K_AZURE_OTHER_FOREGROUND=32 # Custom icon. - # typeset -g POWERLEVEL9K_AZURE_VISUAL_IDENTIFIER_EXPANSION='⭐' + # typeset -g POWERLEVEL9K_AZURE_OTHER_VISUAL_IDENTIFIER_EXPANSION='⭐' ##########[ gcloud: google cloud account and project (https://cloud.google.com/) ]########### # Show gcloud only when the command you are typing invokes one of these tools. @@ -1568,7 +1623,7 @@ # Show battery in yellow when it's discharging. typeset -g POWERLEVEL9K_BATTERY_DISCONNECTED_FOREGROUND=178 # Battery pictograms going from low to high level of charge. - typeset -g POWERLEVEL9K_BATTERY_STAGES='\uf58d\uf579\uf57a\uf57b\uf57c\uf57d\uf57e\uf57f\uf580\uf581\uf578' + typeset -g POWERLEVEL9K_BATTERY_STAGES='\UF008E\UF007A\UF007B\UF007C\UF007D\UF007E\UF007F\UF0080\UF0081\UF0082\UF0079' # Don't show the remaining time to charge/discharge. typeset -g POWERLEVEL9K_BATTERY_VERBOSE=false @@ -1623,7 +1678,7 @@ # User-defined prompt segments may optionally provide an instant_prompt_* function. Its job # is to generate the prompt segment for display in instant prompt. See - # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # https://github.com/romkatv/powerlevel10k#instant-prompt. # # Powerlevel10k will call instant_prompt_* at the same time as the regular prompt_* function # and will record all `p10k segment` calls it makes. When displaying instant prompt, Powerlevel10k @@ -1651,7 +1706,7 @@ # - always: Trim down prompt when accepting a command line. # - same-dir: Trim down prompt when accepting a command line unless this is the first command # typed after changing current working directory. - typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=always + typeset -g POWERLEVEL9K_TRANSIENT_PROMPT=off # Instant prompt mode. # @@ -1659,7 +1714,7 @@ # it incompatible with your zsh configuration files. # - quiet: Enable instant prompt and don't print warnings when detecting console output # during zsh initialization. Choose this if you've read and understood - # https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt. + # https://github.com/romkatv/powerlevel10k#instant-prompt. # - verbose: Enable instant prompt and print a warning when detecting console output during # zsh initialization. Choose this if you've never tried instant prompt, haven't # seen the warning, or if you are unsure what this all means. @@ -1680,4 +1735,4 @@ typeset -g POWERLEVEL9K_CONFIG_FILE=${${(%):-%x}:a} (( ${#p10k_config_opts} )) && setopt ${p10k_config_opts[@]} -'builtin' 'unset' 'p10k_config_opts' \ No newline at end of file +'builtin' 'unset' 'p10k_config_opts' diff --git a/home/dot_config/shell/profile.sh.tmpl b/home/dot_config/shell/profile.sh.tmpl index b91b73af..dfc6a509 100644 --- a/home/dot_config/shell/profile.sh.tmpl +++ b/home/dot_config/shell/profile.sh.tmpl @@ -71,7 +71,7 @@ if [ "$BASH_SUPPORT" = 'true' ]; then else if [ -d /Applications ] && [ -d /Library ] && [ -d /System ]; then # macOS - OS_ICON="" + OS_ICON="" else OS_ICON="" fi diff --git a/home/dot_local/bin/executable_add-usergroup b/home/dot_local/bin/executable_add-usergroup index 9d2938d5..126b58a9 100644 --- a/home/dot_local/bin/executable_add-usergroup +++ b/home/dot_local/bin/executable_add-usergroup @@ -7,6 +7,8 @@ # there is already a user / group with the name present on the system before running # any code. +set -euo pipefail + ### Check if the script is being run as root if [[ $EUID -ne 0 ]]; then logg error "This script must be run as root" diff --git a/home/dot_local/bin/executable_compress-image.tmpl b/home/dot_local/bin/executable_compress-image.tmpl index e024dd23..95ee9bee 100644 --- a/home/dot_local/bin/executable_compress-image.tmpl +++ b/home/dot_local/bin/executable_compress-image.tmpl @@ -1,3 +1,3 @@ #!/usr/bin/env bash -tinypng -k {{ .user.tinypngKey }} "$*" \ No newline at end of file +tinypng -k {{ .user.tinypngKey }} $* \ No newline at end of file diff --git a/home/dot_local/bin/executable_get-secret b/home/dot_local/bin/executable_get-secret new file mode 100644 index 00000000..a3fab4a2 --- /dev/null +++ b/home/dot_local/bin/executable_get-secret @@ -0,0 +1,70 @@ +#!/usr/bin/env zx +// @file Get Secret +// @brief This helper utility allows you to return decrypted secrets or check the file system / environment variables to ensure the secrets are available + +const customArgv = minimist(process.argv.slice(3), { + boolean: [ + 'exists' + ], + alias: { + e: 'exists', + } +}) + +const secretDir = `${os.homedir()}/.local/share/chezmoi/home/.chezmoitemplates/secrets` + +if (customArgv.exists && !customArgv._.length) { + console.error('Must pass one or more secrets to check for when using --exists', customArgv) + process.exit(1) +} else if (!customArgv.exists && (!customArgv._.length || customArgv._.length > 1)) { + console.log('Must pass exactly one argument.', customArgv) + process.exit(1) +} else { + if (customArgv.exists) { + ensureAllChezmoiSecrets(customArgv._) + } else { + const secretName = customArgv._[0] + if (process.env[secretName]) { + console.log(process.env[secretName]) + process.exit(0) + } + + // Check for presence of secret in appropriate Chezmoi directory + const secretPath = `${secretDir}/${secretName}` + const fileExists = fs.existsSync(`${secretPath}`) + if (fileExists) { + getChezmoiSecret(secretPath) + } else { + console.error(`The file ${os.homedir()}/.local/share/chezmoi/home/.chezmoitemplates/secrets/${secretName} does not exist!`) + process.exit(1) + } + } +} + +async function getChezmoiSecret(secretPath) { + try { + const decryptedSecret = await $`cat "${secretPath}" | chezmoi decrypt` + console.log(decryptedSecret.stdout) + process.exit(0) + } catch (e) { + console.error(`Error decrypting ${secretPath}`, e) + process.exit(1) + } +} + +async function ensureAllChezmoiSecrets(secretNames) { + try { + const promises = [] + for (let secretName of secretNames) { + if (!process.env[secretName]) { + promises.push(fs.promises.stat(`${secretDir}/${secretName}`)) + } + } + await Promise.all(promises) + process.exit(0) + } catch (e) { + console.error(`One or more of the secret names are not available as environment variables or in ${secretDir}`) + console.log(`Secrets that were checked:`, customArgv._) + process.exit(1) + } +} diff --git a/home/dot_local/bin/executable_install-program-edit b/home/dot_local/bin/executable_install-program-edit deleted file mode 100644 index 7104458b..00000000 --- a/home/dot_local/bin/executable_install-program-edit +++ /dev/null @@ -1,1882 +0,0 @@ -#!/usr/bin/env zx - -const execSync = require('child_process').execSync - -// Log symbols -const figuresDefault = { - bullet: '●', - circle: '◯', - cross: '✖', - lozenge: '◆', - play: '▶', - pointer: '❯', - square: '◼', - star: '★', - tick: '✔' -} - -const figuresFallback = { - bullet: '■', - circle: '□', - cross: '×', - lozenge: '♦', - play: '►', - pointer: '>', - square: '■', - star: '✶', - tick: '√' -} - -function isUnicodeSupported() { - if (process.platform !== 'win32') { - // Linux console (kernel) - return process.env.TERM !== 'linux' - } - - return ( - Boolean(process.env.CI) || - // Windows Terminal - Boolean(process.env.WT_SESSION) || - // ConEmu and cmder - process.env.ConEmuTask === '{cmd::Cmder}' || - process.env.TERM_PROGRAM === 'vscode' || - process.env.TERM === 'xterm-256color' || - process.env.TERM === 'alacritty' - ) -} - -const figures = isUnicodeSupported() ? figuresDefault : figuresFallback - -function log(type, label, msg) { - let icon, message - let fittedLabel = label - while(fittedLabel.length < 14) { - fittedLabel = fittedLabel.length % 2 === 1 ? fittedLabel + ' ' : ' ' + fittedLabel - } - if (type === 'info') { - icon = `${chalk.cyanBright(figures.pointer)} ${chalk.bold.white.bgCyan(' ' + fittedLabel + ' ')}` - message = wrapMessage(msg) - } else if (type === 'star') { - icon = `${chalk.yellow(figures.star)} ${chalk.bold.black.bgYellow(' ' + fittedLabel + ' ')}` - message = wrapMessage(msg) - } else if (type === 'success') { - icon = `${chalk.greenBright(figures.play)} ${chalk.bold.white.bgGreenBright(' ' + fittedLabel + ' ')}` - message = wrapMessage(msg) - } else if (type === 'warn') { - icon = `${chalk.yellowBright(figures.lozenge)} ${chalk.bold.black.bgYellowBright(' WARNING ')}` - message = chalk.yellowBright(wrapMessage(msg)) - } else if (type === 'error') { - icon = `${chalk.redBright(figures.cross)} ${chalk.black.bold.bgRedBright(' ERROR ')}` - message = chalk.redBright(wrapMessage(msg)) - } - const now = new Date() - const outputMessage = `${icon} ${message} (${now})` - console.log(outputMessage) -} - -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) - 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]) + ' ' - } else { - return msg - } -} - -function runCommand(spinnerTitle, command) { - // execSync(command.includes('sudo') ? `sudo "$(which gum)" spin --spinner dot --title "${spinnerTitle}" -- ${command}` : `gum spin --spinner dot --title "${spinnerTitle}" -- ${command}`, { - log('info', 'CMD', spinnerTitle) - console.log(command) - execSync(command, { - stdio: 'inherit', - shell: true, - // Timeout of 140m - timeout: 1000 * 60 * 140 - }) -} - -async function runSilentCommand(command) { - execSync(`${command}`, { stdio: 'inherit', shell: true }) -} - -function fileExists(pathToFile) { - return fs.existsSync(pathToFile) -} - -function dirExists(pathToDir) { - return fs.existsSync(pathToDir) -} - -let installData -let installOrders = {} -let installMeta = {} -let binLinkRan = false -let chezmoiData = [] -let installOrdersPre = [] -let installOrdersPost = [] -let installOrdersService = [] -let installOrdersGroups = [] -let installOrdersPorts = [] -let installOrdersPlugins = [] -let installOrdersBinLink = [] -let brewUpdated, osType, osID, snapRefreshed - -// Register the OS platform type -const osPlatformData = os.platform() -const osPlatform = osPlatformData === 'win32' ? 'windows' : osPlatformData - -// Download the installation map -async function downloadInstallData() { - const response = await fetch('https://github.com/megabyte-labs/install.doctor/raw/master/software.yml') - if (response.ok) { - log('info', 'Catalog Download', `Received ok response from download`) - const text = await response.text() - log('info', 'Catalog Download', `Parsing software.yml`) - return YAML.parse(text, { maxAliasCount: -1 }) - } else { - 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() - log('info', 'Catalog Download', `Parsing local software.yml file`) - return YAML.parse(text, { maxAliasCount: -1 }) - } -} - -// Download the installation map -async function getChezmoiData() { - const text = fs.readFileSync(process.env.HOME + '/.local/share/chezmoi/home/.chezmoidata.yaml').toString() - return YAML.parse(text, { maxAliasCount: -1 }) -} - -// Creates the installOrders object which maps package managers to arrays of packages to install -let generateInstallOrderCount = 0 -async function generateInstallOrders(pkgsToInstall) { - const installerPreference = await OSTypeInstallerKey() - const preferenceOrder = installData.installerPreference[installerPreference] - const logStage = 'Install Orders' - const packagesToInstall = pkgsToInstall - const softwarePackages = installData.softwarePackages - if (generateInstallOrderCount === 0) { - log('info', logStage, `Installer preference category detected as ${installerPreference}`) - log('info', logStage, `Preference order acquired:`) - console.log('Preference order:', preferenceOrder) - } - generateInstallOrderCount++ - log('info', logStage, `New packages discovered for processing: ${pkgsToInstall} (${pkgsToInstall.length} items)`) - pkgFor: for (let pkg of packagesToInstall) { - let packageKey - if (softwarePackages[pkg + ':' + osID]) { - packageKey = pkg + ':' + osID - } else if (softwarePackages[pkg + ':' + osType]) { - packageKey = pkg + ':' + osType - } else if (softwarePackages[pkg]) { - packageKey = pkg - } else { - log('warn', logStage, `The package \`${pkg}\` was not found in the installation map`) - process.env.DEBUG === 'true' && console.log('softwarePackages:', softwarePackages) - console.log('pkg:', pkg) - continue - } - let comparesRemaining = preferenceOrder.length - for (let preference of preferenceOrder) { - comparesRemaining-- - let currentSelector, doubleScoped, scopedPkgManager, scopedSystem, normalCheck - if ( - softwarePackages[packageKey][preference + ':' + osID] || - softwarePackages[packageKey][preference + ':' + osType] || - softwarePackages[packageKey][preference] - ) { - // Handle the _when attribute - currentSelector = 'when' - doubleScoped = - 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] - scopedSystem = - softwarePackages[packageKey]['_' + currentSelector + ':' + osID] || - softwarePackages[packageKey]['_' + currentSelector + ':' + osType] - normalCheck = softwarePackages[packageKey]['_' + currentSelector] - if (doubleScoped) { - try { - await runSilentCommand(doubleScoped) - } catch (e) { - 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 - } - process.env.DEBUG === 'true' && log('info', 'Filter', `${pkg} is being skipped because of the _when:${pref} condition`) - processPluginOrders(pkg) - continue pkgFor - } - } else if (scopedPkgManager) { - try { - await runSilentCommand(scopedPkgManager) - } catch (e) { - const pref = preference - process.env.DEBUG === 'true' && log('info', 'Filter', `${pkg} is being skipped because of the _when:${pref} condition`) - processPluginOrders(pkg) - continue pkgFor - } - } else if (scopedSystem) { - try { - await runSilentCommand(scopedSystem) - } catch (e) { - let pref - if (softwarePackages[packageKey]['_' + currentSelector + ':' + osID]) { - pref = osID - } else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osType]) { - pref = osType - } - process.env.DEBUG === 'true' && log('info', 'Filter', `${pkg} is being skipped because of the _when:${pref} condition`) - processPluginOrders(pkg) - continue pkgFor - } - } else if (normalCheck) { - try { - await runSilentCommand(normalCheck) - } catch (e) { - process.env.DEBUG === 'true' && log('info', 'Filter', `${pkg} is being skipped because of the _when condition`) - processPluginOrders(pkg) - continue pkgFor - } - } - - // Handle the _bin attribute - currentSelector = 'bin' - doubleScoped = - 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] - scopedSystem = - softwarePackages[packageKey]['_' + currentSelector + ':' + osID] || - softwarePackages[packageKey]['_' + currentSelector + ':' + osType] - normalCheck = softwarePackages[packageKey]['_' + currentSelector] - if (doubleScoped) { - const bin = - typeof doubleScoped === 'string' - ? which.sync(doubleScoped, { nothrow: true }) - : doubleScoped.map((x) => which.sync(x, { nothrow: true })).every((y) => !!y) - if (bin) { - 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 - } - process.env.DEBUG === 'true' && log('info', 'Filter', `${bin} already in PATH (via _bin:${pref})`) - processPluginOrders(pkg) - continue pkgFor - } else { - if (preference === 'cask' || preference === 'flatpak') { - installOrdersBinLink.push({ package: packageKey, bin: doubleScoped, preference }) - } - } - } else if (scopedPkgManager) { - const bin = - typeof scopedPkgManager === 'string' - ? which.sync(scopedPkgManager, { nothrow: true }) - : scopedPkgManager.map((x) => which.sync(x, { nothrow: true })).every((y) => !!y) - if (bin) { - const pref = preference - process.env.DEBUG === 'true' && log('info', 'Filter', `${bin} already in PATH (via _bin:${pref})`) - processPluginOrders(pkg) - continue pkgFor - } else { - if (preference === 'cask' || preference === 'flatpak') { - installOrdersBinLink.push({ package: packageKey, bin: scopedPkgManager, preference }) - } - } - } else if (scopedSystem) { - const bin = - typeof scopedSystem === 'string' - ? which.sync(scopedSystem, { nothrow: true }) - : scopedSystem.map((x) => which.sync(x, { nothrow: true })).every((y) => !!y) - if (bin) { - let pref - if (softwarePackages[packageKey]['_' + currentSelector + ':' + osID]) { - pref = osID - } else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osType]) { - pref = osType - } - process.env.DEBUG === 'true' && log('info', 'Filter', `${bin} already in PATH (via _bin:${pref})`) - processPluginOrders(pkg) - continue pkgFor - } else { - if (preference === 'cask' || preference === 'flatpak') { - installOrdersBinLink.push({ package: packageKey, bin: scopedSystem, preference }) - } - } - } else if (normalCheck) { - const bin = - typeof normalCheck === 'string' - ? which.sync(normalCheck, { nothrow: true }) - : normalCheck.map((x) => which.sync(x, { nothrow: true })).every((y) => !!y) - if (bin) { - process.env.DEBUG === 'true' && log('info', 'Filter', `${bin} already in PATH (via _bin)`) - processPluginOrders(pkg) - continue pkgFor - } else { - if (preference === 'cask' || preference === 'flatpak') { - installOrdersBinLink.push({ package: packageKey, bin: normalCheck, preference }) - } - } - } - - // Handle the _app definition - const appName = softwarePackages[packageKey]['_app'] - if (appName) { - if(fileExists(`/Applications/${appName}`) || fileExists(`${process.env.HOME}/Applications/${appName}`)) { - processPluginOrders(pkg) - continue pkgFor - } - } - - // Handle the _deps attribute - currentSelector = 'deps' - doubleScoped = - 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] - scopedSystem = - softwarePackages[packageKey]['_' + currentSelector + ':' + osID] || - softwarePackages[packageKey]['_' + currentSelector + ':' + osType] - normalCheck = softwarePackages[packageKey]['_' + currentSelector] - const dependenciesTag = 'Dependencies' - if (doubleScoped) { - let pref - if (softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osID]) { - pref = '_deps:' + preference + ':' + osID - log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`) - await generateInstallOrders(softwarePackages[packageKey][pref]) - } else if (softwarePackages[packageKey]['_' + currentSelector + ':' + preference + ':' + osType]) { - pref = '_deps:' + preference + ':' + osType - log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`) - await generateInstallOrders(softwarePackages[packageKey][pref]) - } else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osID + ':' + preference]) { - pref = '_deps:' + osID + ':' + preference - log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`) - await generateInstallOrders(softwarePackages[packageKey][pref]) - } else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osType + ':' + preference]) { - pref = '_deps:' + osType + ':' + preference - log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`) - await generateInstallOrders(softwarePackages[packageKey][pref]) - } - } else if (scopedPkgManager) { - const pref = '_deps:' + preference - log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`) - await generateInstallOrders(softwarePackages[packageKey][pref]) - } else if (scopedSystem) { - let pref - if (softwarePackages[packageKey]['_' + currentSelector + ':' + osID]) { - pref = '_deps:' + osID - log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`) - await generateInstallOrders(softwarePackages[packageKey][pref]) - } else if (softwarePackages[packageKey]['_' + currentSelector + ':' + osType]) { - pref = '_deps:' + osType - log('info', dependenciesTag, `Installing dependencies for ${packageKey}.${pref}`) - await generateInstallOrders(softwarePackages[packageKey][pref]) - } - } else if (normalCheck) { - log('info', dependenciesTag, `Installing dependencies for ${packageKey}.deps`) - await generateInstallOrders(softwarePackages[packageKey]['_deps']) - } - if (softwarePackages[packageKey][preference + ':' + osID]) { - await updateInstallMaps( - preference, - softwarePackages[packageKey], - preference + ':' + osID, - pkg, - packageKey, - softwarePackages - ) - break - } else if (softwarePackages[packageKey][preference + ':' + osType]) { - await updateInstallMaps( - preference, - softwarePackages[packageKey], - preference + ':' + osType, - pkg, - packageKey, - softwarePackages - ) - break - } else if (softwarePackages[packageKey][preference]) { - await updateInstallMaps( - preference, - softwarePackages[packageKey], - preference, - pkg, - packageKey, - softwarePackages - ) - break - } - } else { - if (!comparesRemaining) { - log('info', 'No Match', `There was no match found for ${pkg} - it may be an OS-specific package`) - } - } - } - } - if (generateInstallOrderCount === 1) { - return installOrders - } else { - generateInstallOrderCount-- - } -} - -function processPluginOrders(pkg) { - const pluginMap = chezmoiData && chezmoiData.softwarePlugins && chezmoiData.softwarePlugins[pkg] - if (pluginMap) { - if (pluginMap.cmd && pluginMap.plugins) { - installOrdersPlugins.push({ package: pkg, cmd: pluginMap.cmd, plugins: pluginMap.plugins }) - } - } -} - -// Update install, pre-hook, and post-hook objects -async function updateInstallMaps(preference, packages, scopedPreference, pkg, packageKey, softwarePackages) { - const preHook = getHook(packages, 'pre', scopedPreference, preference) - if (preHook) { - installOrdersPre = installOrdersPre.concat(typeof preHook === 'string' ? [preHook] : preHook) - } - const postHook = getHook(packages, 'post', scopedPreference, preference) - if (postHook) { - installOrdersPost = installOrdersPost.concat(typeof postHook === 'string' ? [postHook] : postHook) - } - const serviceHook = getHook(packages, 'service', scopedPreference, preference) - const serviceEnabledHook = getHook(packages, 'serviceEnabled', scopedPreference) - if (serviceHook && serviceEnabledHook) { - installOrdersService = installOrdersService.concat(typeof serviceHook === 'string' ? [serviceHook] : serviceHook) - } - const groupsHook = getHook(packages, 'groups', scopedPreference, preference) - if (groupsHook) { - installOrdersGroups = installOrdersGroups.concat(typeof groupsHook === 'string' ? [groupsHook] : groupsHook) - } - const portsHook = getHook(packages, 'ports', scopedPreference, preference) - if (portsHook) { - installOrdersPorts = installOrdersPorts.concat(typeof portsHook === 'string' ? [{ - packageKey, - ports: portsHook - }] : { - packageKey, - ports: portsHook}) - } - processPluginOrders(pkg) - if (!installOrders[preference]) { - installOrders[preference] = [] - } - log('info', 'Match', `Found a match for the package \`${pkg}\` (${packageKey} via ${scopedPreference})`) - const newPackages = packages[scopedPreference] - const newPkgs = typeof newPackages === 'string' ? [ newPackages ] : newPackages - 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 - } - } - } - if (preference === 'snap' && softwarePackages[pkg]['_snapClassic'] === true) { - if (!installOrders['snap-classic']) { - installOrders['snap-classic'] = [] - } - installOrders['snap-classic'] = installOrders['snap-classic'].concat(newPkgs) - } else { - installOrders[preference] = installOrders[preference].concat(newPkgs) - } -} - -// Get pre / post install hooks -function getHook(packages, hook, scopedPreference, preference) { - const hookLabel = '_' + hook + ':' - if (packages[hookLabel + scopedPreference]) { - return packages[hookLabel + scopedPreference] - } else if (packages[hookLabel + preference]) { - return packages[hookLabel + preference] - } else if (packages[hookLabel + osID]) { - return packages - } else if (packages[hookLabel + osType]) { - return packages[hookLabel + osType] - } else if (packages['_' + hook]) { - return packages['_' + hook] - } -} - -// Acquire OS type installer key (for the installerPreference data key) -async function OSTypeInstallerKey() { - try { - 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 }) - if (apt) { - return dirExists('/etc/ubuntu-advantage') ? 'ubuntu' : 'apt' - } else if (dnf || yum) { - return 'dnf' - } else if (pacman) { - return 'pacman' - } else if (zypper) { - return 'zypper' - } else if (freebsdPkg && freebsdVersion) { - return 'freebsd' - } else { - return dirExists('/Applications') && dirExists('/Library') ? 'darwin' : 'windows' - } - } catch (e) { - log('error', 'OS Detection', 'There was an error determining the type of operating system') - console.error(e) - } -} - -// Acquire OS type -async function OSType() { - return dirExists('/Applications') && dirExists('/Library') ? 'darwin' : (fileExists('/etc/os-release') ? 'linux' : 'windows') -} - -// Acquire release ID (for Linux) -async function releaseID() { - const ID = await $` - if [ -f /etc/os-release ]; then - . /etc/os-release - echo -n $ID - fi - ` - return ID.stdout -} - -// Post-install hook -/* -async function afterInstall(packageManager) { - const logStage = 'Post-Install Package Manager' - if (packageManager === 'appimage') { - } else if (packageManager === 'ansible') { - } else if (packageManager === 'apk') { - } else if (packageManager === 'apt') { - try { - runCommand('Running apt-get autoclean', `sudo apt-get autoclean`) - runCommand('Running apt-get autoremove', `sudo apt-get -y autoremove`) - } catch (e) { - log('error', logStage, 'Error cleaning up apt-get') - } - } else if (packageManager === 'basher') { - } else if (packageManager === 'binary') { - } else if (packageManager === 'brew' || packageManager === 'cask') { - log('info', logStage, `Ensuring Homebrew cleanup is run`) - await $`brew cleanup` - } 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') { - } -} -*/ -/* -async function ensurePackage(dep) { - const target = which.sync(dep, { nothrow: true }) - if (!target) { - if (osType === 'linux') { - const apk = which.sync('apk', { nothrow: true }) - const apt = which.sync('apt-get', { nothrow: true }) - const dnf = which.sync('dnf', { nothrow: true }) - const pkg = which.sync('pkg', { nothrow: true }) - const yum = which.sync('yum', { nothrow: true }) - const pacman = which.sync('pacman', { nothrow: true }) - const zypper = which.sync('zypper', { nothrow: true }) - if (apk) { - await $`sudo apk add ${dep}` - } else if (apt) { - if (updateDone['apt-get'] !== true) { - // await beforeInstall('apt-get') - } - try { - log('info', 'apt-get Installation', `Checking if ${dep} is already installed`) - runCommand( - `Checking if ${dep} is already installed via apt-get`, - `dpkg -l ${dep} | grep -E '^ii' > /dev/null` - ) - log('info', 'Filter', `${pkg} already installed via apt-get`) - } catch (e) { - runCommand( - `Installing ${dep} via apt-get`, - `sudo apt-get -o DPkg::Options::=--force-confdef install -y ${dep}` - ) - log('success', 'Install', `Successfully installed ${pkg} via apt-get`) - } - } else if (dnf) { - if (updateDone['dnf'] !== true) { - // await beforeInstall('dnf') - } - try { - log('info', 'dnf Installation', `Checking if ${dep} is already installed`) - await $`rpm -qa | grep '$'"${dep}-" > /dev/null` - } catch (e) { - log('info', 'dnf Installation', `Installing ${dep} since it is not already present on the system`) - await $`sudo dnf install -y ${dep}` - } - } else if (yum) { - if (updateDone['yum'] !== true) { - // await beforeInstall('yum') - } - try { - log('info', 'YUM Installation', `Checking if ${dep} is already installed`) - await $`rpm -qa | grep '$'"${dep}-" > /dev/null` - } catch (e) { - log('info', 'YUM Installation', `Installing ${dep} since it is not already present on the system`) - await $`sudo yum install -y ${dep}` - } - } else if (pacman) { - if (updateDone['pacman'] !== true) { - // await beforeInstall('pacman') - } - 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}` - } - } else if (zypper) { - if (updateDone['zypper'] !== true) { - // await beforeInstall('zypper') - } - try { - log('info', 'Zypper Installation', `Checking if ${dep} is already installed`) - await $`rpm -qa | grep '$'"${dep}-" > /dev/null` - } 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}` - } - } - } else if (osType === 'darwin') { - if (updateDone['brew'] !== true) { - // await beforeInstall('brew') - } - await $`brew install --quiet ${dep}` - } else if (osType === 'windows') { - if (updateDone['choco'] !== true) { - // await beforeInstall('choco') - } - await `choco install -y ${dep}` - } - } -} -*/ - -// Pre-install hook -const updateDone = {} -/* -async function ensureInstalled(bin, callback) { - const logStage = 'Package Manager Install' - const installed = which.sync(bin, { nothrow: true }) - if (installed) { - log('info', logStage, `\`${bin}\` is available`) - } else { - log('warn', logStage, `\`${bin}\` is not installed!`) - if (callback) { - await callback - } else { - log('error', logStage, `There does not appear to be an installation method available for \`${bin}\``) - } - } -}*/ -/* -async function ensurePackageManagerAnsible() { - await $`pipx install ansible` - if (osType === 'darwin') { - await $`pipx inject ansible PyObjC PyObjC-core` - } - await $`pipx inject ansible docker lxml netaddr pexpect python-vagrant pywinrm requests-credssp watchdog` - 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`) -} -*/ -// Ensure the package manager is available -//let packageManagerInstalled = {} -/* -async function ensurePackageManager(packageManager) { - const logStage = 'Pre-Reqs' - log('info', logStage, `Ensuring \`${packageManager}\` is set up`) - if (packageManagerInstalled[packageManager]) { - return - } else { - packageManagerInstalled[packageManager] = true - } - if (packageManager === 'ansible') { - await ensurePackageManager('pipx') - } - if ( - packageManager === 'gem' || - packageManager === 'go' || - packageManager === 'npm' || - packageManager === 'pipx' || - packageManager === 'whalebrew' - ) { - await ensurePackageManager('brew') - } - if (packageManager === 'appimage') { - const zap = which.sync('zap', { nothrow: true }) - if (!zap) { - log('info', 'Zap Installation', 'Installing Zap to handle AppImage installation') - await ensurePackage('curl') - await $`sudo curl -sSL --output /usr/local/bin/zap https://github.com/srevinsaju/zap/releases/download/continuous/zap-amd64` - await $`sudo chmod +x /usr/local/bin/zap` - } - } else if (packageManager === 'ansible') { - try { - await $`test -f "$HOME/.cache/megabyte-labs/ansible-installed"` - const ansible = which.sync('ansible', { nothrow: true }) - if (ansible) { - log('info', logStage, `\`ansible\` and its supporting packages appear to be installed`) - } else { - //await ensurePackageManagerAnsible() - } - } catch (e) { - //await ensurePackageManagerAnsible() - } - } else if (packageManager === 'apk') { - await ensureInstalled('apk', false) - } else if (packageManager === 'apt') { - await ensureInstalled('apt', false) - } else if (packageManager === 'basher') { - await ensureInstalled( - 'basher', - $` - # TODO - echo "Bash script that installs basher here" - ` - ) - } else if (packageManager === 'binary') { - await ensurePackage('curl') - } else if (packageManager === 'bpkg') { - await ensureInstalled( - 'bpkg', - $` - # TODO - echo "Bash script that installs bpkg here" - ` - ) - } else if (packageManager === 'brew' || packageManager === 'cask') { - const brew = which.sync('brew', { nothrow: true }) - if (!brew) { - await ensureInstalled( - 'brew', - $` - if command -v sudo > /dev/null && sudo -n true; then - echo | bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - sudo chmod -R g-w "$(brew --prefix)/share" - else - log('info', logStage, 'Homebrew is not installed. Password may be required.') - bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || BREW_EXIT_CODE="$?" - sudo chmod -R g-w "$(brew --prefix)/share" - if [ -n "$BREW_EXIT_CODE" ]; then - if command -v brew > /dev/null; then - log('warn', logStage, 'Homebrew was installed but part of the installation failed. Attempting to fix..') - 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 - fi - fi - ` - ) - } - } else if (packageManager === 'cargo') { - const cargo = which.sync('cargo', { nothrow: true }) - if (!cargo) { - if (osType === 'darwin') { - const rustup = which.sync('rustup-init', { nothrow: true }) - if (!rustup) { - await $`brew install --quiet rustup` - } - await $`rustup-init -y` - } else if (osType === 'windows') { - } else { - await ensurePackage('cargo') - } - } - } else if (packageManager === 'choco') { - await ensureInstalled( - 'choco', - $` - 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'))" - ` - ) - } else if (packageManager === 'crew') { - await ensureInstalled( - 'crew', - $` - # TODO Bash script that installs crew here - # Source: https://github.com/chromebrew/chromebrew - curl -Ls git.io/vddgY | bash - ` - ) - } else if (packageManager === 'dnf') { - const dnf = which.sync('dnf', { nothrow: true }) - const yum = which.sync('yum', { nothrow: true }) - if (dnf) { - log('info', logStage, `\`dnf\` is available`) - } else if (yum) { - log('info', logStage, `\`yum\` is available`) - } else { - log('error', logStage, `Both \`dnf\` and \`yum\` are not available`) - } - } else if (packageManager === 'flatpak') { - const flatpak = which.sync('flatpak', { nothrow: true }) - if (flatpak) { - log('info', logStage, `\`flatpak\` is available`) - } else { - 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 }) - if (apk) { - runCommand('Installing flatpak via apk', 'sudo apk add flatpak') - } else if (apt) { - runCommand('Installing flatpak via apt-get', 'sudo apt-get install -y flatpak') - if (fileExists('/usr/bin/gnome-shell')) { - runCommand( - 'Installing gnome-software-plugin-flatpak via apt-get', - 'sudo apt-get install -y gnome-software-plugin-flatpak' - ) - } - if (fileExists('/usr/bin/plasmashell')) { - runCommand('Installing plasmashell via apt-get', 'sudo apt-get install -y plasmashell') - } - } else if (dnf) { - await $`sudo dnf install -y flatpak` - } else if (yum) { - await $`sudo yum install -y flatpak` - } else if (pacman) { - await $`sudo pacman -Sy flatpak` - } else if (zypper) { - await $`sudo zypper install -y flatpak` - } - log('info', logStage, `\`flatpak\` was installed. It may require a reboot to function correctly.`) - } - 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!`) - } - } else if (packageManager === 'gem') { - const gem = which.sync('gem', { nothrow: true }) - if (!gem) { - await ensureInstalled('gem', $`brew install --quiet ruby`) - } - } else if (packageManager === 'go') { - const go = which.sync('go', { nothrow: true }) - if (!go) { - await ensureInstalled('go', $`brew install --quiet go`) - } - } else if (packageManager === 'nix') { - await ensureInstalled( - 'nix', - $` - 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 - ` - ) - } else if (packageManager === 'npm') { - const npm = which.sync('npm', { nothrow: true }) - const node = which.sync('node', { nothrow: true }) - const volta = which.sync('volta', { nothrow: true }) - if (npm && node && volta) { - log('info', logStage, `\`npm\`, \`node\`, and \`volta\` are available`) - } else { - if (!volta) { - await $`brew install --quiet volta` - } - await $` - export VOLTA_HOME="\${XDG_DATA_HOME:-$HOME/.local/share}/volta" - export PATH="$VOLTA_HOME/bin:$PATH" - volta setup - volta install node - ` - } - log('info', logStage, 'Ensuring Volt has Node.js runtime available') - await $`export VOLTA_HOME="\${XDG_DATA_HOME:-$HOME/.local/share}/volta" && export PATH="$VOLTA_HOME/bin:$PATH" && if ! volta list 2>&1 | grep 'runtime node' > /dev/null; then volta install node; fi` - } else if (packageManager === 'pacman') { - await ensureInstalled('pacman', false) - } else if (packageManager === 'pipx') { - const pipx = which.sync('pipx', { nothrow: true }) - if (!pipx) { - await ensureInstalled('pipx', $`brew install --quiet pipx`) - await $`pipx ensurepath` - } - } else if (packageManager === 'pkg') { - await ensureInstalled('pkg', false) - } else if (packageManager === 'port') { - const port = which.sync('port', { nothrow: true }) - if (!port) { - log('info', logStage, `Installing ${packageManager}`) - await ensureInstalled( - 'port', - $` - sudo mkdir -p /opt/mports - cd /opt/mports - sudo rm -rf macports-base - sudo git clone https://github.com/macports/macports-base.git - cd macports-base - sudo git checkout v2.8.0 - sudo bash --noprofile --norc -c './configure --enable-readline && make && make install && make distclean' - sudo port selfupdate - ` - ) - log('info', logStage, `${packageManager} is now installed`) - } else { - log('info', logStage, `\`port\` is available`) - } - } else if (packageManager === 'scoop') { - await ensureInstalled( - 'scoop', - $` - powershell 'Set-ExecutionPolicy RemoteSigned -Scope CurrentUser' - powershell 'irm get.scoop.sh | iex - ` - ) - } 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 }) - if (apt) { - 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`) - // TODO Following may be required on Kali -> https://snapcraft.io/docs/installing-snap-on-kali - // systemctl enable --now snapd apparmor - runCommand('Enabling snapd service', `sudo systemctl enable snapd`) - runCommand('Starting snapd service', `sudo systemctl start snapd`) - } else if (dnf) { - runCommand('Ensuring snapd is installed', `sudo dnf install -y snapd`) - if (!fileExists('/snap')) { - await $`sudo ln -s /var/lib/snapd/snap /snap` - } - runCommand('Enabling snapd service', `sudo systemctl enable snapd`) - runCommand('Starting snapd service', `sudo systemctl start snapd`) - } else if (yum) { - runCommand('Ensuring snapd is installed', 'sudo yum install -y snapd') - await $`sudo systemctl enable --now snapd.socket` - if (!fileExists('/snap')) { - $`sudo ln -s /var/lib/snapd/snap /snap` - } - } else if (pacman) { - $`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` - } else if (zypper) { - // TODO See https://snapcraft.io/docs/installing-snap-on-opensuse - await $` - echo "TODO - Bash script that installs snap w/ zypper" - ` - } - const snap = which.sync('snap', { nothrow: true }) - if (snap) { - runCommand('Check info for core snap package', `sudo snap info core`) - // Required: https://snapcraft.io/docs/troubleshooting#heading--early - runCommand('Ensuring snap is seeded', `sudo snap wait system seed.loaded`) - runCommand('Ensuring snap core is installed', `sudo snap install core`) - } else { - log('warn', logStage, 'Snap installation sequence completed but the snap bin is still not available') - } - } else if (packageManager === 'script') { - } else if (packageManager === 'whalebrew') { - await ensureInstalled('whalebrew', $`brew install --quiet whalebrew`) - } else if (packageManager === 'winget') { - await ensureInstalled( - 'winget', - $` - echo "TODO - Script that installs winget here" - ` - ) - } else if (packageManager === 'yay') { - const yay = which.sync('yay', { nothrow: true }) - await $`sudo pacman -S --needed base-devel git` - 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 - ` - } else if (packageManager === 'zypper') { - await ensureInstalled('zypper', false) - } -} -*/ -/* -// Installs a list of packages via the specified package manager -async function installPackageList(packageManager, packages) { - const logStage = 'Package Install' - try { - if (packageManager === 'appimage') { - for (let pkg of packages) { - try { - if (pkg.substring(0, 4) === 'http') { - log('info', 'AppImage Install', `Installing ${pkg} from its URL`) - runCommand('Installing ${pkg} via zap', `zap install --select-first -q --from ${pkg}`) - } else if ((pkg.match(/\//g) || []).length === 1) { - log('info', 'AppImage Install', `Installing ${pkg} from a GitHub Release`) - runCommand('Installing ${pkg} via zap', `zap install --select-first -q --github --from ${pkg}`) - } else { - log('info', 'AppImage Install', `Installing ${pkg} using the AppImage Catalog`) - runCommand('Installing ${pkg} via zap', `zap install --select-first -q ${pkg}`) - } - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error using Zap to install ${pkg}`) - console.error(e) - } - } - log('warn', 'Install', 'Zap installs might fail - this is expected. Waiting on fixes to Zap upstream project') - } else if (packageManager === 'ansible') { - for (let pkg of packages) { - try { - const unbuffer = which.sync('unbuffer', { nothrow: true }) - let unbufferPrefix = '' - if (unbuffer) { - unbufferPrefix = 'unbuffer' - } - const verboseMode = process.env.DEBUG_MODE === 'true' ? 'vv' : '' - if (osPlatform === 'darwin' || osPlatform === 'linux' || osPlatform === 'windows') { - 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}` - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } else { - log('warn', 'Ansible', 'Unsupported platform - ' + osPlatform) - } - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with Ansible`) - } - } - } else if (packageManager === 'apk') { - for (let pkg of packages) { - try { - runCommand('Installing ${pkg} via apk', `sudo apk add ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with apk`) - console.error(e) - } - } - } else if (packageManager === 'apt') { - for (let pkg of packages) { - try { - if (pkg.startsWith('http') && pkg.endsWith('.deb')) { - runCommand( - `Downloading and installing ${pkg}`, - `TMP="$(mktemp)" && curl -sSL ${pkg} -o "$TMP" && sudo dpkg -i "$TMP"` - ) - } else { - runCommand( - `Installing ${pkg} via ${packageManager}`, - `sudo DEBIAN_FRONTEND=noninteractive apt-get -o DPkg::Options::=--force-confdef install -y ${pkg}` - ) - } - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with apt-get`) - console.error(e) - } - } - } else if (packageManager === 'basher') { - for (let pkg of packages) { - try { - await $`basher install ${pkg}` - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with basher`) - console.error(e) - } - } - } else if (packageManager === 'binary') { - for (let pkg of packages) { - try { - const bins = installData.softwarePackages.filter((x) => x.appimage === pkg) - 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}` - } - } catch (e) { - log('error', 'Install', `There was an error installing the binary release for ${pkg}`) - console.error(e) - } - } - } else if (packageManager === 'brew') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `brew install --quiet ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with brew`) - console.error(e) - } - } - } else if (packageManager === 'cask') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `brew install --cask --no-quarantine --quiet ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with Homebrew Cask`) - console.error(e) - } - } - } else if (packageManager === 'cargo') { - for (const pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `cargo install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with Cargo`) - console.error(e) - } - } - } else if (packageManager === 'choco') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `choco install -y ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with Chocolatey`) - console.error(e) - } - } - } else if (packageManager === 'crew') { - } else if (packageManager === 'dnf') { - const dnf = which.sync('dnf', { nothrow: true }) - const yum = which.sync('yum', { nothrow: true }) - for (let pkg of packages) { - if (dnf) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `sudo dnf install -y ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with dnf`) - console.error(e) - } - } else if (yum) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `sudo yum install -y ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with yum`) - console.error(e) - } - } - } - } else if (packageManager === 'flatpak') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `sudo flatpak install -y flathub ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with flatpak`) - console.error(e) - } - } - } else if (packageManager === 'gem') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `gem install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with gem`) - console.error(e) - } - } - } else if (packageManager === 'go') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `go install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with go`) - console.error(e) - } - } - } else if (packageManager === 'nix') { - } else if (packageManager === 'npm') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `volta install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with volta`) - console.error(e) - } - } - } else if (packageManager === 'pacman') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `sudo pacman -Sy --noconfirm --needed ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with pacman`) - console.error(e) - } - } - } else if (packageManager === 'pipx') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `pipx install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('warn', 'Install', `There was an error installing ${pkg} with pipx, re-attempting using pip3`) - console.error(e) - try { - runCommand(`Installing ${pkg} via pip3`, `pip3 install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via pip3`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with both pipx and pip3`) - console.error(e) - } - } - } - } else if (packageManager === 'pip') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `pip3 install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('warn', 'Install', `There was an error installing ${pkg} with pip3`) - console.error(e) - } - } - } 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) - } - } - } else if (packageManager === 'port') { - const port = which.sync('port', { nothrow: true }) - if (port) { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `sudo port install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with port`) - console.error(e) - } - } - } else { - log( - 'error', - 'Port Not Installed', - `Unable to install with port because it is not installed. Skipping installation of ${packages}` - ) - } - } else if (packageManager === 'scoop') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `scoop install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with scoop`) - console.error(e) - } - } - } else if (packageManager === 'snap') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `sudo snap install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with snap`) - console.error(e) - } - } - } else if (packageManager === 'script') { - for (let pkg of packages) { - try { - await $`bash -c ${pkg}` - } catch (e) { - log('error', 'Install', `There was an error running the script installation method for ${pkg}`) - console.error(e) - } - } - } else if (packageManager === 'snap-classic') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `sudo snap install --classic ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with snap in classic mode`) - console.error(e) - } - } - } else if (packageManager === 'whalebrew') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `whalebrew install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with whalebrew`) - console.error(e) - } - } - } else if (packageManager === 'winget') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `winget install ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with winget`) - console.error(e) - } - } - } else if (packageManager === 'yay') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `yay -Sy --noconfirm --needed ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with yay`) - console.error(e) - } - } - } else if (packageManager === 'zypper') { - for (let pkg of packages) { - try { - runCommand(`Installing ${pkg} via ${packageManager}`, `sudo zypper install -y ${pkg}`) - log('success', 'Install', `${pkg} successfully installed via ${packageManager}`) - } catch (e) { - log('error', 'Install', `There was an error installing ${pkg} with zypper`) - console.error(e) - } - } - } - } catch (e) { - log('error', logStage, `Possibly encountered an error while installing via \`${packageManager}\``) - log('info', logStage, `Proceeding with the installation..`) - } -}*/ - -async function addUserGroup(group) { - const logStage = 'Users / Groups' - log('info', logStage, `Ensuring the ${group} group / user is added`) - runCommand(`Creating the ${group} user / group`, `sudo "${process.env.HOME}/.local/bin/add-usergroup" "${process.env.USER}" "${group}"`) -} - -/** - * Adds the rules specified in the `_ports` key of each entry in the `software.yml` file. - * - * @param rule {packageKey: string, ports: any} Firewall rule in the form of 8888/tcp or 9999/udp. Can also be the XML file name stored in ~/.config/firewall/etc/firewalld/services. - */ -async function addFirewallRule(rule) { - try { - const logStage = 'Firewall' - const packageName = installData.softwarePackages[rule.packageKey] && installData.softwarePackages[rule.packageKey]._name - const packageDesc = installData.softwarePackages[rule.packageKey] && installData.softwarePackages[rule.packageKey]._desc - log('info', logStage, `Ensuring the ${rule.packageKey} rule is added since the _ports key is defined`) - if (osType === 'linux') { - const firewallCmd = which.sync('firewall-cmd', { nothrow: true }) - // const ufw = which.sync('ufw', { nothrow: true }) - if (firewallCmd) { - const serviceFile = `${process.env.HOME}/.config/firewall/etc/firewalld/services/${rule.packageKey}.xml` - if (fileExists(serviceFile)) { - log('info', logStage, `Service file found at ${serviceFile} - using it to apply firewall-cmd configuration`) - runCommand(`Copying over ${serviceFile} file to /etc/firewalld/services`, `sudo cp -f "${serviceFile}" "/etc/firewalld/services/${rule.packageKey}.xml"`) - runCommand(`Adding the ${rule.packageKey} firewall-cmd service`, `sudo firewall-cmd --add-service=${rule.packageKey} --permanent`) - } else { - if (typeof rule.ports === 'string') { - runCommand(`Adding the ${rule.packageKey} ${rule.ports} rule to the firewall configuration`, `sudo firewall-cmd --add-port=${rule.ports} --permanent`) - } else { - for (const port of rule.ports) { - if (typeof port === 'string') { - runCommand(`Adding the ${rule.packageKey} ${rule.ports} rule to the firewall configuration`, `sudo firewall-cmd --add-port=${rule.ports} --permanent`) - } else if (port.port && port.proto) { - runCommand(`Adding the ${rule.packageKey} ${port.port}/${port.proto} rule to the firewall configuration`, `sudo firewall-cmd --add-port=${port.port}/${port.proto} --permanent`) - } else { - log('error', logStage, `Unable to parse the firewall definition for ${rule.packageKey}`) - } - } - } - } - } else { - log('error', logStage, `The firewall-cmd executable is not present on the system so the firewall cannot be configured`) - } - } else if (osType === 'darwin') { - const socketFilterFw = '/usr/libexec/ApplicationFirewall/socketfilterfw' - const serviceFile = `${process.env.HOME}/.config/firewall/darwin/${rule.packageKey}.sh` - if (fileExists(serviceFile)) { - runCommand(`Executing the matching ${serviceFile} service file`, `sudo bash "${serviceFile}"`) - } else { - if (typeof rule.ports === 'string') { - log('error', logStage, `_ports rules that are equal to strings are not yet implemented on macOS (package: ${rule.packageKey})`) - } else { - for (const port of rule.ports) { - if (typeof port === 'string') { - log('error', logStage, `_ports rules that are equal to strings are not yet implemented on macOS (package: ${rule.packageKey})`) - } else if (port.port && port.proto) { - if (packageDesc) { - runCommand(`Adding new service with description populated for ${rule.packageKey}`, `${socketFilterFw} --add --service "${packageName ? packageName : rule.packageKey}" --setglobaldescription "${packageDesc} --getglobalstate"`) - } else { - runCommand(`Adding new service for ${rule.packageKey}`, `${socketFilterFw} --add --service "${packageName ? packageName : rule.packageKey}" --getglobalstate`) - } - runCommand(`Adding firewall rule for ${rule.packageKey}`, `${socketFilterFw} --add --service "${packageName ? packageName : rule.packageKey}" --port ${port.port} --protocol ${port.proto}`) - } else { - log('error', logStage, `Unable to parse the firewall definition for ${rule.packageKey}`) - } - } - } - } - } else if (osType === 'windows') { - log('warn', logStage, `Windows support not yet added`) - } else { - log('warn', logStage, `Unknown operating system type`) - } - } catch (e) { - console.log(e) - log('error', 'Bin', `Error configuring firewall settings for ${rule.packageKey}`) - } -} - -async function updateService(service) { - const logStage = 'Service Service' - if (osType === 'linux') { - const systemctl = which.sync('systemctl', { nothrow: true }) - const brew = which.sync('brew', { nothrow: true }) - if (systemctl) { - try { - runCommand(`Starting / enabling ${service} with systemctl`, `sudo systemctl enable --now ${service}`) - log('success', logStage, `Started / enabled the ${service} service`) - } catch (e) { - log('info', logStage, `There was an error starting / enabling the ${service} service with systemd`) - try { - if (brew) { - if (typeof service === 'array') { - service.forEach(x => { - runCommand(`Starting / enabling object array ${x.name} with Homebrew`, `${x.sudo ? 'sudo brew' : 'brew'} services restart ${x.name}`) - log('success', logStage, `Started / enabled the ${x.name} service with Homebrew`) - }) - } else if (typeof service === 'object') { - runCommand(`Starting / enabling object ${service.name} with Homebrew`, `${service.sudo ? 'sudo brew' : 'brew'} services restart ${service.name}`) - log('success', logStage, `Started / enabled the ${service.name} service with Homebrew`) - } else { - runCommand(`Starting / enabling ${service} with Homebrew`, `brew services restart ${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) - } - } - } else { - log( - 'warn', - logStage, - `The systemctl command is not available so applications with services cannot be started / enabled` - ) - } - } else if (osType === 'darwin') { - const brew = which.sync('brew', { nothrow: true }) - if (brew) { - try { - if (typeof service === 'array') { - service.forEach(x => { - runCommand(`Starting / enabling object array ${x.name} with Homebrew`, `${x.sudo ? 'sudo brew' : 'brew'} services restart ${x.name}`) - log('success', logStage, `Started / enabled the ${x.name} service with Homebrew`) - }) - } else if (typeof service === 'object') { - runCommand(`Starting / enabling object ${service.name} with Homebrew`, `${service.sudo ? 'sudo brew' : 'brew'} services restart ${service.name}`) - log('success', logStage, `Started / enabled the ${service.name} service with Homebrew`) - } else { - runCommand(`Starting / enabling ${service} with Homebrew`, `brew services restart ${service}`) - log('success', logStage, `Started / enabled the ${service} service with Homebrew`) - } - } catch (e) { - log('error', logStage, `There was an error starting / enabling the ${service} Homebrew service`) - console.error(e) - } - } else { - log('warn', logStage, `Homebrew is not available - skipping service start command`) - } - } -} - -/** - * Filter that resolves when all asynchronous filter actions are done - */ -/* -const asyncFilter = async (arr, predicate) => { - const results = await Promise.all(arr.map(predicate)) - - return arr.filter((_v, index) => results[index]) -} - -async function pruneInstallOrders(installOrders) { - const newOrders = Object.assign({}, installOrders) - log('info', 'Filter', 'Removing packages from installOrders that are already installed') - for (const pkgManager in installOrders) { - log('info', 'Filter', `Filtering the ${pkgManager} installOrders`) - console.log('List to be filtered:', newOrders[pkgManager]) - if (pkgManager === 'appimage') { - newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => { - try { - await runSilentCommand(`zap list | grep "${pkg}" > /dev/null`) - return false - } catch (e) { - return true - } - }) - } else if (pkgManager === 'apt') { - newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => { - try { - await runSilentCommand(`dpkg -l ${pkg} | grep -E '^ii' > /dev/null`) - return false - } catch (e) { - return true - } - }) - } else if (pkgManager === 'brew') { - let newVal = newOrders[pkgManager] - const pkgTmp = '/tmp/brew-list-install-doctor' - runCommand(`Populating temporary file with list of Homebrew packages`, `brew list > ${pkgTmp}`) - for (const pkg of newOrders[pkgManager]) { - try { - await $`cat ${pkgTmp} | grep '^${pkg}$'` - log('info', 'Filter', 'Filtering list') - newVal = newVal.filter((x) => x !== pkg) - console.log('New list', newVal) - } catch (e) { - // Do nothing - } - } - newOrders[pkgManager] = newVal - } else if (pkgManager === 'dnf') { - const dnf = which.sync('dnf', { nothrow: true }) - newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => { - try { - if (dnf) { - await runSilentCommand(`rpm -qa | grep '$'"${pkg}-" > /dev/null`) - } else { - await runSilentCommand(`rpm -qa | grep '$'"${pkg}-" > /dev/null`) - } - return false - } catch (e) { - return true - } - }) - } else if (pkgManager === 'flatpak') { - const flatpakInstallation = await $`flatpak --installations` - const flatpakDir = flatpakInstallation.stdout.replace('\n', '') - newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => { - try { - await runSilentCommand(`test -d ${flatpakDir}/app/${pkg}`) - return false - } catch (e) { - return true - } - }) - newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => { - try { - await runSilentCommand(`flatpak info ${pkg} > /dev/null`) - return false - } catch (e) { - return true - } - }) - } else if (pkgManager === 'pacman') { - newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => { - try { - await runSilentCommand(`pacman -Qs ${pkg} > /dev/null`) - return false - } catch (e) { - return true - } - }) - } else if (pkgManager === 'snap' || pkgManager === 'snap-classic') { - newOrders[pkgManager] = await asyncFilter(newOrders[pkgManager], async (pkg) => { - try { - await runSilentCommand(`snap list ${pkg} | grep ${pkg} > /dev/null`) - return false - } catch (e) { - return true - } - }) - } - log('info', 'Filter', `Finished filtering ${pkgManager}`) - console.log('Filtered list:', newOrders[pkgManager]) - } - return newOrders -} -*/ - -async function installPlugins(pluginData) { - if (pluginData.cmd && pluginData.plugins && pluginData.plugins.length) { - const pluginWhen = pluginData.when - console.log('Plugin when condition:', pluginWhen) - try { - if (pluginWhen) { - runCommand(`Checking when condition for ${pluginData.package} plugin - ${plugin}`, pluginWhen) - } - for (const plugin of pluginData.plugins) { - try { - const pluginCmd = pluginData.cmd.replace(/{PLUGIN}/g, plugin) - try { - try { - runCommand(`Installing ${pluginData.package} plugin - ${plugin}`, pluginCmd) - log('success', 'Plugin', `Successfully installed ${pluginData.package} plugin - ${plugin}`) - } catch (e) { - log('info', 'Plugin', `Failed to install ${pluginData.package} plugin - ${plugin}`) - console.error(e) - } - } catch (e) { - log('info', 'Plugin', `Skipping ${pluginData.package} plugin installs due to failed when condition - ${pluginWhen}`) - break - } - } catch (e) { - log('error', 'Plugin', `Failed to install ${pluginData.package} plugin due to an unknown reason - ${plugin}`) - console.error(e) - } - } - } catch (e) { - log('info', 'Plugin', 'Failed to pass when condition') - } - } - if (pluginData.update) { - const pluginDataPackage = pluginData.package - if (pluginDataPackage) { - runCommand('Updating ' + pluginDataPackage + ' plugins', pluginData.update) - } - } -} -/* -async function linkBin(installOrdersBinLink) { - let flatpakInstallation, flatpakDir - const softwarePackages = installData.softwarePackages - const flatpak = which.sync('flatpak', { nothrow: true }) - if (flatpak) { - flatpakInstallation = await $`flatpak --installations` - flatpakDir = flatpakInstallation.stdout.replace('\n', '') - } - for (const binLink of installOrdersBinLink) { - const pkg = softwarePackages[binLink.package][binLink.preference] - if (typeof pkg === 'string') { - if (binLink.bin !== false) { - if (!which.sync(binLink.bin, { nothrow: true })) { - if (binLink.preference === 'flatpak' && flatpak) { - try { - runCommand( - `Adding bin link for ${pkg} (${binLink.bin})`, - `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}"'` - ) - 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 (softwarePackages[binLink.package]['_app']) { - try { - const appName = softwarePackages[binLink.package]['_app'] - log('info', 'Bin', `Checking for existence of ${appName} application in /Applications and ~/Applications`) - if (fileExists(`/Applications/${appName}`)) { - runCommand( - `Adding shortcut bin link for ${binLink.package}`, - `bash -c 'mkdir -p "${process.env.HOME}/.local/bin/cask" && echo "open \"/Applications/${appName}\" \\\$*" > "${process.env.HOME}/.local/bin/cask/${binLink.bin}" && chmod +x "${process.env.HOME}/.local/bin/cask/${binLink.bin}"'` - ) - } else if(fileExists(`${process.env.HOME}/Applications/${appName}`)) { - runCommand( - `Adding shortcut bin link for ${binLink.package}`, - `bash -c 'mkdir -p "${process.env.HOME}/.local/bin/cask" && echo "open \"${process.env.HOME}/Applications/${appName}\" \\\$*" > "${process.env.HOME}/.local/bin/cask/${binLink.bin}" && chmod +x "${process.env.HOME}/.local/bin/cask/${binLink.bin}"'` - ) - } else { - log('warn', 'Bin', `Expected Homebrew cask directory not found - ${pkg}`) - } - } catch (e) { - console.log(e) - log('warn', 'Bin', `Error creating bin shortcut link for ${pkg}`) - } - } - } else { - log('info', 'Bin', `Link already exists for ${binLink.package}`) - } - } else { - log('info', 'Bin', `Skipping ${binLink.package} because the _bin is equal to false`) - } - } else { - log('info', 'Bin', `Skipping ${binLink.package} because there was more than one _bin value`) - } - } -} -*/ -// main process -async function installSoftware(pkgsToInstall) { - osType = await OSType() - osID = osType - if (osType === 'linux') { - osID = await releaseID() - } - log('info', 'Catalog Download', `Fetching the latest version of the installation map`) - installData = await downloadInstallData() - chezmoiData = await getChezmoiData() - log('info', 'Filter', `Calculating the install orders`) - await generateInstallOrders(pkgsToInstall ? pkgsToInstall : process.argv.slice(3)) - const packageManagers = Object.keys(installOrders) - packageManagers.length && log('info', 'Pre-Reqs', `Ensuring any package managers that will be used are installed / configured`) - for (const packageManager of packageManagers) { - //await ensurePackageManager(packageManager) - } - try { - for (const key in installOrders) { - installOrders[key] = [...new Set(installOrders[key])] - } - log('info', 'Install', `The install orders were generated:`) - } catch (e) { - log('error', 'Filter', `There was an error reducing the duplicates in the install orders`) - console.error(e) - } - //installOrders = await pruneInstallOrders(installOrders) - delete installOrders._deps - console.log('Install orders:', installOrders) - packageManagers.length && log('info', 'Pre-Reqs', `Running package manager pre-installation steps`) - for (const packageManager of packageManagers) { - // await beforeInstall(packageManager) - } - installOrdersPre.length && log('info', 'Pre-Install', `Running package-specific pre-installation steps`) - for (const script of installOrdersPre) { - const timeoutAvail = which.sync('timeout', { nothrow: true }) - if (timeoutAvail) { - await $`${['timeout', '1000', 'bash', '-c', script]}` - } else { - await $`${['bash', '-c', script]}` - } - } - installOrdersGroups.length && log('info', 'Users / Groups', `Adding groups / users`) - for (const group of installOrdersGroups) { - await addUserGroup(group) - } - packageManagers.length && log('info', 'Install', `Installing the packages`) - for (const packageManager of packageManagers) { - const asyncOrders = [] - //asyncOrders.push(installPackageList(packageManager, installOrders[packageManager])) - await Promise.all(asyncOrders) - } - installOrdersPorts.length && log('info', 'Firewall', 'Configuring firewall exceptions') - for (const firewallRule of installOrdersPorts) { - await addFirewallRule(firewallRule) - } - installOrdersService.length && log('info', 'Post-Install', `Running package-specific post-installation steps`) - for (const service of installOrdersService) { - await updateService(service) - } - if (!binLinkRan) { - binLinkRan = true - log('info', 'Bin', 'Linking bin aliases to their installed packages') - // await linkBin(installOrdersBinLink) - } - for (const script of installOrdersPost) { - try { - log('info', 'Post Hook', script) - const timeoutAvail = which.sync('timeout', { nothrow: true }) - if (timeoutAvail) { - await $`${['timeout', '1000', 'bash', '-c', script]}` - } else { - await $`${['bash', '-c', script]}` - } - } catch(e) { - log('info', 'Post-Install Hook', 'Encountered error while running post-install hook') - } - } - installOrdersPlugins.length && log('info', 'Plugin', 'Installing package-specific plugins') - for (const plugin of installOrdersPlugins) { - await installPlugins(plugin) - } - packageManagers.length && log('info', 'Post-Install', `Running package manager post-installation steps`) - for (const packageManager of packageManagers) { - //await afterInstall(packageManager) - } - log('success', 'Complete', `Done!`) -} - -// Start the main process -await installSoftware(false) diff --git a/home/dot_local/bin/executable_installx b/home/dot_local/bin/executable_installx index de781ecd..bfab59bb 100644 --- a/home/dot_local/bin/executable_installx +++ b/home/dot_local/bin/executable_installx @@ -6,6 +6,15 @@ $.verbose = false let installOrder, osArch, osId, osType, pkgs, sysType const cacheDir = os.homedir() + '/.cache/installx' +const customArgv = minimist(process.argv.slice(3), { + boolean: [ + 'all' + ], + alias: { + a: 'all', + } + }) + function log(message) { console.log(`${chalk.cyanBright('instx->')} ${message}`) } @@ -483,7 +492,7 @@ async function main() { const installKeys = Object.keys(pkgs) .filter(i => expandDeps(argv._).includes(i)) log(`Constructing installation data`) - const installData = pkgMap(installKeys) + const installData = pkgMap(customArgv.all ? Object.keys(pkgs) : installKeys) log(`Filtering install instructions`) const installInstructions = installData .map(x => { @@ -602,9 +611,9 @@ async function main() { const name = typeof y === 'string' ? y : y.name const sudo = typeof y === 'string' ? null : y.sudo if (osType === 'linux' && x.installType !== 'brew' && x.installType !== 'cask' && systemctlInstalled) { - return sudo !== false ? $`sudo systemctl enable --now ${name}` : $`systemctl enable --now ${name}` + return sudo === true ? $`sudo systemctl enable --now ${name}` : $`systemctl enable --now ${name}` } else if (brewInstalled) { - return sudo === true ? $`sudo brew services start ${name}` : $`brew services start ${name}` + return sudo === true ? $`sudo brew services restart ${name}` : $`brew services restart ${name}` } }) }) diff --git a/home/dot_local/bin/executable_update-system b/home/dot_local/bin/executable_update-system index 54ea1a37..d2e72986 100644 --- a/home/dot_local/bin/executable_update-system +++ b/home/dot_local/bin/executable_update-system @@ -1,5 +1,7 @@ #!/usr/bin/env bash +set -euo pipefail + updateApk() { if command -v apk > /dev/null; then logg info 'Running sudo apk update' && sudo apk update || logg error 'Failed to run sudo apk update' diff --git a/home/dot_local/bin/post-installx/executable_post-aqua.sh b/home/dot_local/bin/post-installx/executable_post-aqua.sh deleted file mode 100644 index bee34675..00000000 --- a/home/dot_local/bin/post-installx/executable_post-aqua.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -# @file Aqua Initialization -# @brief Updates and installs any Aqua dependencies that are defined in Aqua's configuration file. -# @description -# This script updates Aqua and then installs any Aqua dependencies that are defined. - -if command -v aqua > /dev/null; then - logg info 'Updating Aqua' - aqua update-aqua - logg info 'Installing Aqua dependencies (if any are defined)' - aqua install -a -else - logg info 'Skipping aqua install script because aqua was not installed' -fi diff --git a/home/dot_local/bin/post-installx/executable_post-atuin.sh b/home/dot_local/bin/post-installx/executable_post-atuin.sh index f30542b1..374a2062 100644 --- a/home/dot_local/bin/post-installx/executable_post-atuin.sh +++ b/home/dot_local/bin/post-installx/executable_post-atuin.sh @@ -2,12 +2,14 @@ # @file Atuin Initialization # @brief Registers with atuin, logs in, imports command history, and synchronizes +set -euo pipefail + if command -v atuin > /dev/null; then - source "${XDG_CONFIG_HOME:-$HOME/.config}/shell/private.sh" + get-secret --exists ATUIN_USERNAME ATUIN_EMAIL ATUIN_PASSWORD ATUIN_KEY logg info 'Registering Atuin account' - atuin register -u "$ATUIN_USERNAME" -e "$ATUIN_EMAIL" -p "$ATUIN_PASSWORD" + atuin register -u "$(get-secret ATUIN_USERNAME)" -e "$(get-secret ATUIN_EMAIL)" -p "$(get-secret ATUIN_PASSWORD)" logg info 'Logging into Atuin account' - atuin login -u "$ATUIN_USERNAME" -p "$ATUIN_PASSWORD" -k "$ATUIN_KEY" + atuin login -u "$(get-secret ATUIN_USERNAME)" -p "$(get-secret ATUIN_PASSWORD)" -k "$(get-secret ATUIN_KEY)" logg info 'Running atuin import auto' atuin import auto logg info 'Running atuin sync' diff --git a/home/dot_local/bin/post-installx/executable_post-blocky.sh b/home/dot_local/bin/post-installx/executable_post-blocky.sh index 07dea9e1..af3000cb 100644 --- a/home/dot_local/bin/post-installx/executable_post-blocky.sh +++ b/home/dot_local/bin/post-installx/executable_post-blocky.sh @@ -2,6 +2,8 @@ # @file Blocky Configuration # @brief Copies over configuration (and service file, in the case of Linux) to the appropriate system location +set -euo pipefail + if command -v blocky > /dev/null; then if [ -d /Applications ] && [ -d /System ]; then ### macOS diff --git a/home/dot_local/bin/post-installx/executable_post-clamav.sh b/home/dot_local/bin/post-installx/executable_post-clamav.sh index c5fc098f..9fbca67e 100644 --- a/home/dot_local/bin/post-installx/executable_post-clamav.sh +++ b/home/dot_local/bin/post-installx/executable_post-clamav.sh @@ -2,12 +2,15 @@ # @file ClamAV Configuration # @brief Applies ClamAV configuration, updates its database, and configures background services +set -euo pipefail + if command -v freshclam > /dev/null; then ### Add freshclam.conf if [ -f "$HOME/.local/etc/clamav/freshclam.conf" ]; then sudo mkdir -p /usr/local/etc/clamav sudo cp -f "$HOME/.local/etc/clamav/freshclam.conf" /usr/local/etc/clamav/freshclam.conf - if [ -d "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav" ] && [ ! -f "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav/freshclam.conf" ]; then + if [ -d "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav" ] && [ ! -L "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav/freshclam.conf" ]; then + sudo rm -f "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav/freshclam.conf" ln -s /usr/local/etc/clamav/freshclam.conf "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav/freshclam.conf" fi fi @@ -16,7 +19,8 @@ if command -v freshclam > /dev/null; then if [ -f "$HOME/.local/etc/clamav/clamd.conf" ]; then sudo mkdir -p /usr/local/etc/clamav sudo cp -f "$HOME/.local/etc/clamav/clamd.conf" /usr/local/etc/clamav/clamd.conf - if [ -d "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav" ] && [ ! -f "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav/clamd.conf" ]; then + if [ -d "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav" ] && [ ! -L "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav/clamd.conf" ]; then + sudo rm -f "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav/clamd.conf" ln -s /usr/local/etc/clamav/clamd.conf "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/clamav/clamd.conf" fi fi diff --git a/home/dot_local/bin/post-installx/executable_post-cloudflared.sh b/home/dot_local/bin/post-installx/executable_post-cloudflared.sh index 24792240..b20b45e8 100644 --- a/home/dot_local/bin/post-installx/executable_post-cloudflared.sh +++ b/home/dot_local/bin/post-installx/executable_post-cloudflared.sh @@ -4,6 +4,8 @@ # @description # 1. Skips the deletion of a tunnel when it is currently in use +set -euo pipefail + if command -v cloudflared > /dev/null; then # Show warning message about ~/.cloudflared already existing if [ -d "$HOME/.cloudflared" ]; then diff --git a/home/dot_local/bin/post-installx/executable_post-docker-desktop.sh b/home/dot_local/bin/post-installx/executable_post-docker-desktop.sh index 307a0711..4f78992e 100644 --- a/home/dot_local/bin/post-installx/executable_post-docker-desktop.sh +++ b/home/dot_local/bin/post-installx/executable_post-docker-desktop.sh @@ -8,26 +8,18 @@ # be passed in as a secret (either via the encrypted secret method or passed in as an environment # variable). +set -euo pipefail + if command -v docker > /dev/null; then ### Acquire DOCKERHUB_TOKEN - DOCKERHUB_TOKEN_FILE="${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets/DOCKERHUB_TOKEN" - if [ -f "$DOCKERHUB_TOKEN_FILE" ]; then - logg info "Found DOCKERHUB_TOKEN in ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" - if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/age/chezmoi.txt" ]; then - logg info 'Decrypting DOCKERHUB_TOKEN token with Age encryption key' - DOCKERHUB_TOKEN="$(cat "$DOCKERHUB_TOKEN_FILE" | chezmoi decrypt)" - else - logg warn 'Age encryption key is missing from ~/.config/age/chezmoi.txt' - fi - else - logg warn "DOCKERHUB_TOKEN is missing from ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" - fi + get-secret --exists DOCKERHUB_TOKEN || exit 1 ### Acquire DOCKERHUB_USER if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml" ]; then DOCKERHUB_USER="$(yq '.data.user.docker.username' ~/.config/chezmoi/chezmoi.yaml)" else - logg info "${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml is missing which is required for populating the DOCKERHUB_USER" + logg error "${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml is missing which is required for populating the DOCKERHUB_USER" + exit 1 fi ### Launch Docker.app @@ -36,6 +28,7 @@ if command -v docker > /dev/null; then fi ### Pre-authenticate with DockerHub + DOCKERHUB_TOKEN="$(get-secret DOCKERHUB_TOKEN)" if [ -n "$DOCKERHUB_TOKEN" ] && [ -n "$DOCKERHUB_USER" ]; then logg info 'Headlessly authenticating with DockerHub registry' && echo "$DOCKERHUB_TOKEN" | docker login -u "$DOCKERHUB_USER" --password-stdin > /dev/null && logg success 'Successfully authenticated with DockerHub registry' fi diff --git a/home/dot_local/bin/post-installx/executable_post-easyengine.sh b/home/dot_local/bin/post-installx/executable_post-easyengine.sh index 9e54e54c..90de11f6 100644 --- a/home/dot_local/bin/post-installx/executable_post-easyengine.sh +++ b/home/dot_local/bin/post-installx/executable_post-easyengine.sh @@ -2,9 +2,14 @@ # @file EasyEngine # @brief Configures EasyEngine to use the CloudFlare API for configuring Let's Encrypt +set -euo pipefail + if command -v ee > /dev/null; then - if [ -n "$CLOUDFLARE_EMAIL" ] && [ -n "$CLOUDFLARE_API_KEY" ]; then - ee config set le-mail "$CLOUDFLARE_EMAIL" - ee config set cloudflare-api-key "$CLOUDFLARE_API_KEY" - fi + ### Ensure secrets + get-secret --exists CLOUDFLARE_EMAIL CLOUDFLARE_API_KEY + + ### Configure EasyEngine + logg info 'Configuring EasyEngine with CloudFlare automatic SSL insuance' + ee config set le-mail "$(get-secret CLOUDFLARE_EMAIL)" + ee config set cloudflare-api-key "$(get-secret CLOUDFLARE_API_KEY)" fi \ No newline at end of file diff --git a/home/dot_local/bin/post-installx/executable_post-endlessh.sh b/home/dot_local/bin/post-installx/executable_post-endlessh.sh index 76cafd5b..8e1b6716 100644 --- a/home/dot_local/bin/post-installx/executable_post-endlessh.sh +++ b/home/dot_local/bin/post-installx/executable_post-endlessh.sh @@ -2,14 +2,18 @@ # @file Endlessh Configuration # @brief Applies the Endlessh configuration and starts the service on Linux systems +set -euo pipefail + function configureEndlessh() { ### Update the service configuration file logg info 'Updating endlessh service configuration file' sudo sed -i 's/^.*#AmbientCapabilities=CAP_NET_BIND_SERVICE/AmbientCapabilities=CAP_NET_BIND_SERVICE/' /usr/lib/systemd/system/endlessh.service sudo sed -i 's/^.*PrivateUsers=true/#PrivateUsers=true/' /usr/lib/systemd/system/endlessh.service logg info 'Reloading systemd' && sudo systemctl daemon-reload + ### Update capabilities of `endlessh` logg info 'Updating capabilities of endlessh' && sudo setcap 'cap_net_bind_service=+ep' /usr/bin/endlessh + ### Restart / enable Endlessh logg info 'Enabling the endlessh service' && sudo systemctl enable endlessh logg info 'Restarting the endlessh service' && sudo systemctl restart endlessh diff --git a/home/dot_local/bin/post-installx/executable_post-envchain.sh b/home/dot_local/bin/post-installx/executable_post-envchain.sh index ebec2351..04e4dbca 100644 --- a/home/dot_local/bin/post-installx/executable_post-envchain.sh +++ b/home/dot_local/bin/post-installx/executable_post-envchain.sh @@ -10,19 +10,25 @@ # ## Secrets # # For more information about storing secrets like SSH keys and API keys, refer to our [Secrets documentation](https://install.doctor/docs/customization/secrets). +# +# ## TODO +# +# * Create seperate environments based on encrypted secret type (e.g. Allow `envchain cloudflare env` instead of `envchain default env` for everything) + +set -euo pipefail ### Import environment variables into `envchain` if command -v envchain > /dev/null; then if [ -f "$HOME/.config/age/chezmoi.txt" ]; then logg info 'Importing environment variables into the System keyring' - for file in {{ joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "*" }}; do - logg info "Adding $file to System keyring via envchain" - cat "$file" | chezmoi decrypt | envchain -s default "$(basename $file)" > /dev/null || logg info 'Importing "$(basename $file)" failed' - done + while read ENCRYPTED_FILE; do + logg info "Adding $ENCRYPTED_FILE to System keyring via envchain" + cat "$ENCRYPTED_FILE" | chezmoi decrypt | envchain -s default "$(basename $ENCRYPTED_FILE)" > /dev/null || logg info "Importing "$(basename $ENCRYPTED_FILE)" failed" + done< <(find "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" -type f -maxdepth 1 -mindepth 1) logg success "Added Chezmoi-managed secrets into System keyring via envchain" else logg warn 'Unable to import any variables into envchain because ~/.config/age/chezmoi.txt was not created by the secrets encryption process yet' fi else logg info 'envchain is not installed or it is not available in the PATH' -fi \ No newline at end of file +fi diff --git a/home/dot_local/bin/post-installx/executable_post-fail2ban.sh b/home/dot_local/bin/post-installx/executable_post-fail2ban.sh index 65014c5a..3bc4eb79 100644 --- a/home/dot_local/bin/post-installx/executable_post-fail2ban.sh +++ b/home/dot_local/bin/post-installx/executable_post-fail2ban.sh @@ -11,6 +11,8 @@ # # * [`fail2ban` configuration folder](https://github.com/megabyte-labs/install.doctor/tree/master/home/private_dot_ssh/fail2ban) +set -euo pipefail + if command -v fail2ban-client > /dev/null; then if [[ ! "$(test -d /proc && grep Microsoft /proc/version > /dev/null)" ]]; then if [ -f "$HOME/.ssh/fail2ban/jail.local" ]; then diff --git a/home/dot_local/bin/post-installx/executable_post-fig.sh b/home/dot_local/bin/post-installx/executable_post-fig.sh index 10c172f1..6dcdda45 100644 --- a/home/dot_local/bin/post-installx/executable_post-fig.sh +++ b/home/dot_local/bin/post-installx/executable_post-fig.sh @@ -2,9 +2,14 @@ # @file Fig Login # @brief Logs into Fig using the FIG_TOKEN +set -euo pipefail + if command -v fig > /dev/null; then - source ~/.config/shell/private.sh - fig login --token "$FIG_TOKEN" || logg info 'Fig login failed - User might already be logged in' + ### Ensure FIG_TOKEN + get-secret --exists FIG_TOKEN + + ### Login to Fig + fig login --token "$(get-secret FIG_TOKEN)" || logg info 'Fig login failed - User might already be logged in' else logg warn 'fig is not available in the PATH' fi diff --git a/home/dot_local/bin/post-installx/executable_post-firefox.sh b/home/dot_local/bin/post-installx/executable_post-firefox.sh index 39ad0636..b9a8e01c 100644 --- a/home/dot_local/bin/post-installx/executable_post-firefox.sh +++ b/home/dot_local/bin/post-installx/executable_post-firefox.sh @@ -43,6 +43,8 @@ # * [System-wide configurations](https://github.com/megabyte-labs/install.doctor/tree/master/home/dot_local/share/firefox) as well as the location of the `profile.ini` and some other configurations # * [User-specific configurations](https://github.com/megabyte-labs/install.doctor/blob/master/home/dot_config/firefox/user.js) added to all profiles except Factory +set -euo pipefail + function installFirefoxProfileConnector() { logg info 'Installing the Firefox Profile Connector' if command -v apt-get > /dev/null; then @@ -272,7 +274,7 @@ function firefoxSetup() { ### Install Firefox addons (using list declared in .chezmoidata.yaml) for SETTINGS_PROFILE in "profile.plugins" "profile.private"; do if [ -d "$SETTINGS_DIR/$SETTINGS_PROFILE" ]; then - for FIREFOX_PLUGIN in {{ list (.firefoxAddOns | toString | replace "[" "" | replace "]" "") | uniq | join " " }}; do + while read FIREFOX_PLUGIN; do logg info "Processing the $FIREFOX_PLUGIN Firefox add-on" PLUGIN_HTML="$(mktemp)" curl --silent "https://addons.mozilla.org/en-US/firefox/addon/$FIREFOX_PLUGIN/" > "$PLUGIN_HTML" @@ -310,7 +312,7 @@ function firefoxSetup() { else logg warn 'A null Firefox add-on ID was detected for '"$FIREFOX_PLUGIN"'' fi - done + done< <(yq '.firefoxAddOns[]' ~/.local/share/chezmoi/home/.chezmoidata.yaml) fi done fi diff --git a/home/dot_local/bin/post-installx/executable_post-github-runner.sh b/home/dot_local/bin/post-installx/executable_post-github-runner.sh index d4c5d92e..61f6c9d3 100644 --- a/home/dot_local/bin/post-installx/executable_post-github-runner.sh +++ b/home/dot_local/bin/post-installx/executable_post-github-runner.sh @@ -17,6 +17,8 @@ # # * [Secrets / Environment variables documentation](https://install.doctor/docs/customization/secrets) +set -euo pipefail + ### Check if GitHub runner is installed if [ -f "${XDG_DATA_HOME:-$HOME/.local/share}/github-runnerconfig.sh" ]; then if [ -f "${XDG_DATA_HOME:-$HOME/.local/share}/github-runner/.runner" ]; then @@ -40,10 +42,11 @@ if [ -f "${XDG_DATA_HOME:-$HOME/.local/share}/github-runnerconfig.sh" ]; then if command -v jq > /dev/null; then ### Acquire token logg info 'Acquiring runner token' - RUNNER_TOKEN="$(curl -sSL -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer $GITHUB_TOKEN" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/orgs/{{ .user.github.runnerOrg }}/actions/runners/registration-token | jq -r '.token')" + RUNNER_ORG="$(yq '.data.user.github.runnerOrg' "${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml")" + RUNNER_TOKEN="$(curl -sSL -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer $GITHUB_TOKEN" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/orgs/${RUNNER_ORG}/actions/runners/registration-token | jq -r '.token')" ### Generate the configuration - logg info 'Joining GitHub runner to https://github.com/{{ .user.github.runnerOrg }}' - "${XDG_DATA_HOME:-$HOME/.local/share}/github-runner/config.sh" --unattended --url https://github.com/{{ .user.github.runnerOrg }} --token "$RUNNER_TOKEN" --labels "$LABELS" || EXIT_CODE=$? + logg info "Joining GitHub runner to https://github.com/${RUNNER_ORG}" + "${XDG_DATA_HOME:-$HOME/.local/share}/github-runner/config.sh" --unattended --url https://github.com/${RUNNER_ORG} --token "$RUNNER_TOKEN" --labels "$LABELS" || EXIT_CODE=$? if [ -n "$EXIT_CODE" ]; then logg error 'GitHub runner configuration failed' && exit 1 fi diff --git a/home/dot_local/bin/post-installx/executable_post-gitomatic.sh b/home/dot_local/bin/post-installx/executable_post-gitomatic.sh index 55f9c68c..f41377e1 100644 --- a/home/dot_local/bin/post-installx/executable_post-gitomatic.sh +++ b/home/dot_local/bin/post-installx/executable_post-gitomatic.sh @@ -20,6 +20,8 @@ # * [Systemd Unit file](https://github.com/megabyte-labs/install.doctor/blob/master/home/dot_config/gitomatic/gitomatic.service.tmpl) # * [Helper script](https://github.com/megabyte-labs/install.doctor/blob/master/home/dot_local/bin/executable_gitomatic_service.tmpl +set -euo pipefail + if command -v gitomatic > /dev/null; then ### Copy bin to /usr/local/bin logg info "Copying $HOME/.local/bin/gitomatic-service to /usr/local/bin/gitomatic-service" && sudo cp -f "$HOME/.local/bin/gitomatic-service" /usr/local/bin/gitomatic-servic diff --git a/home/dot_local/bin/post-installx/executable_post-google-chrome.sh b/home/dot_local/bin/post-installx/executable_post-google-chrome.sh index 3a921383..34e97d40 100644 --- a/home/dot_local/bin/post-installx/executable_post-google-chrome.sh +++ b/home/dot_local/bin/post-installx/executable_post-google-chrome.sh @@ -24,6 +24,8 @@ # * [`managed.json`](https://github.com/megabyte-labs/install.doctor/blob/master/home/dot_config/chrome/managed.json) # * [`recommended.json`](https://github.com/megabyte-labs/install.doctor/blob/master/home/dot_config/chrome/recommended.json) +set -euo pipefail + function chromeSetUp() { ### Ensure Chrome policies directory is present logg info 'Processing policy directories for Chromium based browsers' @@ -63,7 +65,7 @@ function chromeSetUp() { fi ### Add extension JSON logg info "Adding Chrome extensions to $EXTENSION_DIR" - for EXTENSION in {{ list (.chromeExtensions | toString | replace "[" "" | replace "]" "") | uniq | join " " }}; do + while read EXTENSION; do logg info "Adding Chrome extension manifest ($EXTENSION)" if ! echo "$EXTENSION" | grep 'https://chrome.google.com/webstore/detail/' > /dev/null; then EXTENSION="https://chrome.google.com/webstore/detail/$EXTENSION" @@ -74,7 +76,7 @@ function chromeSetUp() { else cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/chrome/extension.json" "$EXTENSION_DIR/${EXTENSION_ID}.json" fi - done + done< <(yq '.chromeExtensions[]' "${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoidata.yaml") else logg info "$EXTENSION_DIR does not exist" fi diff --git a/home/dot_local/bin/post-installx/executable_post-juicefs.sh b/home/dot_local/bin/post-installx/executable_post-juicefs.sh index 6474b577..731b2908 100644 --- a/home/dot_local/bin/post-installx/executable_post-juicefs.sh +++ b/home/dot_local/bin/post-installx/executable_post-juicefs.sh @@ -14,6 +14,8 @@ # When creating the four volumes in the [JuiceFS console](https://juicefs.com/console/), it is important that you name the volumes using # these four volume names. +set -euo pipefail + MOUNT_FOLDER="/mnt" UPDATE_FSTAB="--update-fstab" if [ -d /Applications ] && [ -d /System ]; then diff --git a/home/dot_local/bin/post-installx/executable_post-keybase.sh b/home/dot_local/bin/post-installx/executable_post-keybase.sh index 6a65b33a..e3f33e11 100644 --- a/home/dot_local/bin/post-installx/executable_post-keybase.sh +++ b/home/dot_local/bin/post-installx/executable_post-keybase.sh @@ -4,6 +4,8 @@ # @description # This script ensures Keybase utilizes a configuration that, by default, adds a security fix. +set -euo pipefail + if command -v keybase > /dev/null; then KEYBASE_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/keybase/config.json" if [ -f "$KEYBASE_CONFIG" ]; then diff --git a/home/dot_local/bin/post-installx/executable_post-mise.sh b/home/dot_local/bin/post-installx/executable_post-mise.sh index 5f87d102..d0c7c0d6 100644 --- a/home/dot_local/bin/post-installx/executable_post-mise.sh +++ b/home/dot_local/bin/post-installx/executable_post-mise.sh @@ -2,6 +2,8 @@ # @file Mise Install / Tweaks # @brief Performs initial install of mise targets and applies tweaks such as symlinking mise's Java version with the system Java target on macOS +set -euo pipefail + if command -v mise > /dev/null; then logg info 'Running mise install' && mise install diff --git a/home/dot_local/bin/post-installx/executable_post-netdata.sh b/home/dot_local/bin/post-installx/executable_post-netdata.sh index 9125e2ea..14e8fb71 100644 --- a/home/dot_local/bin/post-installx/executable_post-netdata.sh +++ b/home/dot_local/bin/post-installx/executable_post-netdata.sh @@ -9,6 +9,8 @@ # This script installs additional alerts and enables notifications if Netdata is installed. Email notifications are configured # using the provided primary email address. If the OS is Debian based, Netdata shows the number of CVEs in currently installed packages. +set -euo pipefail + ensureNetdataOwnership() { ### Ensure /usr/local/var/lib/netdata/cloud.d is owned by user if [ -d /usr/local/var/lib/netdata ]; then @@ -22,6 +24,9 @@ ensureNetdataOwnership() { fi } +### Ensure secrets are available +get-secret --exists NETDATA_ROOM NETDATA_TOKEN + ### Claim the instance with Netdata Cloud if command -v netdata-claim.sh > /dev/null; then ### Add user / group with script in ~/.local/bin/add-usergroup, if it is available @@ -32,7 +37,7 @@ if command -v netdata-claim.sh > /dev/null; then ### Ensure ownership ensureNetdataOwnership ### netdata-claim.sh must be run as netdata user - sudo -H -u netdata bash -c 'export NETDATA_ROOM="{{- if (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "NETDATA_ROOM")) -}}{{- includeTemplate "secrets/NETDATA_ROOM" | decrypt | trim -}}{{- else -}}{{- env "NETDATA_ROOM" -}}{{- end -}}" && export NETDATA_TOKEN="{{- if (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "NETDATA_TOKEN")) -}}{{- includeTemplate "secrets/NETDATA_TOKEN" | decrypt | trim -}}{{- else -}}{{- env "NETDATA_TOKEN" -}}{{- end -}}" && yes | netdata-claim.sh -token="$NETDATA_TOKEN" -rooms="$NETDATA_ROOM" -url="https://app.netdata.cloud"' + sudo -H -u netdata bash -c "yes | netdata-claim.sh -token="$(get-secret NETDATA_TOKEN)" -rooms="$(get-secret NETDATA_ROOM)" -url="https://app.netdata.cloud"" ### Kernel optimizations # These are mentioned while installing via the kickstart.sh script method. We are using Homebrew for the installation though. # Assuming these optimizations do not cause any harm. diff --git a/home/dot_local/bin/post-installx/executable_post-nginx.sh b/home/dot_local/bin/post-installx/executable_post-nginx.sh index 9f0c1e96..cd2407ca 100644 --- a/home/dot_local/bin/post-installx/executable_post-nginx.sh +++ b/home/dot_local/bin/post-installx/executable_post-nginx.sh @@ -11,6 +11,8 @@ # * [NGINX Amplify login](https://amplify.nginx.com/login) # * [NGINX Amplify documentation](https://docs.nginx.com/nginx-amplify/#) +set -euo pipefail + if command -v nginx > /dev/null; then if [ -d /Applications ] && [ -d /System ]; then ### macOS @@ -19,21 +21,17 @@ if command -v nginx > /dev/null; then else ### Linux NGINX_CONFIG_DIR=/etc/nginx - NGINX_AMPLIFY_API_KEY_FILE="${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets/NGINX_AMPLIFY_API_KEY" - if [ -f "$NGINX_AMPLIFY_API_KEY_FILE" ]; then - logg info "Found NGINX_AMPLIFY_API_KEY in ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" - if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/age/chezmoi.txt" ]; then - logg info 'Decrypting NGINX_AMPLIFY_API_KEY token with Age encryption key' - logg info 'Downloading the NGINX Amplify installer script' - TMP="$(mktemp)" - curl -sSL https://github.com/nginxinc/nginx-amplify-agent/raw/master/packages/install.sh > "$TMP" - logg info 'Running the NGINX Amplify setup script' - API_KEY="$(cat "$NGINX_AMPLIFY_API_KEY_FILE" | chezmoi decrypt)" sh "$TMP" - else - logg warn 'Age encryption key is missing from ~/.config/age/chezmoi.txt' - fi + if get-secret --exists NGINX_AMPLIFY_API_KEY; then + ### Download NGINX Amplify script + logg info 'Downloading the NGINX Amplify installer script' + TMP="$(mktemp)" + curl -sSL https://github.com/nginxinc/nginx-amplify-agent/raw/master/packages/install.sh > "$TMP" + + ### NGINX Amplify registration + logg info 'Running the NGINX Amplify setup script' + API_KEY="$(get-secret NGINX_AMPLIFY_API_KEY)" sh "$TMP" else - logg warn "NGINX_AMPLIFY_API_KEY is missing from ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" + logg warn "Skipping NGINX Amplify setup because the NGINX_AMPLIFY_API_KEY was unavailable" fi fi logg info "Ensuring $NGINX_CONFIG_DIR is present" && sudo mkdir -p "$NGINX_CONFIG_DIR" @@ -42,9 +40,8 @@ if command -v nginx > /dev/null; then if [ -d /Applications ] && [ -d /System ]; then ### macOS if [ -d "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/nginx" ] && [ ! -L "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/nginx" ]; then - logg info "Removing directory at ${HOMEBREW_PREFIX:-/opt/homebrew}/etc/nginx" - sudo rm -rf "{HOMEBREW_PREFIX:-/opt/homebrew}/etc/nginx" - logg info "Symlinking /usr/local/etc/nginx to ${HOMEBREW_PREFIX:-/opt/homebrew}/etc/nginx" + logg info "Removing ${HOMEBREW_PREFIX:-/opt/homebrew}/etc/nginx directory and its contents in favor of symlink to /usr/local/etc/nginx" + rm -rf "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/nginx" ln -s /usr/local/etc/nginx "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/nginx" else logg info "Skipping symlinking of /usr/local/etc/nginx to ${HOMEBREW_PREFIX:-/opt/homebrew}/etc/nginx because directory symlink already appears to be there" diff --git a/home/dot_local/bin/post-installx/executable_post-ntfy.sh b/home/dot_local/bin/post-installx/executable_post-ntfy.sh index c2a0005b..5fbee070 100644 --- a/home/dot_local/bin/post-installx/executable_post-ntfy.sh +++ b/home/dot_local/bin/post-installx/executable_post-ntfy.sh @@ -2,6 +2,8 @@ # @file NTFY Dependencies # @brief Ensures branding assets and sound files are in system locations. Also, ensures system dependencies are installed +set -euo pipefail + if command -v ntfy > /dev/null; then ### Branding assets logg info 'Ensuring branding assets are in expected place for ntfy' diff --git a/home/dot_local/bin/post-installx/executable_post-plymouth.sh b/home/dot_local/bin/post-installx/executable_post-plymouth.sh index 6efa8040..af535b5c 100644 --- a/home/dot_local/bin/post-installx/executable_post-plymouth.sh +++ b/home/dot_local/bin/post-installx/executable_post-plymouth.sh @@ -4,6 +4,8 @@ # @description # This script installs Plymouth and then configures it to use our custom Betelgeuse theme. +set -euo pipefail + ### Create /etc/plymouth/plymouthd.conf if [ -f /etc/plymouth/plymouthd.conf ]; then ### Back up original plymouthd.conf @@ -14,20 +16,20 @@ if [ -f /etc/plymouth/plymouthd.conf ]; then ### Create new plymouthd.conf logg info 'Populating the /etc/plymouth/plymouthd.conf file' echo "[Daemon]" | sudo tee /etc/plymouth/plymouthd.conf > /dev/null - echo "Theme={{ .theme }}" | sudo tee -a /etc/plymouth/plymouthd.conf > /dev/null + echo "Theme=Betelgeuse" | sudo tee -a /etc/plymouth/plymouthd.conf > /dev/null echo "ShowDelay=1" | sudo tee -a /etc/plymouth/plymouthd.conf > /dev/null fi ### Apply update-alternatives if command -v update-alternatives > /dev/null; then - if [ -f "/usr/local/share/plymouth/themes/{{ .theme }}/{{ .theme }}.plymouth" ]; then - sudo update-alternatives --install /usr/share/plymouth/themes/default.plymouth default.plymouth "/usr/local/share/plymouth/themes/{{ .theme }}/{{ .theme }}.plymouth" 100 + if [ -f "/usr/local/share/plymouth/themes/Betelgeuse/Betelgeuse.plymouth" ]; then + sudo update-alternatives --install /usr/share/plymouth/themes/default.plymouth default.plymouth "/usr/local/share/plymouth/themes/Betelgeuse/Betelgeuse.plymouth" 100 logg success 'Installed default.plymouth' # Required sometimes - sudo update-alternatives --set default.plymouth "/usr/local/share/plymouth/themes/{{ .theme }}/{{ .theme }}.plymouth" + sudo update-alternatives --set default.plymouth "/usr/local/share/plymouth/themes/Betelgeuse/Betelgeuse.plymouth" logg success 'Set default.plymouth' else - logg warn "/usr/local/share/plymouth/themes/{{ .theme }}/{{ .theme }}.plymouth does not exist!" + logg warn "/usr/local/share/plymouth/themes/Betelgeuse/Betelgeuse.plymouth does not exist!" fi else logg warn 'update-alternatives is not available' @@ -47,14 +49,14 @@ fi # fi ### Symlink /usr/local/share/plymouth/themes to /usr/share/plymouth/themes -if [ ! -d '/usr/share/plymouth/themes/{{ .theme }}' ]; then - logg info 'Symlinking /usr/local/share/plymouth/themes/{{ .theme }} to /usr/share/plymouth/themes/{{ .theme }}' - sudo ln -s '/usr/local/share/plymouth/themes/{{ .theme }}' '/usr/share/plymouth/themes/{{ .theme }}' +if [ ! -d '/usr/share/plymouth/themes/Betelgeuse' ]; then + logg info 'Symlinking /usr/local/share/plymouth/themes/Betelgeuse to /usr/share/plymouth/themes/Betelgeuse' + sudo ln -s '/usr/local/share/plymouth/themes/Betelgeuse' '/usr/share/plymouth/themes/Betelgeuse' fi ### Set default Plymouth theme if command -v plymouth-set-default-theme > /dev/null; then - sudo plymouth-set-default-theme -R '{{ .theme }}' || EXIT_CODE=$? + sudo plymouth-set-default-theme -R 'Betelgeuse' || EXIT_CODE=$? if [ -n "$EXIT_CODE" ]; then logg warn 'There may have been an issue while setting the Plymouth default theme with plymouth-set-default-theme' else @@ -66,12 +68,12 @@ fi ### Apply update-alternatives (again - required sometimes) if command -v update-alternatives > /dev/null; then - if [ -f "/usr/local/share/plymouth/themes/{{ .theme }}/{{ .theme }}.plymouth" ]; then + if [ -f "/usr/local/share/plymouth/themes/Betelgeuse/Betelgeuse.plymouth" ]; then # Required sometimes - sudo update-alternatives --set default.plymouth "/usr/local/share/plymouth/themes/{{ .theme }}/{{ .theme }}.plymouth" + sudo update-alternatives --set default.plymouth "/usr/local/share/plymouth/themes/Betelgeuse/Betelgeuse.plymouth" logg success 'Set default.plymouth (second time is required sometimes)' else - logg warn "/usr/local/share/plymouth/themes/{{ .theme }}/{{ .theme }}.plymouth does not exist!" + logg warn "/usr/local/share/plymouth/themes/Betelgeuse/Betelgeuse.plymouth does not exist!" fi else logg warn 'update-alternatives is not available' diff --git a/home/dot_local/bin/post-installx/executable_post-postfix.sh b/home/dot_local/bin/post-installx/executable_post-postfix.sh index d9f6a6c9..5761584d 100644 --- a/home/dot_local/bin/post-installx/executable_post-postfix.sh +++ b/home/dot_local/bin/post-installx/executable_post-postfix.sh @@ -10,19 +10,7 @@ # cat ~/.bashrc | mail -s "My subject" name@email.com # ``` -### Acquire SENDGRID_API_KEY -SENDGRID_API_KEY_FILE="${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets/SENDGRID_API_KEY" -if [ -f "$SENDGRID_API_KEY_FILE" ]; then - logg info "Found SENDGRID_API_KEY in ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" - if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/age/chezmoi.txt" ]; then - logg info 'Decrypting SENDGRID_API_KEY token with Age encryption key' - SENDGRID_API_KEY="$(cat "$SENDGRID_API_KEY_FILE" | chezmoi decrypt)" - else - logg warn 'Age encryption key is missing from ~/.config/age/chezmoi.txt' - fi -else - logg warn "SENDGRID_API_KEY is missing from ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" -fi +set -euo pipefail ### Acquire PUBLIC_SERVICES_DOMAIN and PRIMARY_EMAIL if command -v yq > /dev/null; then @@ -36,9 +24,8 @@ else logg warn 'yq is not installed on the system and is required for populating the PUBLIC_SERVICES_DOMAIN and PRIMARY_EMAIL' fi - ### Setup Postfix if SENDGRID_API_KEY is retrieved -if [ -n "$SENDGRID_API_KEY" ] && [ "$SENDGRID_API_KEY" != "" ]; then +if get-secret --exists SENDGRID_API_KEY; then if command -v postfix > /dev/null; then ### Ensure dependencies are installed if command -v apt-get > /dev/null; then diff --git a/home/dot_local/bin/post-installx/executable_post-privoxy.sh b/home/dot_local/bin/post-installx/executable_post-privoxy.sh index e65bb43f..8f667cd6 100644 --- a/home/dot_local/bin/post-installx/executable_post-privoxy.sh +++ b/home/dot_local/bin/post-installx/executable_post-privoxy.sh @@ -13,6 +13,8 @@ # # * [Privoxy configuration](https://github.com/megabyte-labs/install.doctor/tree/master/home/dot_config/privoxy/config) +set -euo pipefail + ### Configure variables if [ -d /Applications ] && [ -d /System ]; then ### macOS diff --git a/home/dot_local/bin/post-installx/executable_post-rclone.sh b/home/dot_local/bin/post-installx/executable_post-rclone.sh index 18315c4e..9ebc4bab 100644 --- a/home/dot_local/bin/post-installx/executable_post-rclone.sh +++ b/home/dot_local/bin/post-installx/executable_post-rclone.sh @@ -8,7 +8,7 @@ # # This script sets up Rclone to provide several folders that are synchronized with S3-compliant buckets (using CloudFlare R2 by default). # The script ensures required directories are created and that proper permissions are applied. This script will only run if `rclone` is -# available in the `PATH`. It also requires the user to provide `CLOUDFLARE_R2_ID` and `CLOUDFLARE_R2_SECRET` as either environment variables +# available in the `PATH`. It also requires the user to provide `CLOUDFLARE_R2_SECRET` and `CLOUDFLARE_R2_SECRET` as either environment variables # or through the encrypted repository-fork-housed method detailed in the [Secrets documentation](https://install.doctor/docs/customization/secrets). # # ## Mounts @@ -44,81 +44,193 @@ # * [Rclone mount script](https://github.com/megabyte-labs/install.doctor/tree/master/home/dot_local/bin/executable_rclone-mount) # * [Rclone default configurations](https://github.com/megabyte-labs/install.doctor/tree/master/home/dot_config/rclone) # * [Rclone documentation](https://rclone.org/docs/) -if command -v rclone > /dev/null; then - {{- if and (or (and (stat (joinPath .host.home ".config" "age" "chezmoi.txt")) (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "CLOUDFLARE_R2_ID"))) (env "CLOUDFLARE_R2_ID")) (or (and (stat (joinPath .host.home ".config" "age" "chezmoi.txt")) (stat (joinPath .chezmoi.sourceDir ".chezmoitemplates" "secrets" "CLOUDFLARE_R2_SECRET"))) (env "CLOUDFLARE_R2_SECRET")) (ne .user.cloudflare.r2 "") }} - logg info 'Removing ~/.config/rclone/rclone.conf Install Doctor managed block' - CONFIG_FILE="${XDG_CONFIG_HOME:-$HOME/.config}/rclone/rclone.conf" - if cat "$CONFIG_FILE" | grep '# INSTALL DOCTOR MANAGED S3 START' > /dev/null; then - # TODO: Remove old block - START_LINE="$(echo `grep -n -m 1 "# INSTALL DOCTOR MANAGED S3 START" "$CONFIG_FILE" | cut -f1 -d ":"`)" - END_LINE="$(echo `grep -n -m 1 "# INSTALL DOCTOR MANAGED S3 END" "$CONFIG_FILE" | cut -f1 -d ":"`)" - if command -v gsed > /dev/null; then - gsed -i "$START_LINE,${END_LINE}d" "$CONFIG_FILE" > /dev/null + +set -euo pipefail + +### Acquire CLOUDFLARE_R2_ID +if [ -z "$CLOUDFLARE_R2_ID" ]; then + CLOUDFLARE_R2_ID_FILE="${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets/CLOUDFLARE_R2_ID" + if [ -f "$CLOUDFLARE_R2_ID_FILE" ]; then + logg info "Found CLOUDFLARE_R2_ID in ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" + if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/age/chezmoi.txt" ]; then + logg info 'Decrypting CLOUDFLARE_R2_ID token with Age encryption key' + CLOUDFLARE_R2_ID="$(cat "$CLOUDFLARE_R2_ID_FILE" | chezmoi decrypt)" else - sed -i "$START_LINE,${END_LINE}d" "$CONFIG_FILE" > /dev/null + logg warn 'Age encryption key is missing from ~/.config/age/chezmoi.txt' + exit 1 fi + else + logg warn "CLOUDFLARE_R2_ID is missing from ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" + exit 1 fi - logg info 'Adding ~/.config/rclone/rclone.conf INSTALL DOCTOR managed block' - sudo tee -a "$CONFIG_FILE" > /dev/null < /dev/null; then + R2_ENDPOINT="$(yq '.data.user.cloudflare.r2' "${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/chezmoi.yaml")" + if [ "$R2_ENDPOINT" != 'null' ]; then + logg info 'Removing ~/.config/rclone/rclone.conf Install Doctor managed block' + CONFIG_FILE="${XDG_CONFIG_HOME:-$HOME/.config}/rclone/rclone.conf" + if cat "$CONFIG_FILE" | grep '# INSTALL DOCTOR MANAGED S3 START' > /dev/null; then + # TODO: Remove old block + START_LINE="$(echo `grep -n -m 1 "# INSTALL DOCTOR MANAGED S3 START" "$CONFIG_FILE" | cut -f1 -d ":"`)" + END_LINE="$(echo `grep -n -m 1 "# INSTALL DOCTOR MANAGED S3 END" "$CONFIG_FILE" | cut -f1 -d ":"`)" + if command -v gsed > /dev/null; then + gsed -i "$START_LINE,${END_LINE}d" "$CONFIG_FILE" > /dev/null + else + sed -i "$START_LINE,${END_LINE}d" "$CONFIG_FILE" > /dev/null + fi + fi + logg info 'Adding ~/.config/rclone/rclone.conf INSTALL DOCTOR managed block' + tee -a "$CONFIG_FILE" > /dev/null < /dev/null; then sudo add-usergroup rclone rclone sudo add-usergroup "$USER" rclone fi + + ### User config file permissions + sudo chmod -f 600 "$CONFIG_FILE" + sudo chown -f "$USER:rclone" "$CONFIG_FILE" + + ### Setup /var/cache/rclone + logg info 'Ensuring /var/cache/rclone exists' + sudo mkdir -p /var/cache/rclone + sudo chmod 750 /var/cache/rclone sudo chown -Rf rclone:rclone /var/cache/rclone + + ### Setup /var/log/rclone logg info 'Ensuring /var/log/rclone exists' sudo mkdir -p /var/log/rclone sudo chmod 750 /var/log/rclone sudo chown -Rf rclone:rclone /var/log/rclone + + ### Add rclone-mount to /usr/local/bin logg info 'Adding ~/.local/bin/rclone-mount to /usr/local/bin' sudo cp -f "$HOME/.local/bin/rclone-mount" /usr/local/bin/rclone-mount sudo chmod +x /usr/local/bin/rclone-mount + + ### Setup /etc/rcloneignore logg info 'Adding ~/.config/rclone/rcloneignore to /etc/rcloneignore' sudo cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/rclone/rcloneignore" /etc/rcloneignore sudo chown -Rf rclone:rclone /etc/rcloneignore sudo chmod 640 /etc/rcloneignore + + ### Setup /etc/rclone.conf logg info 'Adding ~/.config/rclone/system-rclone.conf to /etc/rclone.conf' sudo cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/rclone/system-rclone.conf" /etc/rclone.conf sudo chown -Rf rclone:rclone /etc/rclone.conf sudo chmod 600 /etc/rclone.conf + if [ -d /Applications ] && [ -d /System ]; then ### Enable Rclone mounts logg info 'Ensuring Rclone mount-on-reboot definitions are in place' - if [ -f "$HOME/Library/LaunchDaemons/rclone.private.plist" ] && [ ! -f "/Library/LaunchDaemons/rclone.private.plist" ]; then - logg info 'Adding /Volumes/Private as S3 bucket mount, enabled at boot' - sudo mkdir -p /Library/LaunchDaemons - sudo cp -f "$HOME/Library/LaunchDaemons/rclone.private.plist" '/Library/LaunchDaemons/rclone.private.plist' - sudo launchctl load '/Library/LaunchDaemons/rclone.private.plist' && logg success 'launchctl load successful' + sudo mkdir -p /Library/LaunchDaemons + + ### rclone.private.plist + sudo cp -f "$HOME/Library/LaunchDaemons/rclone.private.plist" '/Library/LaunchDaemons/rclone.private.plist' + logg info 'Ensuring rclone.private.plist service is started' + if sudo launchctl list | grep 'rclone.private.plist' > /dev/null; then + logg info 'Unloading previous rclone.private.plist configuration' + sudo launchctl unload /Library/LaunchDaemons/rclone.private.plist fi - if [ -f "$HOME/Library/LaunchDaemons/rclone.public.plist" ] && [ ! -f "/Library/LaunchDaemons/rclone.public.plist" ]; then - logg info 'Adding /Volumes/Public as S3 bucket mount, enabled at boot' - sudo mkdir -p /Library/LaunchDaemons - sudo cp -f "$HOME/Library/LaunchDaemons/rclone.public.plist" '/Library/LaunchDaemons/rclone.public.plist' - sudo launchctl load '/Library/LaunchDaemons/rclone.public.plist' && logg success 'launchctl load successful' + logg info 'Starting up rclone.private.plist configuration' + sudo launchctl load -w /Library/LaunchDaemons/rclone.private.plist + + ### rclone.public.plist + sudo cp -f "$HOME/Library/LaunchDaemons/rclone.public.plist" '/Library/LaunchDaemons/rclone.public.plist' + logg info 'Ensuring rclone.public.plist service is started' + if sudo launchctl list | grep 'rclone.public.plist' > /dev/null; then + logg info 'Unloading previous rclone.public.plist configuration' + sudo launchctl unload /Library/LaunchDaemons/rclone.public.plist fi - if [ -f "$HOME/Library/LaunchDaemons/rclone.user.plist" ] && [ ! -f "/Library/LaunchDaemons/rclone.user.plist" ]; then - logg info "Adding /Volumes/User-$USER as S3 bucket mount, enabled at boot" - sudo mkdir -p /Library/LaunchDaemons - sudo cp -f "$HOME/Library/LaunchDaemons/rclone.user.plist" '/Library/LaunchDaemons/rclone.user.plist' - sudo launchctl load '/Library/LaunchDaemons/rclone.user.plist' && logg success 'launchctl load successful' + logg info 'Starting up rclone.public.plist configuration' + sudo launchctl load -w /Library/LaunchDaemons/rclone.public.plist + + ### rclone.user.plist + sudo cp -f "$HOME/Library/LaunchDaemons/rclone.user.plist" '/Library/LaunchDaemons/rclone.user.plist' + logg info 'Ensuring rclone.user.plist service is started' + if sudo launchctl list | grep 'rclone.user.plist' > /dev/null; then + logg info 'Unloading previous rclone.user.plist configuration' + sudo launchctl unload /Library/LaunchDaemons/rclone.user.plist fi + logg info 'Starting up rclone.user.plist configuration' + sudo launchctl load -w "$HOME/Library/LaunchDaemons/rclone.user.plist" elif [ -d /etc/systemd/system ]; then find "${XDG_CONFIG_HOME:-$HOME/.config}/rclone/system" -mindepth 1 -maxdepth 1 -type f | while read RCLONE_SERVICE; do ### Add systemd service file @@ -126,17 +238,20 @@ EOT FILENAME="$(basename "$RCLONE_SERVICE")" SERVICE_ID="$(echo "$FILENAME" | sed 's/.service//')" sudo cp -f "$RCLONE_SERVICE" "/etc/systemd/system/$(basename "$RCLONE_SERVICE")" + ### Ensure mount folder is created logg info "Ensuring /mnt/$SERVICE_ID is created with proper permissions" sudo mkdir -p "/mnt/$SERVICE_ID" sudo chmod 750 "/mnt/$SERVICE_ID" + ### Enable / restart the service logg info "Enabling / restarting the $SERVICE_ID S3 service" sudo systemctl enable "$SERVICE_ID" sudo systemctl restart "$SERVICE_ID" done + ### Add user Rclone mount - logg info 'Adding user S3 rclone mount (available at ~/.local/mnt/s3)' + logg info 'Adding user S3 rclone mount (available at ~/Cloud/User and /Volumes/User)' sudo cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/rclone/s3-user.service" "/etc/systemd/system/s3-${USER}.service" logg info 'Enabling / restarting the S3 user mount' sudo systemctl enable "s3-${USER}" diff --git a/home/dot_local/bin/post-installx/executable_post-rkhunter.sh b/home/dot_local/bin/post-installx/executable_post-rkhunter.sh index 48c138c6..ae493649 100644 --- a/home/dot_local/bin/post-installx/executable_post-rkhunter.sh +++ b/home/dot_local/bin/post-installx/executable_post-rkhunter.sh @@ -2,6 +2,8 @@ # @file rkhunter configuration # @brief This script applies the rkhunter integration and updates it as well +set -euo pipefail + if command -v rkhunter > /dev/null; then if [ -d /Applications ] && [ -d /System ]; then ### macOS diff --git a/home/dot_local/bin/post-installx/executable_post-samba.sh b/home/dot_local/bin/post-installx/executable_post-samba.sh index bfda52b1..196029bb 100644 --- a/home/dot_local/bin/post-installx/executable_post-samba.sh +++ b/home/dot_local/bin/post-installx/executable_post-samba.sh @@ -47,6 +47,9 @@ # # * [Default Samba configuration](https://github.com/megabyte-labs/install.doctor/tree/master/home/dot_local/samba/config.tmpl) # * [Secrets / Environment variables documentation](https://install.doctor/docs/customization/secrets) + +set -euo pipefail + ### Configure Samba server if command -v smbd > /dev/null; then # Add user / group with script in ~/.local/bin/add-usergroup, if it is available @@ -63,26 +66,67 @@ if command -v smbd > /dev/null; then fi PRIVATE_SHARE="/$MNT_FOLDER/Private" PUBLIC_SHARE="/$MNT_FOLDER/Public" + + ### Private share logg info "Ensuring $PRIVATE_SHARE is created" sudo mkdir -p "$PRIVATE_SHARE" sudo chmod 750 "$PRIVATE_SHARE" sudo chown -Rf root:rclone "$PRIVATE_SHARE" + + ### Public share logg info "Ensuring $PUBLIC_SHARE is created" sudo mkdir -p "$PUBLIC_SHARE" sudo chmod 755 "$PUBLIC_SHARE" sudo chown -Rf root:rclone "$PUBLIC_SHARE" - logg info "Ensuring $HOME/Public is created" - mkdir -p "$HOME/Public" - chmod 755 "$HOME/Public" - chown -Rf "$USER":rclone "$HOME/Public" + + ### User share + logg info "Ensuring $HOME/Shared is created" + mkdir -p "$HOME/Shared" + chmod 755 "$HOME/Shared" + chown -Rf "$USER":rclone "$HOME/Shared" + ### Copy the Samba server configuration file if [ -d /Applications ] && [ -d /System ]; then - sudo sharing -a "$PRIVATE_SHARE" -S "Private (System)" -n "Private (System)" -g 000 -s 001 -E 1 -R 1 && logg success "Configured $PRIVATE_SHARE as a private Samba share" || logg info 'sharing command failed - it is likely that the share was already set up' - sudo sharing -a "$PUBLIC_SHARE" -S "Public (System)" -n "Public (System)" -g 001 -s 001 -E 1 -R 0 && logg success "Configured $PUBLIC_SHARE as a public Samba share" || logg info 'sharing command failed - it is likely that the share was already set up' - sudo sharing -a "$HOME/Public" -S "Public (User)" -n "Public (User)" -g 001 -s 001 -E 1 -R 0 && logg success "Configured $HOME/Public as a public Samba share" || logg info 'sharing command failed - it is likely that the share was already set up' + ### System Private Samba Share + if SMB_OUTPUT=$(sudo sharing -a "$PRIVATE_SHARE" -S "Private (System)" -n "Private (System)" -g 000 -s 001 -E 1 -R 1); then + logg success "Configured $PRIVATE_SHARE as a private Samba share" + else + if echo $SMB_OUTPUT | grep 'smb name already exists' > /dev/null; then + logg info "$PRIVATE_SHARE Samba share already exists" + else + logg error 'An error occurred while running sudo sharing -a "$PRIVATE_SHARE" -S "Private (System)" -n "Private (System)" -g 000 -s 001 -E 1 -R 1' + echo "$SMB_OUTPUT" + fi + fi + + ### System Public Samba Share + if SMB_OUTPUT=$(sudo sharing -a "$PUBLIC_SHARE" -S "Public (System)" -n "Public (System)" -g 001 -s 001 -E 1 -R 0); then + logg success "Configured $PUBLIC_SHARE as a system public Samba share" + else + if echo $SMB_OUTPUT | grep 'smb name already exists' > /dev/null; then + logg info "$PUBLIC_SHARE Samba share already exists" + else + logg error 'An error occurred while running sudo sharing -a "$PUBLIC_SHARE" -S "Public (System)" -n "Public (System)" -g 001 -s 001 -E 1 -R 0' + echo "$SMB_OUTPUT" + fi + fi + + ### User Shared Samba Share + if SMB_OUTPUT=$(sudo sharing -a "$HOME/Shared" -S "Shared (User)" -n "Shared (User)" -g 001 -s 001 -E 1 -R 0); then + logg success "Configured $HOME/Shared as a user-scoped Samba share" + else + if echo $SMB_OUTPUT | grep 'smb name already exists' > /dev/null; then + logg info "$HOME/Shared Samba share already exists" + else + logg error 'An error occurred while running sudo sharing -a "$HOME/Shared" -S "Shared (User)" -n "Shared (User)" -g 001 -s 001 -E 1 -R 0' + echo "$SMB_OUTPUT" + fi + fi else + ### Copy Samba configuration logg info "Copying Samba server configuration to /etc/samba/smb.conf" sudo cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/samba/config" "/etc/samba/smb.conf" + ### Reload configuration file changes logg info 'Reloading the smbd config' smbcontrol smbd reload-config diff --git a/home/dot_local/bin/post-installx/executable_post-sftpgo.sh b/home/dot_local/bin/post-installx/executable_post-sftpgo.sh index a202d794..e6b9e22a 100644 --- a/home/dot_local/bin/post-installx/executable_post-sftpgo.sh +++ b/home/dot_local/bin/post-installx/executable_post-sftpgo.sh @@ -2,16 +2,23 @@ # @file sftpgo configuration # @brief This script copies over the required configuration files for sftpgo and then initializes sftpgo +set -euo pipefail + if command -v sftpgo > /dev/null; then + ### Copy configuration file sudo mkdir -p /usr/local/etc/sftpgo logg info 'Copying over sftpgo configuration to /usr/local/etc/sftpgo/sftpgo.json' sudo cp -f "$HOME/.local/etc/sftpgo/sftpgo.json" /usr/local/etc/sftpgo/sftpgo.json + + ### Copy branding assets / banner logg info 'Copying over sftpgo branding assets' sudo cp -f "$HOME/.local/etc/sftpgo/banner" /usr/local/etc/sftpgo/banner sudo mkdir -p /usr/local/etc/branding sudo cp -f "$HOME/.local/etc/branding/favicon.ico" /usr/local/etc/branding/favicon.ico sudo cp -f "$HOME/.local/etc/branding/logo-color-256x256.png" /usr/local/etc/branding/logo-color-256x256.png sudo cp -f "$HOME/.local/etc/branding/logo-color-900x900.png" /usr/local/etc/branding/logo-color-900x900.png + + ### Initialize logg info 'Running sudo sftpgo initprovider' sudo sftpgo initprovider else diff --git a/home/dot_local/bin/post-installx/executable_post-tabby.sh b/home/dot_local/bin/post-installx/executable_post-tabby.sh index 111cc3af..7f672e47 100644 --- a/home/dot_local/bin/post-installx/executable_post-tabby.sh +++ b/home/dot_local/bin/post-installx/executable_post-tabby.sh @@ -41,6 +41,8 @@ # * [Tabby plugins `package.json`](https://github.com/megabyte-labs/install.doctor/tree/master/home/dot_config/tabby/plugins/package.json) # * [Secrets / Environment variables documentation](https://install.doctor/docs/customization/secrets) which details how to store your Tabby configuration in as an encrypted file +set -euo pipefail + if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/tabby/plugins/package.json" ]; then if [ -d "${XDG_CONFIG_HOME:-$HOME/.config}/tabby/plugins/node_modules" ]; then logg info 'Skipping Tabby plugin installation because it looks like the plugins were already installed since node_modules is present in ~/.config/tabby/plugins' diff --git a/home/dot_local/bin/post-installx/executable_post-tailscale.sh b/home/dot_local/bin/post-installx/executable_post-tailscale.sh index 2fb9e1f0..d20d92fd 100644 --- a/home/dot_local/bin/post-installx/executable_post-tailscale.sh +++ b/home/dot_local/bin/post-installx/executable_post-tailscale.sh @@ -10,6 +10,8 @@ # CloudFlare WARP, you will have to set up a [split tunnel](https://www.youtube.com/watch?v=eDFs8hm3xWc) for # [Tailscale IP addresses](https://tailscale.com/kb/1105/other-vpns). +set -euo pipefail + ### Disconnect from CloudFlare WARP (if connected) if command -v warp-cli > /dev/null; then warp-cli disconnect && logg info 'CloudFlare WARP temporarily disconnected while Tailscale connects' @@ -35,32 +37,38 @@ if [ -d /Applications ] && [ -d /System ]; then fi ### Acquire TAILSCALE_AUTH_KEY -TAILSCALE_KEY_FILE="${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets/TAILSCALE_AUTH_KEY" -if [ -f "$TAILSCALE_KEY_FILE" ]; then - logg info "Found TAILSCALE_AUTH_KEY in ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" - if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/age/chezmoi.txt" ]; then - logg info 'Decrypting TAILSCALE_AUTH_KEY token with Age encryption key' - TAILSCALE_AUTH_KEY="$(cat "$TAILSCALE_KEY_FILE" | chezmoi decrypt)" +if [ -z "$TAILSCALE_AUTH_KEY" ]; then + TAILSCALE_AUTH_KEY_FILE="${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets/TAILSCALE_AUTH_KEY" + if [ -f "$TAILSCALE_AUTH_KEY_FILE" ]; then + logg info "Found TAILSCALE_AUTH_KEY in ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" + if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/age/chezmoi.txt" ]; then + logg info 'Decrypting TAILSCALE_AUTH_KEY token with Age encryption key' + TAILSCALE_AUTH_KEY="$(cat "$TAILSCALE_AUTH_KEY_FILE" | chezmoi decrypt)" + else + logg warn 'Age encryption key is missing from ~/.config/age/chezmoi.txt' + exit 1 + fi else - logg warn 'Age encryption key is missing from ~/.config/age/chezmoi.txt' + logg warn "TAILSCALE_AUTH_KEY is missing from ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" + exit 1 fi else - logg warn "TAILSCALE_AUTH_KEY is missing from ${XDG_DATA_HOME:-$HOME/.local/share}/chezmoi/home/.chezmoitemplates/secrets" + logg info 'TAILSCALE_AUTH_KEY provided as environment variable' fi ### Connect to Tailscale network -if [ -n "$TAILSCALE_AUTH_KEY" ] && [ "$TAILSCALE_AUTH_KEY" != "" ]; then +if get-secret --exists TAILSCALE_AUTH_KEY; then if [ -f /Applications/Tailscale.app/Contents/MacOS/Tailscale ]; then logg info 'Connecting to Tailscale with user-defined authentication key (TAILSCALE_AUTH_KEY)' - timeout 30 /Applications/Tailscale.app/Contents/MacOS/Tailscale up --authkey="$TAILSCALE_AUTH_KEY" --accept-routes || EXIT_CODE=$? + timeout 30 /Applications/Tailscale.app/Contents/MacOS/Tailscale up --authkey="$(get-secret TAILSCALE_AUTH_KEY)" --accept-routes || EXIT_CODE=$? if [ -n "$EXIT_CODE" ]; then logg warn '/Applications/Tailscale.app/Contents/MacOS/Tailscale timed out' fi logg info 'Disabling update check' /Applications/Tailscale.app/Contents/MacOS/Tailscale set --update-check=false - elif command -v tailscale > /dev/null && [ "$TAILSCALE_AUTH_KEY" != "" ]; then + elif command -v tailscale > /dev/null; then logg info 'Connecting to Tailscale with user-defined authentication key (TAILSCALE_AUTH_KEY)' - timeout 30 tailscale up --authkey="$TAILSCALE_AUTH_KEY" --accept-routes || EXIT_CODE=$? + timeout 30 tailscale up --authkey="$(get-secret TAILSCALE_AUTH_KEY)" --accept-routes || EXIT_CODE=$? if [ -n "$EXIT_CODE" ]; then logg warn 'tailscale up timed out' else diff --git a/home/dot_local/bin/post-installx/executable_post-tfenv.sh b/home/dot_local/bin/post-installx/executable_post-tfenv.sh deleted file mode 100644 index 66aae7b4..00000000 --- a/home/dot_local/bin/post-installx/executable_post-tfenv.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -# @file tfenv -# @brief Configures tfenv to use the latest version of Terraform - -if command -v tfenv > /dev/null; then - logg info 'Configuring tfenv to use latest version of Terraform' - tfenv use latest -else - logg warn 'tfenv is not available in the PATH' -fi diff --git a/home/dot_local/bin/post-installx/executable_post-timeshift.sh b/home/dot_local/bin/post-installx/executable_post-timeshift.sh index 248bd1e2..86aee410 100644 --- a/home/dot_local/bin/post-installx/executable_post-timeshift.sh +++ b/home/dot_local/bin/post-installx/executable_post-timeshift.sh @@ -4,6 +4,8 @@ # @description # This script applies a Timeshift configuration that defines how Timeshift should maintain system backups. +set -euo pipefail + if command -v timeshift > /dev/null; then logg info 'Ensuring /etc/timeshift is a directory' sudo mkdir -p /etc/timeshift diff --git a/home/dot_local/bin/post-installx/executable_post-tor.sh b/home/dot_local/bin/post-installx/executable_post-tor.sh index 2949bf3c..dd81fda0 100644 --- a/home/dot_local/bin/post-installx/executable_post-tor.sh +++ b/home/dot_local/bin/post-installx/executable_post-tor.sh @@ -14,6 +14,8 @@ # # * [Tor configuration](https://github.com/megabyte-labs/install.doctor/tree/master/home/dot_config/tor/torrc) +set -euo pipefail + ### Determine the Tor configuration location by checking whether the system is macOS or Linux if [ -d /Applications ] && [ -d /System ]; then ### macOS @@ -40,7 +42,7 @@ if command -v torify > /dev/null; then ln -s /usr/local/etc/tor/torrc "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/tor/torrc" else if [ -L "${HOMEBREW_PREFIX:-/opt/homebrew}/etc/tor/torrc" ]; then - logg info ""${HOMEBREW_PREFIX:-/opt/homebrew}/etc/tor/torrc" symlinked" + logg info ""${HOMEBREW_PREFIX:-/opt/homebrew}/etc/tor/torrc" already symlinked to $TORRC_CONFIG" else logg warn ""${HOMEBREW_PREFIX:-/opt/homebrew}/etc/tor/torrc" not symlinked!" fi diff --git a/home/dot_local/bin/post-installx/executable_post-vim.sh b/home/dot_local/bin/post-installx/executable_post-vim.sh index 2239690c..ceb6d819 100644 --- a/home/dot_local/bin/post-installx/executable_post-vim.sh +++ b/home/dot_local/bin/post-installx/executable_post-vim.sh @@ -2,6 +2,8 @@ # @file VIM Plugins AOT Installation # @brief This script triggers VIM to pre-install plugins so that VIM loads into the desired state the first time it is invoked +set -euo pipefail + logg info "Installing VIM plugins" && vim +'PlugInstall --sync' +qall # @description This script installs the extensions defined in `${XDG_CONFIG_HOME:-$HOME/.config}/coc/extensions/package.json` diff --git a/home/dot_local/bin/post-installx/executable_post-virtualbox.sh b/home/dot_local/bin/post-installx/executable_post-virtualbox.sh index 86b6c1db..9f4ecad9 100644 --- a/home/dot_local/bin/post-installx/executable_post-virtualbox.sh +++ b/home/dot_local/bin/post-installx/executable_post-virtualbox.sh @@ -4,6 +4,8 @@ # @description # This script ensures the VirtualBox extension pack that corresponds with VirtualBox's version is properly installed. +set -euo pipefail + ### Run logic if VirtualBox is installed if command -v VirtualBox > /dev/null; then ### Install VirtualBox extension pack if it is not installed already diff --git a/home/dot_local/bin/post-installx/executable_post-vmware.sh b/home/dot_local/bin/post-installx/executable_post-vmware.sh index f8872d8e..0c0b6bdf 100644 --- a/home/dot_local/bin/post-installx/executable_post-vmware.sh +++ b/home/dot_local/bin/post-installx/executable_post-vmware.sh @@ -42,6 +42,8 @@ # * [`home/.chezmoidata.yaml`](https://github.com/megabyte-labs/install.doctor/blob/master/home/.chezmoidata.yaml) # * [Default license key gist](https://gist.github.com/PurpleVibe32/30a802c3c8ec902e1487024cdea26251) +set -euo pipefail + ### Run logic if VMware is installed if command -v vmware > /dev/null; then ### Build kernel modules if they are not present @@ -137,9 +139,15 @@ if command -v vagrant > /dev/null && command -v vmware-id > /dev/null; then logg success 'Generated Vagrant VMWare Utility certificates via vagrant-vmware-utility certificate generate' fi logg info 'Ensuring the Vagrant VMWare Utility service is enabled' - sudo vagrant-vmware-utility service install || EXIT_CODE=$? - if [ -n "$EXIT_CODE" ]; then - logg info 'The Vagrant VMWare Utility command vagrant-vmware-utility service install failed. If it was already set up, there should be a notice above.' + if VVU_OUTPUT=$(sudo vagrant-vmware-utility service install 2>&1); then + logg info 'sudo vagrant-vmware-utility service install successfully ran' + else + if echo $VVU_OUTPUT | grep 'service is already installed' > /dev/null; then + logg info 'Vagrant VMWare Utility is already installed' + else + logg error 'An error occurred while running sudo vagrant-vmware-utility service install' + echo "$VVU_OUTPUT" + fi fi fi else diff --git a/home/dot_local/bin/post-installx/executable_post-volta.sh b/home/dot_local/bin/post-installx/executable_post-volta.sh index eb76ff52..323d9b75 100644 --- a/home/dot_local/bin/post-installx/executable_post-volta.sh +++ b/home/dot_local/bin/post-installx/executable_post-volta.sh @@ -2,9 +2,17 @@ # @file Volta initialization # @brief This script initializes Volta and ensures the latest version of node and yarn are installed +set -euo pipefail + export VOLTA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/volta" export PATH="$VOLTA_HOME/bin:$PATH" +### Disconnect from CloudFlare WARP (if connected) +if command -v warp-cli > /dev/null; then + warp-cli disconnect && logg info 'CloudFlare WARP temporarily disconnected while Volta installs Node / Yarn' +fi + +### Configure Volta if it is installed if command -v volta > /dev/null; then logg info 'Running volta setup' volta setup diff --git a/home/dot_local/bin/post-installx/executable_post-vscode.sh b/home/dot_local/bin/post-installx/executable_post-vscode.sh index 67245831..57d67dfd 100644 --- a/home/dot_local/bin/post-installx/executable_post-vscode.sh +++ b/home/dot_local/bin/post-installx/executable_post-vscode.sh @@ -72,6 +72,8 @@ # * [Visual Studio Code settings folder](https://github.com/megabyte-labs/install.doctor/blob/master/home/dot_config/Code/User) # * [Visual Studio Code `extensions.json`](https://github.com/megabyte-labs/install.doctor/blob/master/home/dot_config/Code/User/extensions.json) +set -euo pipefail + ### Hides useless error during extension installations # Error looks like: # (node:53151) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. diff --git a/home/dot_local/bin/post-installx/executable_post-warp.sh b/home/dot_local/bin/post-installx/executable_post-warp.sh index ec41f322..d9271432 100644 --- a/home/dot_local/bin/post-installx/executable_post-warp.sh +++ b/home/dot_local/bin/post-installx/executable_post-warp.sh @@ -50,6 +50,8 @@ # * [Linux managed configuration](https://github.com/megabyte-labs/install.doctor/tree/master/home/dot_config/warp/private_mdm.xml.tmpl) # * [macOS managed configuration](https://github.com/megabyte-labs/install.doctor/tree/master/home/Library/Managed%20Preferences/private_com.cloudflare.warp.plist.tmpl) +set -euo pipefail + SSL_CERT_PATH="/etc/ssl/cert.pem" ### Install CloudFlare WARP (on non-WSL *nix systems) if [[ ! "$(test -d /proc && grep Microsoft /proc/version > /dev/null)" ]]; then @@ -60,7 +62,7 @@ if [[ ! "$(test -d /proc && grep Microsoft /proc/version > /dev/null)" ]]; then else logg info 'Cloudflare WARP already installed' fi - elif [ '{{ .host.distro.id }}' = 'debian' ]; then + elif [ -n "$(uname -a | grep Debian)" ]; then ### Add CloudFlare WARP desktop app apt-get source if [ ! -f /etc/apt/sources.list.d/cloudflare-client.list ]; then logg info 'Adding CloudFlare WARP keyring' @@ -71,7 +73,7 @@ if [[ ! "$(test -d /proc && grep Microsoft /proc/version > /dev/null)" ]]; then ### Update apt-get and install the CloudFlare WARP CLI sudo apt-get update && sudo apt-get install -y cloudflare-warp - elif [ '{{ .host.distro.id }}' = 'ubuntu' ]; then + elif [ -n "$(uname -a | grep Ubuntu)" ]; then ### Add CloudFlare WARP desktop app apt-get source if [ ! -f /etc/apt/sources.list.d/cloudflare-client.list ]; then logg info 'Adding CloudFlare WARP keyring' diff --git a/home/dot_local/bin/post-installx/executable_post-wazuh.sh b/home/dot_local/bin/post-installx/executable_post-wazuh.sh index 5e9f4012..0018206a 100644 --- a/home/dot_local/bin/post-installx/executable_post-wazuh.sh +++ b/home/dot_local/bin/post-installx/executable_post-wazuh.sh @@ -2,6 +2,11 @@ # @file Wazuh Client Install # @brief Installs the Wazuh client and connects to the manager if configured to do so through secrets / environment variables +set -euo pipefail + +### Ensure secrets +get-secret --exists WAZUH_MANAGER WAZUH_REGISTRATION_PASSWORD + if [ -d /Applications ] && [ -d /System ]; then ### macOS logg info 'Downloading the macOS Wazuh agent pkg' @@ -13,7 +18,7 @@ if [ -d /Applications ] && [ -d /System ]; then wget -q "$PKG_URL" -O /tmp/wazuh-agent.pkg &> /dev/null logg info 'Setting Wazuh launch parameters in /tmp/wazuh_envs' # https://documentation.wazuh.com/current/user-manual/agent/deployment-variables/deployment-variables-macos.html - echo "WAZUH_MANAGER="$WAZUH_MANAGER" && WAZUH_REGISTRATION_SERVER="$WAZUH_MANAGER" && WAZUH_REGISTRATION_PASSWORD="WazuhRegister" && WAZUH_AGENT_NAME="$WAZUH_AGENT_NAME"" > /tmp/wazuh_envs + echo "WAZUH_MANAGER="$(get-secret WAZUH_MANAGER)" && WAZUH_REGISTRATION_PASSWORD="$(get-secret WAZUH_REGISTRATION_PASSWORD)"" > /tmp/wazuh_envs logg info 'Installing the Wazuh agent pkg' sudo installer -pkg /tmp/wazuh-agent.pkg -target / sudo chmod 755 /Library/Ossec diff --git a/home/dot_local/bin/post-installx/executable_post-wireguard-tools.sh b/home/dot_local/bin/post-installx/executable_post-wireguard-tools.sh index a702cb4d..9416e7ac 100644 --- a/home/dot_local/bin/post-installx/executable_post-wireguard-tools.sh +++ b/home/dot_local/bin/post-installx/executable_post-wireguard-tools.sh @@ -20,8 +20,7 @@ # * [VPN profile folder](https://github.com/megabyte-labs/install.doctor/blob/master/home/dot_config/vpn) # * [VPN profile documentation](https://install.doctor/docs/customization/secrets#vpn-profiles) -# TODO - Populate Tunnelblick on macOS using the .ovpn profiles located in $HOME/.config/vpn (execpt in the `openvpn` entry of software.yml) -# along with the secrets for the protonVPN OpenVPN (check vpn-linux.tmpl) +set -euo pipefail ### Backs up previous network settings to `/Library/Preferences/com.apple.networkextension.plist.old` before applying new VPN profiles logg info 'Backing up /Library/Preferences/com.apple.networkextension.plist to /Library/Preferences/com.apple.networkextension.plist.old' diff --git a/software.yml b/software.yml index 4a901124..985971ea 100644 --- a/software.yml +++ b/software.yml @@ -493,7 +493,6 @@ softwarePackages: _name: AptCacherNG _short: "apt-cacher-ng is a caching proxy for software packages, primarily used in Debian-based systems like Ubuntu. It helps in saving bandwidth and speeding up package installations by caching downloaded \npackages locally. " _systemd: apt-cacher-ng - ansible: professormanhattan.aptcacherng aqua: _bin: aqua _desc: "[aqua](https://aquaproj.github.io/) is a Declarative CLI Version manager written in Go. It supports Lazy Install, Registry, and continuous update with Renovate." @@ -501,7 +500,10 @@ softwarePackages: _github: https://github.com/aquaproj/aqua _home: https://aquaproj.github.io _name: aqua - _short: "Aqua is a tool for secure and efficient container image scanning. " + _short: "Aqua is a tool for secure and efficient container image scanning." + _post: | + aqua update-aqua + aqua install -a binary:linux: https://github.com/aquaproj/aqua/releases/download/v2.0.0-0/aqua_linux_amd64.tar.gz binary:windows: https://github.com/aquaproj/aqua/releases/download/v2.0.0-0/aqua_windows_amd64.tar.gz brew: aquaproj/aqua/aqua @@ -544,7 +546,6 @@ softwarePackages: _github: https://github.com/aria2/aria2 _name: Aria2/AriaNg _short: "aria2 is a lightweight multi-protocol & multi-source command-line download utility. " - ansible: professormanhattan.aria apt: aria2 brew: aria2 choco: aria2 @@ -594,7 +595,6 @@ softwarePackages: _home: https://asdf-vm.com/ _name: asdf-vm _short: "asdf is a tool for managing multiple runtime versions like Node.js, Ruby, Python, etc., in a single environment. " - ansible: professormanhattan.asdf assh: _bin: assh _desc: "[assh](https://manfred.life/assh) makes your ssh client smarter" @@ -632,7 +632,7 @@ softwarePackages: _desc: "Atuin is a tool for managing AWS infrastructure using a simple command-line interface. It allows users to create, update, and delete AWS resources like EC2 instances, security groups, and S3 buckets \nusing a declarative configuration file. Atuin aims to simplify AWS infrastructure management by providing a user-friendly interface and automating common tasks. It is written in Go and is open-source, \navailable on GitHub at https://github.com/ellie/atuin. " _github: https://github.com/ellie/atuin _name: Atuin - _short: "Atuin is a command-line tool for managing macOS windows. " + _short: "Atuin is a command-line tool for managing macOS windows. " brew: atuin cargo: atuin pacman: atuin @@ -706,7 +706,6 @@ softwarePackages: _home: https://autorestic.vercel.app/ _name: Autorestic _short: "AutoRestic is a tool that simplifies and automates backups using Restic, a fast, secure, and efficient backup program. " - ansible: professormanhattan.autorestic brew: autorestic aws-shell: _bin: aws-shell @@ -726,7 +725,6 @@ softwarePackages: _home: https://aws.amazon.com/ _name: AWS CLI _short: "AWS CLI is a unified tool to manage AWS services through the command line. " - ansible: professormanhattan.awscli binary:darwin: https://awscli.amazonaws.com/AWSCLIV2.pkg binary:linux: https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip binary:windows: https://awscli.amazonaws.com/AWSCLIV2.msi @@ -740,7 +738,6 @@ softwarePackages: _home: https://docs.ansible.com/automation.html _name: AWX CLI _short: "AWX is an open-source automation platform that provides a web-based user interface, REST API, and task engine built on top of Ansible. " - ansible: professormanhattan.awxcli pipx: https://releases.ansible.com/ansible-tower/cli/ansible-tower-cli-latest.tar.gz axel: _bin: axel @@ -762,7 +759,6 @@ softwarePackages: _home: https://azure.microsoft.com/ _name: Azure CLI _short: "Azure CLI is a command-line tool for managing Azure resources. " - ansible: professormanhattan.azurecli brew: azure-cli choco: azure-cli winget: Microsoft.AzureCLI @@ -805,7 +801,6 @@ softwarePackages: _github: https://github.com/imsnif/bandwhich _name: Bandwhich _short: "bandwhich is a terminal bandwidth utilization tool for Linux and macOS. " - ansible: professormanhattan.bandwhich brew: bandwhich github: github.com/imsnif/bandwhich pacman: bandwhich @@ -858,7 +853,6 @@ softwarePackages: _github: https://github.com/sharkdp/bat _name: bat _short: "bat is a cat(1) clone with syntax highlighting and Git integration. " - ansible: professormanhattan.bat apk: bat apt: bat brew: bat @@ -917,7 +911,6 @@ softwarePackages: _home: https://beets.io/ _name: Beets _short: "Beets is a music library manager and tagger for organizing your music collection efficiently. " - ansible: professormanhattan.beets pipx: beets betwixt: _app: Betwixt.app @@ -997,7 +990,6 @@ softwarePackages: _home: https://bitwarden.com/ _name: Bitwarden CLI _short: "Bitwarden Clients: Open-source password manager with clients for various platforms including web, desktop, and mobile. " - ansible: professormanhattan.bw brew: bitwarden-cli choco: bitwarden-cli npm: "@bitwarden/cli" @@ -1147,7 +1139,6 @@ softwarePackages: _home: https://dystroy.org/broot/ _name: Broot _short: "broot is a command-line interactive tree view tool for navigating directories efficiently. " - ansible: professormanhattan.broot apk: broot brew: broot cargo: broot @@ -1589,7 +1580,6 @@ softwarePackages: _github: https://github.com/cloudflare/cloudflared _name: CloudFlared _short: "cloudflared is a tool by Cloudflare that allows secure and fast access to the internet. " - ansible: professormanhattan.cloudflared binary:linux: https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 brew:darwin: cloudflare/cloudflare/cloudflared github: github.com/cloudflare/cloudflared @@ -1753,12 +1743,6 @@ softwarePackages: _name: commitlint _short: "commitlint is a tool that enforces commit message conventions to ensure consistent and structured commit messages in a project. " npm: "@commitlint/cli" - common: - _bin: null - _desc: For example, this role sets the timezone, sets the hostname, sets up the swap space, ensures auto-login is either disabled or enabled, and customizes GRUB (on Linux). It also ensures that specified groups are present on the system. On Windows, the role ensures all the available updates are installed, ensures [Scoop](https://scoop.sh/) is installed, and ensures common dependencies like [Bandizip](https://en.bandisoft.com/bandizip/) (a compressed-file manager) are installed. - _github: false - _name: Common - ansible: professormanhattan.common composer: _bin: composer _desc: "[Composer](https://getcomposer.org/) is an application-level package manager for the PHP programming language that provides a standard format for managing dependencies of PHP software and required libraries. It was developed by Nils Adermann and Jordi Boggiano, who continue to manage the project." @@ -1767,7 +1751,6 @@ softwarePackages: _home: https://getcomposer.org/ _name: Composer _short: "Composer is a dependency manager for PHP. " - ansible: professormanhattan.composer brew: composer choco: composer pacman: composer @@ -1810,7 +1793,6 @@ softwarePackages: _home: https://www.hashicorp.com/ _name: Consul Template _short: "Consul Template is a tool by HashiCorp that renders templates based on Consul data. " - ansible: professormanhattan.consultemplate brew: consul-template choco: consul-template scoop: main/consul @@ -1935,7 +1917,6 @@ softwarePackages: proto: tcp _short: "CUPS (Common UNIX Printing System) is an open-source printing system developed by Apple for Unix-like operating systems. " _systemd: smbd - ansible: professormanhattan.cups apt: - avahi-daemon - cups @@ -1960,6 +1941,7 @@ softwarePackages: _github: https://github.com/curl/curl _home: https://curl.se/ _name: cURL + _preload: true _short: "curl is a command-line tool and library for transferring data with URLs. " apk: curl apt: curl @@ -2058,12 +2040,6 @@ softwarePackages: _name: "dconf-editor " _short: "dconf-editor is a graphical editor for the Dconf configuration system used in GNOME. " flatpak: ca.desrt.dconf-editor - debloat: - _bin: null - _desc: This repository is the home of an Ansible role that Debloats Windows - _github: false - _name: Debloat Windows - ansible: professormanhattan.debloat debsecan: _bin: debsecan-by-type _desc: debsecan analyzes the list of installed packages on the current host and reports vulnerabilities found on the system. @@ -2072,12 +2048,6 @@ softwarePackages: _home: https://wiki.debian.org/DebianSecurity/debsecan _name: Debian Security Analyzer apt: debsecan - defaultbrowser: - _bin: null - _desc: This role performs the necessary logic to set the default browser on nearly any platform. - _github: false - _name: Default Browser Setter - ansible: professormanhattan.defaultbrowser deja-dup: _bin: dejadup _github: false @@ -2092,7 +2062,6 @@ softwarePackages: _home: https://github.com/dandavison/delta _name: Delta _short: "Delta is a tool for viewing git diff output with syntax highlighting and line decorations. " - ansible: professormanhattan.delta brew: git-delta cargo: git-delta choco: delta @@ -2118,7 +2087,6 @@ softwarePackages: _home: https://deno.land/ _name: Deno _short: "Deno is a secure runtime for JavaScript and TypeScript. " - ansible: professormanhattan.deno brew: deno cargo: deno choco: deno @@ -2144,12 +2112,6 @@ softwarePackages: _name: Desk _short: "desk is a tool for managing your workspace configurations in macOS. " brew: desk - desktop: - _bin: null - _desc: This role is essentially the place where all desktop-specific tasks that are substantial enough for their own role are placed. - _github: false - _name: Desktop - ansible: professormanhattan.desktop deta: _bin: deta _desc: Command line interface for managing Deta micros and deployments @@ -2245,7 +2207,6 @@ softwarePackages: _home: https://direnv.net/ _name: direnv _short: "direnv is a tool that helps automate loading and unloading of environment variables based on the current directory. " - ansible: professormanhattan.direnv apt: direnv brew: direnv github: github.com/direnv/direnv @@ -2275,17 +2236,10 @@ softwarePackages: _home: https://github.com/wagoodman/dive _name: dive _short: "Dive is a tool for exploring and analyzing Docker images interactively. " - ansible: professormanhattan.dive brew: dive github: github.com/wagoodman/dive go: github.com/wagoodman/dive@latest yay: dive - dns: - _bin: null - _desc: This role ensures that DNS requests are encrypted if you supply it the appropriate configuration. It uses systemd on Linux. On macOS/Windows, it installs and configures [Stubby](https://github.com/getdnsapi/stubby). - _github: false - _name: DNS - ansible: professormanhattan.dns dnsmasq: _bin: dnsmasq _desc: "[Dnsmasq](https://wiki.debian.org/dnsmasq) is free software providing Domain Name System caching, a Dynamic Host Configuration Protocol server, router advertisement and network boot features, intended for small computer networks." @@ -2294,7 +2248,6 @@ softwarePackages: _name: dnsmasq _service: dnsmasq _short: "dnsmasq is a lightweight DNS forwarder and DHCP server. " - ansible: professormanhattan.dnsmasq apt: dnsmasq brew: dnsmasq dnf: dnsmasq @@ -2564,7 +2517,6 @@ softwarePackages: _home: https://github.com/muesli/duf _name: duf _short: "Duf is a disk usage utility with a modern interface for visualizing disk space usage on your system. " - ansible: professormanhattan.duf brew: duf choco: duf github: github.com/muesli/duf @@ -2747,7 +2699,6 @@ softwarePackages: _github: https://github.com/hashicorp/envconsul _name: envconsul _short: "Envconsul is a tool by HashiCorp that updates environment variables in running processes from Consul. " - ansible: professormanhattan.envconsul brew: envconsul github: github.com/hashicorp/envconsul envio: @@ -2757,10 +2708,6 @@ softwarePackages: _name: Envio _short: "envio is a lightweight command-line tool for sending files securely over the internet using end-to-end encryption. " cargo: envio - environment: - _bin: null - _github: false - ansible: professormanhattan.environment envpane: _bin: null _desc: An OS X preference pane for environment variables @@ -2905,7 +2852,6 @@ softwarePackages: _home: https://exiftool.org/ _name: exiftool _short: "ExifTool is a powerful command-line tool for reading, writing, and editing metadata in a wide variety of files, including images, videos, and documents. " - ansible: professormanhattan.exiftool apt: libimage-exiftool-perl brew: exiftool choco: exiftool @@ -2922,12 +2868,6 @@ softwarePackages: dnf: expect pacman: expect port: expect - extensions: - _bin: null - _desc: This role acts as a catch-all for extensions for various system software. - _github: false - _name: Extensions - ansible: professormanhattan.extensions fabric: _bin: fab _desc: "Fabric is a Python library and command-line tool designed for streamlining the process of executing shell commands remotely over SSH. It simplifies the automation of tasks like deploying applications, \nrunning scripts, and managing servers. Fabric allows you to define tasks in Python scripts and execute them across multiple servers simultaneously. It provides features like parallel execution, error \nhandling, and output processing. Fabric is commonly used by developers and system administrators to automate repetitive tasks in a more efficient and consistent manner. " @@ -2990,7 +2930,6 @@ softwarePackages: _github: https://github.com/sharkdp/fd _name: fd _short: "fd is a simple, fast and user-friendly alternative to find command, written in Rust. " - ansible: professormanhattan.fd apk: fd apt: fd-find brew: fd @@ -3040,7 +2979,6 @@ softwarePackages: _github: https://github.com/FFmpeg/FFmpeg _name: FFmpeg _short: "FFmpeg is a powerful multimedia framework that can decode, encode, transcode, mux, demux, stream, filter, and play almost anything that humans and machines have created. " - ansible: professormanhattan.ffmpeg apk: ffmpeg apt: ffmpeg brew: ffmpeg @@ -3054,7 +2992,6 @@ softwarePackages: _github: https://github.com/timvisee/ffsend _name: ffsend _short: "ffsend is a command-line tool for securely and easily sharing files from the terminal using Firefox Send. " - ansible: professormanhattan.ffsend apk: ffsend brew: ffsend github: github.com/timvisee/ffsend @@ -3115,7 +3052,6 @@ softwarePackages: _home: https://filebrowser.org/ _name: File Browser _short: "Filebrowser is an open-source, self-hosted web-based file manager with a simple and intuitive interface for managing files on a server. " - ansible: professormanhattan.filebrowser brew: filebrowser/tap/filebrowser github: github.com/filebrowser/filebrowser filezilla: @@ -3138,12 +3074,6 @@ softwarePackages: _bin: gfind _github: false brew: findutils - finish: - _bin: null - _desc: This role should be the last role in the playbook. - _github: false - _name: Finish - ansible: professormanhattan.finish firebase: _bin: firebase _desc: The Firebase Command Line Interface (CLI) Tools can be used to test, manage, and deploy your Firebase project from the command line @@ -3373,7 +3303,6 @@ softwarePackages: _github: https://github.com/jordansissel/fpm _name: fpm _short: "fpm is a tool for building packages in various formats like deb, rpm, and others, making package management easier across different systems. " - ansible: professormanhattan.fpm gem: fpm fpm:deps: _github: false @@ -3496,8 +3425,8 @@ softwarePackages: _github: https://github.com/junegunn/fzf _home: https://github.com/junegunn/fzf _name: fzf + _preload: true _short: "fzf is a command-line fuzzy finder for searching and selecting items interactively. " - ansible: professormanhattan.fzf apk: fzf apt: fzf brew: fzf @@ -3540,7 +3469,6 @@ softwarePackages: _desc: "[Google Cloud SDK](https://cloud.google.com/sdk) includes tools and libraries for interacting with Google Cloud products and services. With it, you can orchestrate virtual machine instances directly from your command line, manage Compute Engine networks/firewalls/disks, simulate Pub/Sub locally, and much more." _github: false _name: Google Cloud SDK - ansible: professormanhattan.googlecloudsdk cask: google-cloud-sdk choco: gcloudsdk snap: google-cloud-sdk --classic @@ -3625,7 +3553,6 @@ softwarePackages: _home: https://cli.github.com/ _name: Github CLI _short: "GitHub CLI is a command-line tool that brings GitHub to your terminal. " - ansible: professormanhattan.gh brew: gh choco: gh port: gh @@ -3645,7 +3572,6 @@ softwarePackages: _name: ghorg _post: ghorg reclone _short: "ghorg is a tool for cloning all repositories of a GitHub organization quickly and easily. " - ansible: professormanhattan.ghorg brew: gabrie30/utils/ghorg github: github.com/gabrie30/ghorg go: github.com/gabrie30/ghorg@latest @@ -3672,7 +3598,6 @@ softwarePackages: _home: https://www.gimp.org/ _name: GIMP _short: "GIMP is a free and open-source image editor for tasks like photo retouching, image composition, and image authoring. " - ansible: professormanhattan.gimp apt: gimp cask: gimp choco: gimp @@ -3686,7 +3611,6 @@ softwarePackages: _github: https://github.com/defunkt/gist _name: gist _short: "Gist is a tool for sharing code snippets or files easily on GitHub. " - ansible: professormanhattan.gist gem: gist git: _bin: git @@ -3739,7 +3663,6 @@ softwarePackages: _github: https://github.com/newren/git-filter-repo _name: "git-filter-repo " _short: "git-filter-repo is a powerful tool for rewriting Git repository history efficiently and with ease. " - ansible: professormanhattan.gitfilterrepo brew: git-filter-repo pipx: git-filter-repo git-jump: @@ -3761,7 +3684,6 @@ softwarePackages: sudo git lfs install --system git lfs install _short: "git-lfs is an open-source extension for Git that manages large files by storing them outside the main repository. " - ansible: professormanhattan.gitlfs brew: git-lfs scoop: git-lfs git-notify: @@ -3798,7 +3720,6 @@ softwarePackages: _github: https://github.com/IonicaBizau/git-stats _name: git-stats _short: "git-stats is a tool that provides statistics about a Git repository, such as contributors, commits per author, and more. " - ansible: professormanhattan.gitstats npm: git-stats git-subrepo: _bin: git-subrepo @@ -3896,13 +3817,13 @@ softwarePackages: _home: https://www.gitkraken.com/ _name: GitKraken _short: "$'Not open-source' is a string in zsh shell that uses single quotes to interpret escape sequences like \\n for newline. " - ansible: professormanhattan.gitkraken cask: gitkraken choco: gitkraken flatpak: com.axosoft.GitKraken snap: gitkraken --classic gitlab-runner: _bin: gitlab-runner + _deprecated: Deprecated in favor of GitHub CI/CD _desc: "[GitLab Runner](https://docs.gitlab.com/runner/) is an application that works with GitLab CI/CD to run jobs in a pipeline." _docs: https://docs.gitlab.com/runner/ _github: https://github.com/gitlabhq/gitlab-runner @@ -3911,7 +3832,6 @@ softwarePackages: _service: gitlab-runner _serviceEnabled: true _short: "GitLab Runner is an open-source project that works with GitLab CI/CD to run jobs and send the results back to GitLab. " - ansible: professormanhattan.gitlabrunner brew: gitlab-runner choco: gitlab-runner pacman: gitlab-runner @@ -3950,7 +3870,6 @@ softwarePackages: _github: https://github.com/muesli/gitomatic _name: git-o-matic _short: "gitomatic is a tool for automatic syncing of Git repositories. " - ansible: professormanhattan.gitomatic github: github.com/muesli/gitomatic go: github.com/muesli/gitomatic@latest pacman: gitomatic @@ -4005,7 +3924,6 @@ softwarePackages: _name: Glances _post:pipx: pipx inject glances glances[all] _short: "Glances is a cross-platform monitoring tool that provides real-time system information in a visually appealing way. " - ansible: professormanhattan.glances apt:ubuntu: - python3-dev - python3-jinja2 @@ -4215,7 +4133,6 @@ softwarePackages: _home: https://go.dev/ _name: Go _short: "The official repository for the Go programming language. " - ansible: professormanhattan.go apt: golang-go brew: go choco: golang @@ -4331,7 +4248,6 @@ softwarePackages: _home: https://www.google.com/chrome/ _name: Google Chrome _short: "$'Not open-source' is a string in zsh shell that uses single quotes to interpret escape sequences like \\n for newline. " - ansible: professormanhattan.chrome cask: google-chrome choco: googlechrome flatpak: com.google.Chrome @@ -4418,7 +4334,6 @@ softwarePackages: _github: https://github.com/orf/gping _name: gping _short: "gping is a modern ping tool that shows a graph of ping responses over time. " - ansible: professormanhattan.gping brew: gping cargo: gping choco: gping @@ -4440,7 +4355,6 @@ softwarePackages: _home: https://gradle.org/ _name: Gradle _short: "Gradle is a powerful build automation tool that helps manage dependencies and build processes efficiently for software projects. " - ansible: professormanhattan.gradle brew: gradle choco: gradle port: gradle @@ -4516,7 +4430,7 @@ softwarePackages: _home: https://guacamole.apache.org/ _name: Guacamole _short: "Apache Guacamole is an open-source remote desktop gateway that provides access to desktop environments using a web browser. " - ansible: professormanhattan.guacamole + _todo: Add installer for guacamole gulp: _bin: gulp _desc: "[Gulp](https://gulpjs.com/) is a toolkit to automate & enhance your workflow" @@ -4548,14 +4462,6 @@ softwarePackages: _short: "gup is a tool for updating Git repositories with ease. " brew: nao1215/tap/gup go: github.com/nao1215/gup@latest - gvm: - _bin: null - _deprecated: Deprecated in favor of using ASDF. - _desc: "[gvm](https://github.com/moovweb/gvm) lets you manage Go environments and switch between Go versions." - _github: https://github.com/moovweb/gvm - _name: rvm - _short: "gvm is a Go Version Manager that allows you to easily install and manage multiple versions of Go on your system. " - ansible: professormanhattan.gvm hadolint: _bin: hadolint _desc: A smarter Dockerfile linter that helps you build best practice Docker images. The linter parses the Dockerfile into an AST and performs rules on top of the AST @@ -4565,6 +4471,14 @@ softwarePackages: brew: hadolint dnf:fedora: hadolint scoop: hadolint + hammerspoon: + _app: Hammerspoon.app + _bin: hs + _desc: Staggeringly powerful macOS desktop automation with Lua + _docs: https://www.hammerspoon.org/go/ + _github: https://github.com/Hammerspoon/hammerspoon + _name: Hammerspoon + cask: hammerspoon handbrake: _app: HandBrake.app _bin: handbrake @@ -4672,7 +4586,6 @@ softwarePackages: _github: https://github.com/heroku/cli _name: Heroku CLI _short: "Heroku CLI is a command-line tool that allows developers to manage and deploy applications on the Heroku platform easily. " - ansible: professormanhattan.heroku brew: heroku/brew/heroku choco: heroku-cli npm: heroku @@ -4684,7 +4597,6 @@ softwarePackages: _github: https://github.com/sharkdp/hexyl _name: hexyl _short: "Hexyl is a command-line hex viewer designed for speed and ease of use. " - ansible: professormanhattan.hexyl apt: hexyl brew: hexyl cargo: hexyl @@ -4722,7 +4634,6 @@ softwarePackages: _github: https://github.com/soywod/himalaya _name: Himalaya _short: "himalaya is a minimalist and fast static site generator written in Rust. " - ansible: professormanhattan.himalaya brew: himalaya scoop: himalaya hishtory: @@ -4762,17 +4673,6 @@ softwarePackages: github: github.com/guumaster/hostctl scoop: hostctl yay: hostctl - hosthomepage: - _bin: null - _github: false - _name: Host Home Page - ansible: professormanhattan.hosthomepage - hosts: - _bin: null - _desc: This role is intended to be used with the [main ProfessorManhattan playbook](https://gitlab.com/ProfessorManhattan/Playbooks). It integrates tightly with the configuration variables that come with the playbook. - _github: false - _name: Hosts - ansible: professormanhattan.hosts howdoi: _bin: howdoi _desc: "howdoi is a command-line tool that provides quick answers to programming questions by searching through Stack Overflow. Users can simply type a question related to programming, and howdoi will fetch and\ndisplay relevant answers from Stack Overflow. It's a handy tool for developers looking for quick solutions or explanations without having to manually search through forums. The tool is written in Python\nand is available on GitHub for anyone to use and contribute to. " @@ -4865,7 +4765,6 @@ softwarePackages: _name: HTTPie _short: "HTTPie is a command-line HTTP client for making requests with a simple and intuitive syntax. " _todo: Look into https://github.com/httpie/desktop as alternative to Postman and other HTTP request clients - ansible: professormanhattan.httpie brew: httpie choco: httpie dnf: httpie @@ -4947,7 +4846,6 @@ softwarePackages: _home: https://hyper.is/ _name: Hyper _short: "Hyper is a customizable terminal built on web technologies. " - ansible: professormanhattan.hyper appimage: hyper brew: hyper choco: hyper @@ -4959,7 +4857,6 @@ softwarePackages: _github: https://github.com/sharkdp/hyperfine _name: hyperfine _short: "hyperfine is a command-line benchmarking tool for measuring the execution time of programs. " - ansible: professormanhattan.hyperfine apk: hyperfine brew: hyperfine cargo: hyperfine @@ -5074,7 +4971,6 @@ softwarePackages: _home: https://inkscape.org _name: Inkscape _short: "Inkscape is a popular open-source vector graphics editor for creating illustrations, icons, logos, diagrams, and more. " - ansible: professormanhattan.inkscape apt: inkscape cask: inkscape choco: inkscape @@ -5091,7 +4987,6 @@ softwarePackages: _home: https://www.jetbrains.com/idea/ _name: IntelliJ IDEA (CE) _short: "intellij-community is an open-source project by JetBrains for IntelliJ IDEA, a popular Java IDE. " - ansible: professormanhattan.intellij cask: intellij-idea-ce choco: intellijidea-community snap: intellij-idea-community --classic @@ -5254,7 +5149,6 @@ softwarePackages: _name: Java _short: "nosql-java-sdk is a Java library for interacting with Oracle NoSQL Database. " _when:cask: "! brew list temurin > /dev/null" - ansible: professormanhattan.java apt: openjdk-11-jdk brew: openjdk cask: temurin @@ -5284,7 +5178,6 @@ softwarePackages: _home: https://www.jenv.be/ _name: jenv _short: "jenv is a tool for managing Java environments on your system. It allows you to easily switch between different Java versions and set the Java version on a per-directory basis. " - ansible: professormanhattan.jenv brew: jenv jest: _bin: jest @@ -5322,7 +5215,6 @@ softwarePackages: _github: https://github.com/jpmens/jo _name: jo _short: "jo is a command-line utility that creates JSON output from shell commands. " - ansible: professormanhattan.jo apt: jo brew: jo github: github.com/jpmens/jo @@ -5360,8 +5252,8 @@ softwarePackages: _github: https://github.com/stedolan/jq _home: https://stedolan.github.io/jq _name: jq + _preload: true _short: "jq is a lightweight and flexible command-line JSON processor for parsing, manipulating, and formatting JSON data efficiently. " - ansible: professormanhattan.jq apk: jq apt: jq brew: jq @@ -5407,7 +5299,6 @@ softwarePackages: _home: https://juju.is/ _name: Juju _short: "Juju is an open-source application modeling tool that allows you to deploy, configure, manage, and scale applications in the cloud easily. " - ansible: professormanhattan.juju brew: juju choco: juju snap: juju --classic @@ -5556,7 +5447,6 @@ softwarePackages: _name: Keybase _short: "Keybase Client is an open-source security app that offers encrypted messaging, file sharing, and identity verification services. " _when:ansible: "! test -f /opt/keybase/Keybase" - ansible: professormanhattan.keybase cask: keybase choco: keybase pacman: @@ -5582,7 +5472,6 @@ softwarePackages: _home: https://sw.kovidgoyal.net/kitty/ _name: KiTTY _short: "kitty is a fast, feature-rich, and cross-platform terminal emulator. " - ansible: professormanhattan.kitty kn: _bin: kn _desc: The Knative CLI (kn) provides a quick and easy interface for creating Knative resources, such as Knative Services and Event Sources @@ -5601,7 +5490,6 @@ softwarePackages: _home: https://kodi.tv/ _name: Kodi _short: "GitHub Repository: \n\n • Name: xbmc/xbmc \n • Description: Open-source media player software \n • Link: xbmc/xbmc " - ansible: professormanhattan.kodi apt: kodi cask: kodi choco: kodi @@ -5779,7 +5667,6 @@ softwarePackages: _name: KVM _service: libvirt _serviceEnabled: true - ansible: professormanhattan.kvm apt: - bridge-utils - libvirt-clients @@ -5854,7 +5741,6 @@ softwarePackages: _home: https://www.ledger.com/ledger-live _name: Ledger Live _short: "Ledger Live is a desktop application for managing cryptocurrency assets using Ledger hardware wallets. " - ansible: professormanhattan.ledgerlive appimage: ledger-live-desktop cask: ledger-live choco: ledger-live @@ -5868,7 +5754,6 @@ softwarePackages: _home: https://k8slens.dev/ _name: Lens _short: "Lens is an open-source Kubernetes IDE that provides a visual way to work with Kubernetes clusters. " - ansible: professormanhattan.lens cask: lens choco: lens snap: kontena-lens --classic @@ -5892,7 +5777,6 @@ softwarePackages: _name: Lexicon _post:pipx: pipx inject dns-lexicon dns-lexicon[full] _short: "Lexicon is a DNS manipulation framework that makes it easy to interact with multiple DNS providers. " - ansible: professormanhattan.lexicon pipx: dns-lexicon libguestfs-tools: _bin: guestfish @@ -6097,7 +5981,6 @@ softwarePackages: _github: https://github.com/lastpass/lastpass-cli _name: LastPass CLI _short: "lastpass-cli is a command line interface for LastPass password manager, allowing users to access and manage their passwords from the terminal. " - ansible: professormanhattan.lpass lsd: _bin: lsd _deprecated: Deprecated in favor of using `exa`. `lsd` may be re-introduced when Windows support is added. @@ -6247,7 +6130,6 @@ softwarePackages: _home: https://github.com/lra/mackup _name: mackup _short: "Mackup is a tool that syncs application settings across multiple macOS devices using cloud storage services like Dropbox or Google Drive. " - ansible: professormanhattan.mackup brew: mackup pipx: mackup macprefs: @@ -6604,7 +6486,6 @@ softwarePackages: _desc: "[Microsoft Teams](https://www.microsoft.com/en-us/microsoft-teams/group-chat-software) is a proprietary business communication platform developed by Microsoft, as part of the Microsoft 365 family of products. Teams primarily competes with the similar service Slack, offering workspace chat and videoconferencing, file storage, and application integration." _github: false _name: Microsoft Teams - ansible: professormanhattan.teams cask: microsoft-teams choco: microsoft-teams flatpak: com.microsoft.Teams @@ -6619,7 +6500,6 @@ softwarePackages: _github: false _home: https://todo.microsoft.com/tasks/ _name: Microsoft To-Do - ansible: professormanhattan.microsofttodo cask: ao mas: 1274495053 snap: microsoft-todo-unofficial @@ -6669,7 +6549,6 @@ softwarePackages: _home: https://mitmproxy.org/ _name: mitmproxy _short: "mitmproxy is an open-source interactive HTTPS proxy. " - ansible: professormanhattan.mitmproxy apt: mitmproxy cask: mitmproxy choco: mitmproxy @@ -6764,7 +6643,6 @@ softwarePackages: _restricted: true _service: monero _short: "Monero is an open-source cryptocurrency that focuses on privacy, security, and decentralization. " - ansible: professormanhattan.monero cask: monero-wallet choco: monero flatpak: org.getmonero.Monero @@ -6861,7 +6739,6 @@ softwarePackages: _home: https://motrix.app/ _name: Motrix _short: "Motrix is a full-featured download manager that supports downloading HTTP, FTP, BitTorrent, Magnet, and more. " - ansible: professormanhattan.motrix cask: motrix choco: motrix flatpak: net.agalwood.Motrix @@ -6961,7 +6838,6 @@ softwarePackages: _post:cask: multipass set local.driver=virtualbox _post:choco: multipass set local.driver=virtualbox _short: "Multipass is a lightweight VM manager for Linux, Windows, and macOS. " - ansible: professormanhattan.multipass cask: multipass choco: multipass snap: multipass @@ -7061,6 +6937,7 @@ softwarePackages: _github: https://github.com/denisidoro/navi _home: https://github.com/denisidoro/navi _name: Navi + _preload: true _repology: navi _short: "navi is a command-line cheat sheet tool that helps users navigate commands more efficiently. " brew: navi @@ -7082,7 +6959,6 @@ softwarePackages: _home: https://xwmx.github.io/nb _name: nb _short: "nb is a command-line note-taking, bookmarking, and knowledge base application for developers. " - ansible: professormanhattan.nb basher: xwmx/nb bpkg: xwmx/nb brew: nb @@ -7241,7 +7117,6 @@ softwarePackages: sudo: true _serviceEnabled: true _short: "Netdata is an open-source real-time performance monitoring tool for system administrators and developers. " - ansible: professormanhattan.netdata brew: netdata pacman: netdata port: netdata @@ -7298,7 +7173,6 @@ softwarePackages: _service: nginx _serviceEnabled: true _short: "nginx is a popular open-source web server known for its high performance, stability, and scalability. " - ansible: professormanhattan.nginx apt: nginx brew: nginx choco: nginx @@ -7320,7 +7194,6 @@ softwarePackages: _github: false _home: https://ngrok.com/) _name: Ngrok - ansible: professormanhattan.ngrok cask: ngrok choco: ngrok snap: ngrok @@ -7365,7 +7238,6 @@ softwarePackages: _name: Nmap _post:snap: sudo snap connect nmap:network-control _short: "Nmap is a popular open-source network scanning tool used for network discovery and security auditing. " - ansible: professormanhattan.nmap apt: nmap brew: nmap choco: nmap @@ -7394,7 +7266,6 @@ softwarePackages: _home: https://nodejs.org/en/ _name: Node.js _short: "Node.js is an open-source JavaScript runtime built on Chrome's V8 JavaScript engine. " - ansible: professormanhattan.nodejs brew: node scoop: nodejs node-prune: @@ -7421,7 +7292,6 @@ softwarePackages: _name: HashiCorp Nomad _service: nomad _short: "Nomad is a cluster manager and scheduler designed by HashiCorp for deploying and managing containerized and non-containerized applications at scale. " - ansible: professormanhattan.nomad brew: nomad choco: nomad yay: nomad-git @@ -7434,16 +7304,6 @@ softwarePackages: cargo: nomino github: github.com/yaa110/nomino yay: nomino - nordvpn: - _bin: null - _deprecated: Deprecated in favor of leveraging ProtonVPN as the primary VPN service. - _desc: "[NordVPN](https://nordvpn.com/) is a virtual private network service provider. It has desktop applications for Windows, macOS, and Linux, mobile apps for Android and iOS, as well as an application for Android TV. Manual setup is available for wireless routers, NAS devices and other platforms." - _docs: https://support.nordvpn.com/ - _github: https://github.com/jotyGill/openpyn-nordvpn - _home: https://nordvpn.com/ - _name: NordVPN - _short: "openpyn-nordvpn is a script that simplifies connecting to NordVPN servers using the OpenVPN protocol on Linux systems. " - ansible: professormanhattan.nordvpn normit: _bin: normit _deps: @@ -7452,7 +7312,6 @@ softwarePackages: _github: https://github.com/pawurb/normit _name: Normit _short: "normit is a command-line tool for translating text using multiple translation engines. " - ansible: professormanhattan.normit npm: normit notion: _app: Notion.app @@ -7637,7 +7496,6 @@ softwarePackages: _home: https://onionshare.org/ _name: OnionShare _short: "OnionShare is a tool that allows you to securely and anonymously share files over the Tor network. " - ansible: professormanhattan.onionshare apt: onionshare cask: onionshare choco: onionshare @@ -7881,7 +7739,6 @@ softwarePackages: _home: https://www.packer.io/ _name: Packer _short: "Packer is an open-source tool for creating identical machine images for multiple platforms from a single source configuration. " - ansible: professormanhattan.packer apt: packer brew: packer choco: packer @@ -7920,7 +7777,6 @@ softwarePackages: _home: https://pandoc.org/ _name: Pandoc _short: "Pandoc is a versatile tool for converting between various document formats. " - ansible: professormanhattan.pandoc apt: pandoc brew: - pandoc @@ -7999,7 +7855,6 @@ softwarePackages: _home: https://peco.github.io/ _name: Peco _short: "Peco is a interactive filtering tool for the command line. " - ansible: professormanhattan.peco apt: peco brew: peco choco: peco @@ -8049,7 +7904,6 @@ softwarePackages: _home: https://www.pgcli.com/ _name: pgcli _short: "pgcli is a command-line interface for PostgreSQL with auto-completion and syntax highlighting. " - ansible: professormanhattan.pgcli brew: pgcli choco: pgcli pipx: pgcli @@ -8065,7 +7919,6 @@ softwarePackages: _name: PHP _service: php _short: "The official repository for the PHP programming language source code. " - ansible: professormanhattan.php apt: php brew: php choco: php @@ -8263,16 +8116,6 @@ softwarePackages: _name: "PinApp " _short: "PinApp is a simple command-line tool for pinning applications to the macOS dock. " flatpak: io.github.fabrialberio.pinapp - pip: - _bin: pip - _deprecated: The `pip` installation is handled by the `install-program` program bundled with Install Doctor. - _desc: "[pip](https://pypi.org/project/pip/) is a package-management system written in Python used to install and manage software packages. It connects to an online repository of public and paid-for private packages, called the Python Package Index." - _docs: https://pip.pypa.io/en/stable/user_guide/ - _github: https://github.com/pypa/pip - _home: https://pip.pypa.io/en/stable/ - _name: PIP - _short: "pip is a package installer for Python. " - ansible: professormanhattan.pip pipedream-cli: _bin: pd _desc: Connect APIs, remarkably fast. Free for developers. @@ -8348,7 +8191,6 @@ softwarePackages: _github: false _home: https://www.plex.tv/ _name: Plex - ansible: professormanhattan.plex cask: plex choco: plex flatpak: tv.plex.PlexDesktop @@ -8423,7 +8265,6 @@ softwarePackages: _home: https://pnpm.io/ _name: pnpm _short: "pnpm is a fast, disk space-efficient package manager for Node.js projects. " - ansible: professormanhattan.pnpm brew: pnpm npm: pnpm scoop: pnpm @@ -8467,7 +8308,6 @@ softwarePackages: _home: https://python-poetry.org/ _name: Poetry _short: "Poetry is a Python dependency management and packaging tool that simplifies and streamlines the process of managing Python projects. " - ansible: professormanhattan.poetry brew: poetry yay: python-poetry-git polybar: @@ -8571,7 +8411,6 @@ softwarePackages: _home: https://www.postman.com/ _name: Postman _short: "postman-app-support is a repository for Postman app support resources. " - ansible: professormanhattan.postman cask: postman choco: postman flatpak: com.getpostman.Postman @@ -8596,7 +8435,6 @@ softwarePackages: _name: Powershell _post:cask: brew install mono-libgdiplus _short: "PowerShell is a cross-platform task automation and configuration management framework. " - ansible: professormanhattan.powershell cask: powershell snap: powershell --classic pppc-utility: @@ -8622,11 +8460,6 @@ softwarePackages: _name: PrefSniff _short: "prefsniff is a tool that monitors and logs changes to macOS system preferences. " pipx: prefsniff - prepare: - _bin: null - _desc: An Ansible Role that prepares hosts for playbook execution - _github: false - ansible: professormanhattan.prepare prettier: _bin: prettier _desc: "[Prettier](https://prettier.io/docs/en/index.html) is an opinionated code formatter. It enforces a consistent style by parsing your code and re-printing it with its own rules that take the maximum line length into account, wrapping code when necessary" @@ -8869,7 +8702,6 @@ softwarePackages: _github: https://github.com/ericchiang/pup _name: pup _short: "pup is a command line tool for parsing HTML. " - ansible: professormanhattan.pup brew: pup github: github.com/ericchiang/pup go: github.com/ericchiang/pup@latest @@ -8950,7 +8782,6 @@ softwarePackages: _home: https://www.qbittorrent.org/ _name: qBittorrent _short: "qBittorrent is an open-source BitTorrent client that aims to be a free alternative to µTorrent. " - ansible: professormanhattan.qbittorrent apt: qbittorrent cask: qbittorrent choco: qbittorrent @@ -9090,7 +8921,6 @@ softwarePackages: _home: https://www.raspberrypi.com/software/ _name: Raspberry Pi Imager _short: "rpi-imager is a tool for easily flashing operating system images onto SD cards for Raspberry Pi devices. " - ansible: professormanhattan.raspberryimager cask: raspberry-pi-imager choco: rpi-imager dnf: rpi-imager @@ -9120,7 +8950,6 @@ softwarePackages: _home: https://rclone.org/ _name: Rclone _short: "rclone is a command-line program to manage files on cloud storage. " - ansible: professormanhattan.rclone apt: rclone brew:linux: rclone choco: @@ -9253,7 +9082,6 @@ softwarePackages: _home: https://restic.net/ _name: Restic _short: "restic is an open-source backup program that is fast, secure, and efficient. " - ansible: professormanhattan.restic apk: restic apt: restic brew: restic @@ -9281,7 +9109,6 @@ softwarePackages: _github: https://github.com/BurntSushi/ripgrep _name: ripgrep _short: "ripgrep is a fast, line-oriented search tool that recursively searches your current directory for a regex pattern while respecting your gitignore rules. " - ansible: professormanhattan.ripgrep apt: ripgrep brew: ripgrep cargo: ripgrep @@ -9405,7 +9232,6 @@ softwarePackages: _home: https://www.ruby-lang.org/en/ _name: Ruby _short: "Ruby is an open-source programming language known for its simplicity and productivity. " - ansible: professormanhattan.ruby apt: ruby-dev brew: ruby choco: ruby @@ -9451,7 +9277,6 @@ softwarePackages: _home: https://www.rust-lang.org/ _name: Rust _short: "rust-lang/rust is the official Rust programming language repository on GitHub. " - ansible: professormanhattan.rust brew: rust choco: rust dnf: @@ -9512,7 +9337,6 @@ softwarePackages: _github: https://github.com/peak/s5cmd _name: s5cmd _short: "s5cmd is a command-line utility for managing Amazon S3 storage. It provides fast and efficient operations for uploading, downloading, and managing objects in S3 buckets. " - ansible: professormanhattan.s5cmd brew: peak/tap/s5cmd github: github.com/peak/s5cmd go: github.com/peak/s5cmd@latest @@ -9570,7 +9394,6 @@ softwarePackages: _name: Sanoid _short: "Sanoid is a tool for creating and managing ZFS snapshots. " _when:linux: command -v zfs > /dev/null && ! zfs list - ansible:linux: professormanhattan.sanoid apt: - libcapture-tiny-perl - libconfig-inifiles-perl @@ -9624,7 +9447,6 @@ softwarePackages: _github: https://github.com/Genymobile/scrcpy _name: scrcpy _short: "scrcpy is a free and open-source tool that allows you to display and control Android devices connected via USB or TCP/IP. " - ansible: professormanhattan.scrcpy apt: scrcpy brew: scrcpy choco: scrcpy @@ -9740,12 +9562,6 @@ softwarePackages: _name: "Secretive " _short: "Secretive is a macOS app that securely stores and manages your SSH keys in the Secure Enclave of your Mac. " cask: secretive - security: - _bin: null - _desc: This role turns on auto-updates and configures sudo, for instance. - _github: false - _name: Security - ansible: professormanhattan.security semantic-release: _bin: semantic-release _desc: "[semantic-release](https://semantic-release.gitbook.io) automates the whole package release workflow including: determining the next version number, generating the release notes, and publishing the package" @@ -9843,8 +9659,6 @@ softwarePackages: _home: https://neurobin.org/projects/softwares/unix/shc/ _name: shc _short: "shc is a shell script compiler that converts shell scripts into C code for faster execution. " - ansible:darwin: professormanhattan.shc - ansible:linux: professormanhattan.shc brew: shc port: shc shdoc: @@ -9855,8 +9669,6 @@ softwarePackages: _github: https://github.com/reconquest/shdoc _name: shdoc _short: "shdoc is a tool for generating documentation from shell scripts. " - ansible:darwin: professormanhattan.shdoc - ansible:linux: professormanhattan.shdoc script:darwin: cd /tmp && git clone --recursive https://github.com/reconquest/shdoc && cd shdoc && sudo make install && cd /tmp && sudo rm -rf shdoc script:linux: cd /tmp && git clone --recursive https://github.com/reconquest/shdoc && cd shdoc && sudo make install && cd /tmp && sudo rm -rf shdoc yay: shdoc-git @@ -9908,7 +9720,6 @@ softwarePackages: _home: https://pkg.go.dev/mvdan.cc/sh/v3 _name: shfmt _short: "mvdan/sh is a shell parser and formatter written in Go. " - ansible: professormanhattan.shfmt apk: shfmt brew: shfmt github: github.com/mvdan/sh @@ -9934,7 +9745,6 @@ softwarePackages: _home: https://shotcut.org/ _name: Shotcut _short: "Shotcut is an open-source video editing software that offers a range of features for creating and editing videos. " - ansible: professormanhattan.shotcut apt: shotcut cask: shotcut choco: shotcut @@ -10006,6 +9816,7 @@ softwarePackages: _desc: Skate is a personal key-value store. Use it to save and retrieve anything you’d like—even binary data. It’s fully encrypted, backed up to the cloud (that you can self-host if you want) and can be synced with all your machines _github: https://github.com/charmbracelet/skate _name: skate + _preload: true _short: "Skate is a terminal-based visual layout tool for creating interactive user interfaces in Go. " brew: charmbracelet/tap/skate go: github.com/charmbracelet/skate@latest @@ -10039,7 +9850,6 @@ softwarePackages: _home: https://www.skype.com/en/ _name: Skype _short: "$'Not open-source' is a string enclosed in single quotes preceded by a dollar sign and is typically used in Unix-like systems to enable escape sequences like \\n for new lines. " - ansible: professormanhattan.skype cask: skype choco: skype flatpak: com.skype.Client @@ -10054,7 +9864,6 @@ softwarePackages: _home: https://slack.com/ _name: Slack _short: "SlackTextViewController is a library for iOS that provides a chat interface similar to Slack. " - ansible: professormanhattan.slack cask: slack choco: slack flatpak: com.slack.Slack @@ -10066,7 +9875,6 @@ softwarePackages: _github: https://github.com/erroneousboat/slack-term _name: slack-term _short: "slack-term is a terminal-based Slack client that allows you to chat on Slack from the command line. " - ansible: professormanhattan.slackterm go: github.com/erroneousboat/slack-term@latest slides: _bin: slides @@ -10242,6 +10050,7 @@ softwarePackages: _github: https://github.com/sqlite/sqlite _home: https://sqlite.org/index.html _name: SQLite + _preload: true _short: "SQLite is a lightweight, self-contained, serverless, zero-configuration, transactional SQL database engine. " apt: sqlite3 brew: sqlite @@ -10255,19 +10064,12 @@ softwarePackages: _desc: "Squid is a widely-used caching proxy server that supports HTTP, HTTPS, FTP, and more. It helps improve web server performance by caching frequently accessed content, reducing bandwidth usage, and \nproviding access control features. Squid is open-source and highly configurable, making it popular for improving web browsing speeds and security. It is compatible with various operating systems and is \nknown for its stability and extensibility through plugins. The project is actively maintained and has a large community of users and developers contributing to its ongoing development. " _github: https://github.com/squid-cache/squid _name: Squid - _preload: true _service: squid _short: "Squid is a caching proxy server that supports HTTP, HTTPS, FTP, and more. " apt: squid brew: squid dnf: squid pacman: squid - ssh: - _bin: null - _desc: On top of tightening up SSH security settings, this role also installs fail2ban on Linux systems. If provided, the role will also populate all your SSH keys and set their permissions appropriately - _github: false - _name: SSH - ansible: professormanhattan.ssh ssh-vault: _bin: ssh-vault _desc: "[sshvault](https://ssh-vault.com/) lets you encrypt/decrypt using SSH private keys. It is written in Go and the documentation can be read in under a minute." @@ -10276,7 +10078,6 @@ softwarePackages: _home: https://ssh-vault.com/ _name: ssh-vault _short: "ssh-vault is a tool for encrypting and decrypting secrets using SSH keys. " - ansible: professormanhattan.sshvault brew: ssh-vault github: github.com/ssh-vault/ssh-vault sshfs: @@ -10298,6 +10099,7 @@ softwarePackages: _github: https://github.com/kevinburke/sshpass _home: https://sourceforge.net/projects/sshpass/ _name: sshpass + _preload: true _short: "sshpass is a tool that allows non-interactive SSH password authentication. " apt: sshpass brew: hudochenkov/sshpass/sshpass @@ -10369,14 +10171,6 @@ softwarePackages: _name: Starred _short: "starred is a tool that helps you manage your starred repositories on GitHub. " pipx: starred - starship: - _bin: null - _deprecated: Deprecated in favor of alternative terminal status prompts such as PowerLevel10k. - _desc: "[Starship](https://starship.rs/) is the minimal, blazing fast, and extremely customizable prompt for any shell! It shows the information you need, while staying sleek and minimal. Unlike most other prompts, it is compatible with nearly every type of terminal. If you want to retain the same look and feel across different terminals, then look no further." - _github: https://github.com/starship/starship - _name: Starship - _short: "Starship is a customizable, fast, and minimal prompt for any shell. " - ansible: professormanhattan.starship statcode: _bin: statcode _desc: "statcode is a command-line tool available on GitHub at https://github.com/shobrook/statcode. It allows you to quickly view HTTP status codes and their definitions. By providing a status code as an \nargument, it returns the corresponding status code along with a brief description. This tool can be handy for developers and system administrators to quickly reference HTTP status codes without needing \nto search online. It simplifies the process of understanding and working with HTTP status codes in a terminal environment. " @@ -10489,14 +10283,6 @@ softwarePackages: _short: "SVGO is a tool for optimizing SVG files, reducing their size without affecting quality. " brew: svgo npm: svgo - swarm: - _bin: null - _desc: Docker Swarm is an orchestration management tool that runs Docker applications. It helps in creating and deploying a cluster of Docker nodes - _docs: https://docs.docker.com/engine/swarm/ - _github: https://github.com/moby/swarmkit - _name: Docker Swarm - _short: "swarmkit is a toolkit for orchestrating distributed systems at any scale. " - ansible: professormanhattan.swarm swiftbar: _app: SwiftBar.app _desc: "SwiftBar is a macOS menu bar customization tool that allows users to add custom scripts, widgets, and plugins to their menu bar. It is highly customizable and extensible, enabling users to display \nvarious information such as system stats, weather, calendar events, and more directly in the menu bar. SwiftBar supports scripting in languages like Shell, Python, Ruby, and JavaScript, making it \nversatile for users with different scripting preferences. It provides a simple yet powerful way to enhance the functionality and appearance of the macOS menu bar. " @@ -10540,7 +10326,6 @@ softwarePackages: _home: https://swh.app/ _name: SwitchHosts _short: "SwitchHosts is a tool for managing and switching between multiple hosts files on macOS. " - ansible: professormanhattan.switchhosts appimage: oldj/SwitchHosts cask: switchhosts choco: switchhosts @@ -10604,7 +10389,6 @@ softwarePackages: _home: https://sysdig.com/ _name: sysdig _short: "draios is a GitHub repository belonging to a company that specializes in system monitoring and troubleshooting tools. " - ansible: professormanhattan.sysdig brew: sysdig pacman: - sysdig @@ -10647,7 +10431,6 @@ softwarePackages: _home: https://crates.io/crates/t-rec _name: t-rec _short: "t-rec-rs is a terminal-based screen recorder written in Rust. " - ansible: professormanhattan.trec brew: t-rec cargo: t-rec port: t-rec @@ -10678,10 +10461,10 @@ softwarePackages: _github: https://github.com/tailscale/tailscale _home: https://tailscale.com/ _name: Tailscale + _preload: true _service:brew: tailscale _service:pacman: tailscaled _short: "Tailscale is a secure mesh VPN that makes it easy to connect your devices securely. " - ansible: professormanhattan.tailscale brew: tailscale cask: tailscale choco: tailscale @@ -10722,6 +10505,7 @@ softwarePackages: _github: https://github.com/go-task/task _home: https://taskfile.dev _name: Task + _preload: true _short: "Task is a simple task runner / build tool for Go projects. " brew: go-task choco: go-task @@ -10781,7 +10565,6 @@ softwarePackages: _github: https://github.com/gravitational/teleport _name: Teleport _short: "Teleport is an open-source tool for securely accessing SSH servers and Kubernetes clusters. " - ansible: professormanhattan.teleport brew: teleport pkg: teleport yay: teleport-bin @@ -10823,7 +10606,6 @@ softwarePackages: _github: false _home: https://www.termius.com/ _name: Termius - ansible: professormanhattan.termius brew: termius choco: termius pipx: termius @@ -10862,7 +10644,9 @@ softwarePackages: _github: https://github.com/tfutils/tfenv _home: https://github.com/tfutils/tfenv _name: tfenv - _short: "tfenv is a tool for managing multiple versions of Terraform. " + _short: tfenv is a tool for managing multiple versions of Terraform. + _post: | + tfenv use latest ansible:darwin: professormanhattan.tfenv ansible:linux: professormanhattan.tfenv brew: tfenv @@ -10874,7 +10658,6 @@ softwarePackages: _github: https://github.com/terraform-linters/tflint _name: tflint _short: "tflint is a Terraform linter that helps in detecting errors in Terraform configurations. " - ansible: professormanhattan.tflint brew: tflint choco: tflint github: github.com/terraform-linters/tflint @@ -11010,7 +10793,6 @@ softwarePackages: _github: https://github.com/tmux/tmux _name: tmux _short: "tmux is a terminal multiplexer for Unix-like operating systems that allows multiple terminal sessions to be accessed and controlled from a single window. " - ansible: professormanhattan.tmux apt: tmux brew: - awk @@ -11133,7 +10915,6 @@ softwarePackages: _github: https://github.com/MrRaindrop/tree-cli _name: tree-cli _short: "tree-cli is a command-line tool that generates directory trees in a visually appealing way. " - ansible: professormanhattan.tree apt: tree brew: tree choco: tree @@ -11210,6 +10991,7 @@ softwarePackages: _github: https://github.com/microsoft/TypeScript _home: https://www.typescriptlang.org/ _name: TypeScript + _preload: true _short: "TypeScript is a superset of JavaScript that adds static typing to the language, making it easier to build and maintain large-scale applications. " brew: typescript npm: tsc @@ -11230,16 +11012,6 @@ softwarePackages: _name: ugm _short: "ugm is a tool for managing Git repositories. " go: github.com/ariasmn/ugm@latest - ulauncher: - _bin: ulauncher - _deprecated: Deprecated in favor of alternative app launchers. - _desc: "[Ulauncher](https://ulauncher.io/) is a software packaging and deployment system developed by Canonical for operating systems that use the Linux kernel. The packages, called ulaunchers, and the tool for using them, ulauncher, work across a range of Linux distributions and allow upstream software developers to distribute their applications directly to users. Ulaunchers are self-contained applications running in a sandbox with mediated access to the host system." - _docs: https://docs.ulauncher.io/ - _github: https://github.com/Ulauncher/Ulauncher/ - _home: https://ulauncher.io/ - _name: Ulauncher - _short: "Ulauncher is a fast application launcher for Linux with a minimal design and customizable features. " - ansible: professormanhattan.ulauncher ultra: _bin: ultra _desc: Ultra fast monorepo script runner and build tool @@ -11253,6 +11025,7 @@ softwarePackages: _bin: unbuffer _github: false _name: Unbuffer + _preload: true apt: unbuffer brew: expect dnf: unbuffer @@ -11279,7 +11052,6 @@ softwarePackages: _github: https://github.com/akavel/up _name: Ultimate Plumber (up) _short: "up is a tool for writing command-line applications in pure Bash, without external dependencies. " - ansible: professormanhattan.up brew: up github: github.com/akavel/up pkg: up @@ -11310,7 +11082,6 @@ softwarePackages: _home: https://upx.github.io/ _name: UPX _short: "UPX is a versatile executable packer for various platforms. " - ansible: professormanhattan.upx apt: upx brew: upx choco: upx @@ -11353,7 +11124,6 @@ softwarePackages: _home: https://www.vagrantup.com/ _name: Vagrant _short: "Vagrant is an open-source tool for building and managing virtual machine environments in a single workflow. " - ansible: professormanhattan.vagrant apt: vagrant brew: hashicorp/tap/vagrant cask: vagrant @@ -11379,7 +11149,6 @@ softwarePackages: _name: Vagrant VMWare Utility _short: "vagrant-vmware-desktop is a plugin for Vagrant that allows users to manage VMware Desktop virtual machines. " _when:cask: "! test -f /opt/vagrant-vmware-desktop/bin/vagrant-vmware-utility" - ansible: professormanhattan.vmware cask: vagrant-vmware-utility choco: vagrant-vmware-utility script: rm -rf /tmp/vagrant-vmware-utility_1.0.21_linux_amd64.zip && curl https://releases.hashicorp.com/vagrant-vmware-utility/1.0.21/vagrant-vmware-utility_1.0.21_linux_amd64.zip -o /tmp/vagrant-vmware-utility_1.0.21_linux_amd64.zip && unzip /tmp/vagrant-vmware-utility_1.0.21_linux_amd64.zip && sudo mv -f /tmp/vagrant-vmware-utility /usr/local/bin/vagrant-vmware-utility && sudo chmod +x /usr/local/bin/vagrant-vmware-utility @@ -11402,7 +11171,6 @@ softwarePackages: _service: vault _service:brew: hashicorp/tap/vault _short: "Vault is a tool for securely accessing secrets. " - ansible: professormanhattan.vault brew: hashicorp/tap/vault yay: vault-cli vdirsyncer: @@ -11480,8 +11248,8 @@ softwarePackages: _github: https://github.com/vim/vim _home: https://www.vim.org/ _name: VIM + _preload: true _short: "Vim is a highly configurable text editor built for efficiency and speed, with a focus on keyboard shortcuts for navigation and editing. " - ansible: professormanhattan.vim apt: vim brew: vim choco: vim @@ -11513,7 +11281,6 @@ softwarePackages: sudo dnf -y install kernel-headers kernel-devel dkms elfutils-libelf-devel qt5-qtx11extras _short: "mirror/vbox is a mirror of the VirtualBox repository on GitHub. " _todo: Add support for arm64 - currently brew install --cask virtualbox requires intel 64 bit - ansible: professormanhattan.virtualbox apt: virtualbox cask: virtualbox choco: virtualbox @@ -11549,7 +11316,6 @@ softwarePackages: _home: https://www.videolan.org/vlc/ _name: VLC Media Player _short: "VLC Media Player: Open-source multimedia player that supports various audio and video formats, streaming protocols, and more. " - ansible: professormanhattan.vlc apt: vlc cask: vlc choco: vlc @@ -11564,7 +11330,6 @@ softwarePackages: _github: false _home: https://www.vmware.com/ _name: VMWare - ansible: professormanhattan.vmware cask: vmware-fusion script:linux: | if ! command -v vmware > /dev/null; then @@ -11590,16 +11355,10 @@ softwarePackages: _github: https://github.com/volta-cli/volta _home: https://volta.sh _name: Volta + _preload: true _short: "Volta is a tool for managing JavaScript command-line tools. " - ansible: professormanhattan.volta brew: volta scoop: volta - vpn: - _bin: null - _desc: You can populate a configuration to power this role. When configured properly, the system's built-in VPN client will be configured with your desired settings. - _github: false - _name: System VPN - ansible: professormanhattan.vpn vscode: _app: Visual Studio Code.app _bin: code @@ -11609,7 +11368,6 @@ softwarePackages: _home: https://code.visualstudio.com/ _name: Visual Studio Code _short: "Visual Studio Code is a free source-code editor made by Microsoft for Windows, Linux, and macOS. " - ansible: professormanhattan.vscode cask: visual-studio-code choco: vscode flatpak: com.visualstudio.code @@ -11659,7 +11417,6 @@ softwarePackages: _github: https://github.com/wailsapp/wails _name: Wails _short: "Wails is a framework for building desktop apps using Go and Web technologies. " - ansible: professormanhattan.wails go: github.com/wailsapp/wails/cmd/wails@latest wallpaper-cli: _bin: wallpaper @@ -11675,6 +11432,7 @@ softwarePackages: _github: false _home: https://cloudflarewarp.com/ _name: Cloudflare WARP Client + _preload: true apt: cloudflare-warp cask: cloudflare-warp choco: warp @@ -11723,7 +11481,6 @@ softwarePackages: _github: https://github.com/facebook/watchman _name: Watchman _short: "Watchman is a tool by Facebook for watching changes in the filesystem. " - ansible: professormanhattan.watchman brew: watchman choco: watchman port: watchman @@ -11736,7 +11493,6 @@ softwarePackages: _home: https://www.waypointproject.io/ _name: HashiCorp Waypoint _short: "Waypoint is a tool by HashiCorp for building, deploying, and releasing applications across any platform. " - ansible: professormanhattan.waypoint brew: hashicorp/tap/waypoint scoop: waypoint wazuh: @@ -11820,7 +11576,7 @@ softwarePackages: _github: false _home: https://www.gnu.org/software/wget/ _name: wget - ansible: professormanhattan.wget + _preload: true apk: wget apt: wget brew: wget @@ -11926,6 +11682,7 @@ softwarePackages: _desc: "WireGuard Tools Repository \n\nThe WireGuard Tools repository is the official collection of tools for the WireGuard VPN protocol. It includes utilities for configuring and managing WireGuard tunnels on various platforms. The tools \nare designed to be lightweight, secure, and easy to use, making them popular for setting up secure VPN connections. The repository is actively maintained by the WireGuard development team and is open \nsource, allowing users to contribute, report issues, and stay up to date with the latest developments in the WireGuard ecosystem. " _github: https://github.com/WireGuard/wireguard-tools _name: WireGuard Tools + _preload: true _short: "WireGuard Tools is a set of utilities for configuring and managing the WireGuard VPN protocol. " apk: wireguard-tools apt: wireguard @@ -12044,7 +11801,6 @@ softwarePackages: _home: https://github.com/blangel/wrk _name: wrk _short: "wrk is a modern HTTP benchmarking tool designed for high performance. " - ansible: professormanhattan.wrk apt: wrk brew: wrk pacman: wrk @@ -12055,7 +11811,6 @@ softwarePackages: _desc: Sets up Windows Subsystem For Linux _github: false _name: wsl - ansible: professormanhattan.wsl x64dbg: _bin: x64dbg _desc: An open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis. @@ -12225,6 +11980,7 @@ softwarePackages: _desc: "xz is a compression utility that provides high compression ratios and fast decompression. It supports various compression formats like LZMA and LZMA2, and it can compress single files or whole \ndirectories. The utility is commonly used to compress files for distribution or archival purposes. It is open-source and available on GitHub at https://github.com/xz-mirror/xz for users to download, \ncontribute, or report issues. " _github: https://github.com/xz-mirror/xz _name: xz + _preload: true _short: "xz is a compression utility that provides high compression ratios and fast decompression. " apk: xz apt: xz @@ -12249,7 +12005,6 @@ softwarePackages: _github: https://github.com/mptre/yank _name: yank _short: "Yank is a tool that allows you to copy text from your terminal to your clipboard. " - ansible: professormanhattan.yank apt: yank brew: yank choco: win32yank @@ -12279,7 +12034,6 @@ softwarePackages: _name: Yarn _preload: true _short: "Yarn Berry is a next-generation package manager for JavaScript that aims to improve performance and reliability. " - ansible: professormanhattan.yarn brew: yarn choco: yarn npm: yarn @@ -12322,7 +12076,6 @@ softwarePackages: _home: https://youtube-dl.org/ _name: youtube-dl _short: "youtube-dl is a command-line tool for downloading videos from YouTube and other websites. " - ansible: professormanhattan.youtubedl brew: youtube-dl pipx: youtube-dl port: youtube-dl @@ -12364,7 +12117,6 @@ softwarePackages: _name: yq _preload: true _short: "yq is a lightweight and portable command-line YAML processor. " - ansible: professormanhattan.yq apk: yq brew: yq choco: yq @@ -12498,7 +12250,6 @@ softwarePackages: _home: https://zoom.us/ _name: Zoom _short: "$'Not open-source' is a string enclosed in single quotes preceded by a dollar sign and is a way to represent special characters in zsh shell. " - ansible: professormanhattan.zoom cask: zoom choco: zoom flatpak: us.zoom.Zoom @@ -12511,7 +12262,6 @@ softwarePackages: _name: zoxide _preload: true _short: "zoxide is a blazing fast replacement for cd, allowing you to navigate your filesystem with ease using fuzzy matching and tracking your most used directories. " - ansible: professormanhattan.zoxide brew: zoxide zsh: _bin: zsh @@ -12531,6 +12281,7 @@ softwarePackages: _desc: "zsh-completions is a repository on GitHub maintained by the zsh-users organization. It provides a collection of completion scripts for various commands and utilities to enhance auto-completion \ncapabilities in the zsh shell. These completion scripts help users by suggesting and completing command options, arguments, and file paths as they type commands in the terminal. The repository is \nregularly updated to support new commands and improve existing completions, making it a valuable resource for zsh users looking to streamline their command-line experience. " _github: https://github.com/zsh-users/zsh-completions _name: ZSH Completions + _preload: true _short: "zsh-completions is a repository that provides additional completion definitions for the Zsh shell, enhancing auto-completion capabilities for various commands and utilities. " brew: zsh-completions zx: