Compare commits

..

16 Commits

Author SHA1 Message Date
443361cddb chore(scripts): remove unused VERBOSE declarations
Remove VERBOSE="${VERBOSE:-0}" from scripts that never reference
$VERBOSE after setting it. The variable is already set in
scripts/shared.sh line 5.
2026-02-05 22:57:20 +02:00
083d30a0c3 fix(scripts): fix shared.sh guard logic and echo -e portability
- shared.sh: simplify guard logic, remove misleading warning message,
  use ${VAR:-} pattern to avoid unbound variable error
- install-cheat-purebashbible.sh: replace echo -e with printf for
  POSIX portability
2026-02-05 22:55:27 +02:00
81190c051a fix(scripts): standardize source paths and quoting
- install-composer.sh: use $DOTFILES instead of $HOME/.dotfiles
- install-macos-defaults.sh: use $DOTFILES, replace which with command -v
- install-xcode-cli-tools.sh: quote command substitution
- create-nvim-keymaps.sh: quote $DEST in nvim redir command
2026-02-05 22:53:04 +02:00
de773ad68f refactor(scripts): add set -euo pipefail to all installer scripts
Add strict error handling to all scripts:
- 13 scripts get `set -euo pipefail`
- install-macos-defaults.sh gets `set -uo pipefail` (without -e) because
  defaults write commands may fail on newer macOS versions
- install-cargo-packages.sh: also add missing source of shared.sh
2026-02-05 22:51:40 +02:00
e8725c4b47 fix(scripts): use safe temp directories and fix composer exit code
- install-ntfy.sh: use mktemp -d with cleanup trap instead of /tmp/ntfy_*
- install-git-crypt.sh: use mktemp -d with cleanup trap instead of /tmp/git-crypt
- install-composer.sh: only move composer.phar if installation succeeded
2026-02-05 22:49:36 +02:00
b8070e2815 fix(scripts): add missing exit after error handlers
Critical bugs where error paths print a message but don't stop execution:
- install-fonts.sh: cd failure now exits properly
- install-ntfy.sh: unsupported OS case now exits with error
- install-git-crypt.sh: git clone and cd failures now exit properly
2026-02-05 22:44:44 +02:00
9de394d8e9 chore(python): add openapi-python-client to uv tools 2026-02-05 22:07:03 +02:00
08de5ea4a6 refactor(submodules): improve old submodule cleanup in add-submodules.sh 2026-02-05 22:07:03 +02:00
0e69b7cb16 refactor: remove dotbot-brew, dotbot-pip submodules and pipx 2026-02-05 22:07:03 +02:00
7c9096d666 fix: standardize shebangs, error handling, and minor issues in x-* scripts
Normalize shebangs to #!/usr/bin/env bash (x-env-list, x-localip).
Use XDG_CONFIG_HOME in x-change-alacritty-theme. Remove unused
VERBOSE variable in x-multi-ping. Add set -euo pipefail to x-when-down
and x-when-up. Add usage header to x-term-colors. Fix notify-call
to notify-send.sh in x-record.
2026-02-05 22:07:03 +02:00
efd9eebc85 fix: resolve critical issues in x-clean-vendordirs, x-foreach, x-ip
x-clean-vendordirs: remove broken msgr dependency (not sourced),
add set -euo pipefail. x-foreach: replace eval on command args with
direct "$@" execution, add usage guard. x-ip: add set -euo pipefail,
curl dependency check, and silent-fail flag.
2026-02-05 22:07:03 +02:00
fc8db1f5b5 refactor(path): consolidate x-path-{append,prepend,remove} as thin wrappers
Add source guard to x-path so its functions can be loaded without
executing the main logic. Rewrite standalone path scripts to source
x-path and call the appropriate function directly, eliminating code
duplication while preserving source-ability for shell integration.
2026-02-05 22:07:03 +02:00
4414e0c3b6 chore: remove unused x-mkd and x-validate-sha256sum.sh scripts
x-mkd's cd-in-subshell cannot work when executed (only sourced) and
is unused in the repo. x-validate-sha256sum.sh duplicates the
functionality of x-sha256sum-matcher.
2026-02-05 22:07:03 +02:00
abb6c9f615 refactor(dfm): clean up portability, dead code, and error handling
Add bash 4.0+ version check with macOS Homebrew bootstrap. Remove
unreachable fish shell detection and source_file function. Fix bugs:
remove dead ntfy menu entry, fix msg/msgr case mismatch in tests,
guard shift calls against empty args, quote $width, fix $"..." locale
string, fix exit 0 on apt error. Replace declare -A with indexed
array in section_scripts. Use early-return guards with msgr warn for
unavailable brew/apt. Replace exit with return in section functions.
2026-02-05 22:07:03 +02:00
57b566704e fix(lint): resolve all lint errors and remove dangling symlinks
Fix 14 editorconfig/biome errors across 6 files: update biome schema
version, replace tabs with spaces, fix continuation indents, and wrap
long lines. Remove dangling OrbStack fish completion symlinks.
2026-02-05 22:07:03 +02:00
renovate[bot]
4510e62070 chore(deps): update ivuorinen/actions action (v2026.01.21 → v2026.02.03) (#278)
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-05 17:56:56 +00:00
55 changed files with 360 additions and 592 deletions

View File

@@ -35,4 +35,4 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run PR Lint
uses: ivuorinen/actions/pr-lint@f98ae7cd7d0feb1f9d6b01de0addbb11414cfc73 # v2026.01.21
uses: ivuorinen/actions/pr-lint@f371da218e9152e7d29ee39358454e41010c36dc # v2026.02.03

View File

@@ -29,4 +29,4 @@ jobs:
issues: write
steps:
- uses: ivuorinen/actions/sync-labels@f98ae7cd7d0feb1f9d6b01de0addbb11414cfc73 # v2026.01.21
- uses: ivuorinen/actions/sync-labels@f371da218e9152e7d29ee39358454e41010c36dc # v2026.02.03

12
.gitmodules vendored
View File

@@ -4,11 +4,6 @@
url = https://github.com/anishathalye/dotbot.git
ignore = dirty
[submodule "dotbot-brew"]
path = tools/dotbot-brew
url = https://github.com/wren/dotbot-brew.git
ignore = dirty
[submodule "dotbot-include"]
path = tools/dotbot-include
url = https://gitlab.com/gnfzdz/dotbot-include.git
@@ -29,11 +24,6 @@
url = https://github.com/tmux-plugins/tmux-sessionist.git
ignore = dirty
[submodule "dotbot-pip"]
path = tools/dotbot-pip
url = https://github.com/sobolevn/dotbot-pip.git
ignore = dirty
[submodule "tmux/tmux-suspend"]
path = config/tmux/plugins/tmux-suspend
url = https://github.com/MunifTanjim/tmux-suspend.git
@@ -63,6 +53,8 @@
[submodule "tmux/tmux-resurrect"]
path = config/tmux/plugins/tmux-resurrect
url = https://github.com/tmux-plugins/tmux-resurrect.git
ignore = dirty
[submodule "tmux/catppuccin"]
path = config/tmux/plugins/catppuccin
url = https://github.com/catppuccin/tmux.git
ignore = dirty

View File

@@ -6,6 +6,5 @@ config/tmux/plugins/**
config/vim/plugged/**
node_modules
tools/antidote/**
tools/dotbot-brew/**
tools/dotbot-include/**
tools/dotbot/**

View File

@@ -5,12 +5,8 @@ git submodule sync --recursive
# dotbot and plugins
git submodule add --name dotbot \
-f https://github.com/anishathalye/dotbot.git tools/dotbot
git submodule add --name dotbot-brew \
-f https://github.com/wren/dotbot-brew.git tools/dotbot-brew
git submodule add --name dotbot-include \
-f https://gitlab.com/gnfzdz/dotbot-include.git tools/dotbot-include
git submodule add --name dotbot-pip \
-f https://github.com/sobolevn/dotbot-pip.git tools/dotbot-pip
# other repos
git submodule add --name cheat-community \
@@ -46,26 +42,64 @@ done
# Mark certain repositories shallow
git config -f .gitmodules submodule.antidote.shallow true
# remove old submodules
folders=(
"config/tmux/plugins/tpm"
"config/tmux/plugins/tmux"
"config/tmux/plugins/tmux-menus"
"tools/dotbot-crontab"
"tools/dotbot-snap"
"config/tmux/plugins/tmux-window-name"
"config/tmux/plugins/tmux-sensible"
"config/tmux/plugins/tmux-mode-indicator"
"config/tmux/plugins/tmux-yank"
"config/tmux/plugins/tmux-fzf-url"
"config/nvim-kickstart"
"local/bin/asdf"
"local/asdf"
"tools/dotbot-asdf"
_log() {
if command -v msgr > /dev/null 2>&1; then
msgr run_done "$1"
else
echo " [ok] $1"
fi
}
remove_old_submodule() {
local name="$1" path="$2"
# Remove working tree
if [ -d "$path" ]; then
rm -rf "$path"
_log "Removed $path"
fi
# Remove stale git index entry
git rm --cached "$path" 2> /dev/null || true
# Remove .git/config section keyed by path
git config --remove-section "submodule.$path" 2> /dev/null || true
# Skip name-based cleanup if no submodule name provided
[ -z "$name" ] && return 0
# Remove .git/config section keyed by name
git config --remove-section "submodule.$name" 2> /dev/null || true
# Remove .git/modules/<name>/ cached repository
if [ -d ".git/modules/$name" ]; then
rm -rf ".git/modules/$name"
_log "Removed .git/modules/$name"
fi
}
# remove old submodules (name:path pairs)
old_submodules=(
"tmux/tpm:config/tmux/plugins/tpm"
":config/tmux/plugins/tmux"
"tmux/tmux-menus:config/tmux/plugins/tmux-menus"
"dotbot-crontab:tools/dotbot-crontab"
"dotbot-snap:tools/dotbot-snap"
"tmux/tmux-window-name:config/tmux/plugins/tmux-window-name"
"tmux/tmux-sensible:config/tmux/plugins/tmux-sensible"
"tmux/tmux-mode-indicator:config/tmux/plugins/tmux-mode-indicator"
"tmux/tmux-yank:config/tmux/plugins/tmux-yank"
":config/tmux/plugins/tmux-fzf-url"
"nvim-kickstart:config/nvim-kickstart"
"asdf:local/bin/asdf"
"asdf:local/asdf"
"dotbot-asdf:tools/dotbot-asdf"
"dotbot-pip:tools/dotbot-pip"
"dotbot-brew:tools/dotbot-brew"
)
for folder in "${folders[@]}"; do
[ -d "$folder" ] \
&& rm -rf "$folder" \
&& msgr run_done "Removed old submodule $folder"
for entry in "${old_submodules[@]}"; do
name="${entry%%:*}"
path="${entry#*:}"
remove_old_submodule "$name" "$path"
done

View File

@@ -2,14 +2,14 @@
-- These globals can be set and accessed:
--
globals = {
"rawrequire",
"rawrequire",
}
--
-- These globals can only be accessed:
--
read_globals = {
"hs",
"ls",
"spoon",
"hs",
"ls",
"spoon",
}

View File

@@ -370,7 +370,7 @@ def infer_type_from_param_name(param_name: str) -> str:
# Function indicators
if (param_name in ["fn", "func", "callback", "handler", "listener",
"predicate", "filter", "mapper", "reducer"]):
"predicate", "filter", "mapper", "reducer"]):
return "function"
# Number indicators

View File

@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.1/schema.json",
"$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",

View File

@@ -1 +0,0 @@
/Applications/OrbStack.app/Contents/MacOS/../Resources/completions/fish/kubectl.fish

View File

@@ -1 +0,0 @@
/Applications/OrbStack.app/Contents/MacOS/../Resources/completions/fish/orbctl.fish

View File

@@ -260,8 +260,6 @@ brew "php@8.2", link: true
brew "php@8.3"
# Pins GitHub Actions to full hashes and versions
brew "pinact"
# Execute binaries from Python packages in isolated environments
brew "pipx"
# Python version management
brew "pyenv"
# Migrate pip packages from one Python version to another

View File

@@ -40,7 +40,8 @@ return {
operators = {},
-- miscs = {}, -- Uncomment to turn off hard-coded styles
},
lsp_styles = { -- Handles the style of specific lsp hl groups (see `:h lsp-highlight`).
-- Style of specific lsp hl groups (`:h lsp-highlight`)
lsp_styles = {
virtual_text = {
errors = { 'italic' },
hints = { 'italic' },
@@ -72,7 +73,8 @@ return {
enabled = true,
indentscope_color = '',
},
-- For more plugins integrations please scroll down (https://github.com/catppuccin/nvim#integrations)
-- More integrations:
-- github.com/catppuccin/nvim#integrations
},
}
@@ -115,7 +117,8 @@ return {
{
'dmtrKovalenko/fff.nvim',
build = function()
-- this will download prebuild binary or try to use existing rustup toolchain to build from source
-- Downloads prebuild binary or uses rustup
-- toolchain to build from source
-- (if you are using lazy you can use gb for rebuilding a plugin if needed)
require('fff.download').download_or_build_binary()
end,
@@ -124,7 +127,8 @@ return {
opts = { -- (optional)
debug = {
enabled = true, -- we expect your collaboration at least during the beta
show_scores = true, -- to help us optimize the scoring system, feel free to share your scores!
-- Share scores to help optimize scoring
show_scores = true,
},
},
-- No need to lazy-load with lazy.nvim.

View File

@@ -15,10 +15,7 @@ git submodule update --init --recursive "${DOTBOT_DIR}"
"${DOTBOT_BIN_PATH}" \
-d "${BASEDIR}" \
--plugin-dir=tools/dotbot-asdf \
--plugin-dir=tools/dotbot-brew \
--plugin-dir=tools/dotbot-include \
--plugin-dir=tools/dotbot-pip \
-c "${CONFIG}" \
"${@}"
@@ -29,10 +26,7 @@ if [ "${DOTBOT_HOST}" != "" ]; then
echo "(!) Found $DOTBOT_HOST_CONFIG" &&
"$DOTBOT_BIN_PATH" \
-d "$BASEDIR" \
--plugin-dir=tools/dotbot-asdf \
--plugin-dir=tools/dotbot-brew \
--plugin-dir=tools/dotbot-include \
--plugin-dir=tools/dotbot-pip \
-c "$DOTBOT_HOST_CONFIG" \
"${@}"
fi

View File

@@ -78,8 +78,3 @@
- shell:
# Use my dotfiles manager to install everything
- bash local/bin/dfm install all
- pipx:
file: tools/requirements-pipx.txt
stdout: true
stderr: true

View File

@@ -15,38 +15,37 @@
SCRIPT=$(basename "$0")
# Detect the current shell
CURRENT_SHELL=$(ps -p $$ -ocomm= | awk -F/ '{print $NF}')
# Require bash 4.0+ for associative arrays and mapfile
if ((BASH_VERSINFO[0] < 4)); then
echo "dfm requires bash 4.0+, found ${BASH_VERSION}"
if [[ "$(uname)" == "Darwin" ]]; then
if ! command -v brew &> /dev/null; then
echo "Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
echo "Installing modern bash via Homebrew..."
brew install bash
echo "Done. Restart your shell and run dfm again."
else
echo "Install bash 4.0+ and try again."
fi
exit 1
fi
# Function to source files based on the shell
source_file()
# shellcheck disable=SC1091
source "$DOTFILES/config/shared.sh"
# shellcheck disable=SC1090
source "${DOTFILES}/local/bin/msgr"
# Get description from a script file's @description tag
get_script_description()
{
local file=$1
case "$CURRENT_SHELL" in
fish)
if [[ -f "$file.fish" ]]; then
# shellcheck disable=SC1090
source "$file.fish"
else
echo "Fish shell file not found: $file.fish"
exit 1
fi
;;
sh | bash | zsh)
# shellcheck disable=SC1090
source "$file"
;;
*)
echo "Unsupported shell: $CURRENT_SHELL"
exit 1
;;
esac
local file="$1"
local desc
desc=$(sed -n '/@description/s/.*@description *\(.*\)/\1/p' "$file" | head -1)
echo "${desc:-No description available}"
}
# Modify the source commands to use the new function
source_file "$DOTFILES/config/shared.sh"
source_file "${DOTFILES}/local/bin/msgr"
# Menu builder
menu_builder()
{
@@ -54,9 +53,9 @@ menu_builder()
local commands=("${@:2}")
local width=60
printf "\n%s\n" "$(printf '%.s─' $(seq 1 $width))"
printf "\n%s\n" "$(printf '%.s─' $(seq 1 "$width"))"
printf "%-${width}s\n" " $title"
printf "%s\n" "$(printf '%.s─' $(seq 1 $width))"
printf "%s\n" "$(printf '%.s─' $(seq 1 "$width"))"
for cmd in "${commands[@]}"; do
local name=${cmd%%:*}
@@ -80,7 +79,6 @@ section_install()
"imagick:Install ImageMagick CLI"
"macos:Setup nice macOS defaults"
"npm-packages:Install NPM Packages"
"ntfy:Install ntfy"
"nvm-latest:Install latest lts node using nvm"
"nvm:Install Node Version Manager (nvm)"
"z:Install z"
@@ -100,6 +98,7 @@ section_install()
$0 install npm-packages
$0 install z
msgr msg "Reloading configurations again..."
# shellcheck disable=SC1091
source "$DOTFILES/config/shared.sh"
msgr yay "All done!"
;;
@@ -208,87 +207,88 @@ section_brew()
"untracked:List untracked brew packages"
)
x-have brew && {
case "$1" in
install)
brew bundle install --file="$BREWFILE" --force --quiet && msgr yay "Done!"
;;
if ! x-have brew; then
msgr warn "brew not available, skipping"
return 0
fi
update)
brew update && brew outdated && brew upgrade && brew cleanup
msgr yay "Done!"
;;
case "$1" in
install)
brew bundle install --file="$BREWFILE" --force --quiet && msgr yay "Done!"
;;
updatebundle)
# Updates .dotfiles/homebrew/Brewfile with descriptions
brew bundle dump \
--force \
--file="$BREWFILE" \
--cleanup \
--tap \
--formula \
--cask \
--describe && msgr yay "Done!"
;;
update)
brew update && brew outdated && brew upgrade && brew cleanup
msgr yay "Done!"
;;
leaves)
brew leaves --installed-on-request
;;
updatebundle)
# Updates .dotfiles/homebrew/Brewfile with descriptions
brew bundle dump \
--force \
--file="$BREWFILE" \
--cleanup \
--tap \
--formula \
--cask \
--describe && msgr yay "Done!"
;;
untracked)
declare -a BREW_LIST_ALL
while IFS= read -r line; do
BREW_LIST_ALL+=("$line")
done < <(brew list --formula --installed-on-request -1 --full-name)
while IFS= read -r c; do
BREW_LIST_ALL+=("$c")
done < <(brew list --cask -1 --full-name)
leaves)
brew leaves --installed-on-request
;;
# Remove entries that are installed as dependencies
declare -a BREW_LIST_DEPENDENCIES
while IFS= read -r l; do
BREW_LIST_DEPENDENCIES+=("$l")
done < <(brew list -1 --installed-as-dependency)
untracked)
declare -a BREW_LIST_ALL
while IFS= read -r line; do
BREW_LIST_ALL+=("$line")
done < <(brew list --formula --installed-on-request -1 --full-name)
while IFS= read -r c; do
BREW_LIST_ALL+=("$c")
done < <(brew list --cask -1 --full-name)
declare -a BREW_LIST_BUNDLED
while IFS= read -r b; do
BREW_LIST_BUNDLED+=("$b")
done < <(brew bundle list --all --file="$BREWFILE")
# Remove entries that are installed as dependencies
declare -a BREW_LIST_DEPENDENCIES
while IFS= read -r l; do
BREW_LIST_DEPENDENCIES+=("$l")
done < <(brew list -1 --installed-as-dependency)
declare -a BREW_LIST_TRACKED_WITHOUT_DEPS
for f in "${BREW_LIST_ALL[@]}"; do
# shellcheck disable=SC2199
if [[ " ${BREW_LIST_DEPENDENCIES[@]} " != *" ${f} "* ]]; then
BREW_LIST_TRACKED_WITHOUT_DEPS+=("$f")
fi
done
declare -a BREW_LIST_BUNDLED
while IFS= read -r b; do
BREW_LIST_BUNDLED+=("$b")
done < <(brew bundle list --all --file="$BREWFILE")
array_diff BREW_LIST_UNTRACKED BREW_LIST_TRACKED_WITHOUT_DEPS BREW_LIST_BUNDLED
# If there are no untracked packages, exit
if [ ${#BREW_LIST_UNTRACKED[@]} -eq 0 ]; then
msgr yay "No untracked packages found!"
exit 0
declare -a BREW_LIST_TRACKED_WITHOUT_DEPS
for f in "${BREW_LIST_ALL[@]}"; do
# shellcheck disable=SC2199
if [[ " ${BREW_LIST_DEPENDENCIES[@]} " != *" ${f} "* ]]; then
BREW_LIST_TRACKED_WITHOUT_DEPS+=("$f")
fi
done
echo "Untracked:"
for f in "${BREW_LIST_UNTRACKED[@]}"; do
echo " $f"
done
;;
array_diff BREW_LIST_UNTRACKED BREW_LIST_TRACKED_WITHOUT_DEPS BREW_LIST_BUNDLED
autoupdate)
brew autoupdate delete
brew autoupdate start 43200 --upgrade --cleanup --immediate
;;
# If there are no untracked packages, return
if [ ${#BREW_LIST_UNTRACKED[@]} -eq 0 ]; then
msgr yay "No untracked packages found!"
return 0
fi
clean) brew bundle cleanup --file="$BREWFILE" && msgr yay "Done!" ;;
echo "Untracked:"
for f in "${BREW_LIST_UNTRACKED[@]}"; do
echo " $f"
done
;;
*) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;;
esac
}
autoupdate)
brew autoupdate delete
brew autoupdate start 43200 --upgrade --cleanup --immediate
;;
! x-have brew && menu_builder "$USAGE_PREFIX" "brew not available on this system"
clean) brew bundle cleanup --file="$BREWFILE" && msgr yay "Done!" ;;
*) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;;
esac
}
section_helpers()
@@ -305,10 +305,10 @@ section_helpers()
"wezterm:Show wezterm keybindings"
)
CMD="$1"
shift
SECTION="$1"
shift
CMD="${1:-}"
[[ $# -gt 0 ]] && shift
SECTION="${1:-}"
[[ $# -gt 0 ]] && shift
case "$CMD" in
path)
@@ -379,55 +379,60 @@ section_apt()
"clean:Clean apt cache"
)
x-have apt && {
case "$1" in
upkeep)
sudo apt update \
&& sudo apt upgrade -y \
&& sudo apt autoremove -y \
&& sudo apt clean
;;
if ! x-have apt; then
msgr warn "apt not available, skipping"
return 0
fi
install)
# if apt.txt is not found, exit
[ ! -f "$DOTFILES/tools/apt.txt" ] && msgr err "apt.txt not found" && exit 0
case "$1" in
upkeep)
sudo apt update \
&& sudo apt upgrade -y \
&& sudo apt autoremove -y \
&& sudo apt clean
;;
# Load apt.txt, remove comments (even if trailing comment) and empty lines.
#
# Ignoring "Quote this to prevent word splitting."
install)
# if apt.txt is not found, return with error
if [ ! -f "$DOTFILES/tools/apt.txt" ]; then
msgr err "apt.txt not found"
return 1
fi
# Load apt.txt, remove comments (even if trailing comment) and empty lines.
#
# Ignoring "Quote this to prevent word splitting."
# shellcheck disable=SC2046
sudo apt install \
-y $(
grep -vE '^\s*#' "$DOTFILES/tools/apt.txt" \
| sed -e 's/#.*//' \
| tr '\n' ' '
)
# If there's a apt.txt file under hosts/$hostname/apt.txt,
# run install on those lines too.
HOSTNAME=$(hostname -s)
HOST_APT="$DOTFILES/hosts/$HOSTNAME/apt.txt"
[[ -f $HOST_APT ]] && {
# shellcheck disable=SC2046
sudo apt install \
-y $(
grep -vE '^\s*#' "$DOTFILES/tools/apt.txt" \
| sed -e 's/#.*//' \
| tr '\n' ' '
)
sudo apt install -y $(
grep -vE '^\s*#' "$HOST_APT" \
| sed -e 's/#.*//' \
| tr '\n' ' '
)
}
# If there's a apt.txt file under hosts/$hostname/apt.txt,
# run install on those lines too.
HOSTNAME=$(hostname -s)
HOST_APT="$DOTFILES/hosts/$HOSTNAME/apt.txt"
[[ -f $HOST_APT ]] && {
# shellcheck disable=SC2046
sudo apt install -y $(
grep -vE '^\s*#' "$HOST_APT" \
| sed -e 's/#.*//' \
| tr '\n' ' '
)
}
# Try this for an alternative way to install packages
# xargs -a <(awk '! /^ *(#|$)/' "$packagelist") -r -- sudo apt-get install -y
;;
# Try this for an alternative way to install packages
# xargs -a <(awk '! /^ *(#|$)/' "$packagelist") -r -- sudo apt-get install -y
;;
update) sudo apt update ;;
upgrade) sudo apt upgrade -y ;;
autoremove) sudo apt autoremove -y ;;
clean) sudo apt clean ;;
*) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;;
esac
}
! x-have apt && menu_builder "$USAGE_PREFIX" "apt not available on this system"
update) sudo apt update ;;
upgrade) sudo apt upgrade -y ;;
autoremove) sudo apt autoremove -y ;;
clean) sudo apt clean ;;
*) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;;
esac
}
section_docs()
@@ -534,13 +539,13 @@ section_check()
case "$1" in
a | arch)
[[ $2 == "" ]] && echo "$X_ARCH" && exit 0
[[ $X_ARCH == "$2" ]] && exit 0 || exit 1
[[ $2 == "" ]] && echo "$X_ARCH" && return 0
[[ $X_ARCH == "$2" ]] && return 0 || return 1
;;
h | host | hostname)
[[ $2 == "" ]] && echo "$X_HOSTNAME" && exit 0
[[ $X_HOSTNAME == "$2" ]] && exit 0 || exit 1
[[ $2 == "" ]] && echo "$X_HOSTNAME" && return 0
[[ $X_HOSTNAME == "$2" ]] && return 0 || return 1
;;
*) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;;
@@ -551,33 +556,18 @@ section_scripts()
{
USAGE_PREFIX="$SCRIPT scripts <command>"
# Get description from a file
get_script_description()
{
local file
local desc
file="$1"
desc=$(sed -n '/@description/s/.*@description *\(.*\)/\1/p' "$file" | head -1)
echo "${desc:-No description available}"
}
# Collect scripts and their descriptions
declare -A SCRIPT_MENU
local menu_items=()
for script in "$DOTFILES/scripts/install-"*.sh; do
if [ -f "$script" ]; then
name=$(basename "$script" .sh | sed 's/install-//')
desc=$(get_script_description "$script")
SCRIPT_MENU[$name]="$desc"
menu_items+=("$name:$desc")
fi
done
case "$1" in
"")
# Show the menu
local menu_items=()
for name in "${!SCRIPT_MENU[@]}"; do
menu_items+=("$name:${SCRIPT_MENU[$name]}")
done
menu_builder "$USAGE_PREFIX" "${menu_items[@]}"
;;
*)
@@ -609,7 +599,7 @@ section_tests()
echo " $i"
done
;;
msg)
msgr)
# shellcheck disable=SC1010
msgr done "msgr done"
msgr done_suffix "msgr done_suffix"
@@ -633,7 +623,7 @@ usage()
{
echo ""
msgr prompt "Usage: $SCRIPT <section> <command>"
echo $" Empty <command> prints <section> help."
echo " Empty <command> prints <section> help."
echo ""
section_install
echo ""
@@ -654,8 +644,8 @@ usage()
main()
{
SECTION="$1"
shift
SECTION="${1:-}"
[[ $# -gt 0 ]] && shift
# The main loop. The first keyword after $0 triggers section, or help.
case "$SECTION" in
install) section_install "$@" ;;
@@ -667,7 +657,7 @@ main()
docs) section_docs "$@" ;;
scripts) section_scripts "$@" ;;
tests) section_tests "$@" ;;
*) usage && exit 0 ;;
*) usage && return 0 ;;
esac
}

View File

@@ -8,7 +8,7 @@ set -euo pipefail
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
A_DIR="$HOME/.config/alacritty"
A_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/alacritty"
# Function to print usage information
usage()

View File

@@ -7,13 +7,15 @@
# Author: Ismo Vuorinen 2025
# License: MIT
set -euo pipefail
# Check if the user has provided a directory as an argument
if [ "$1" ]; then
if [ "${1:-}" ]; then
# Check if the directory exists
if [ -d "$1" ]; then
CLEANDIR="$1"
else
msgr err "Directory $1 does not exist."
echo "Error: Directory $1 does not exist." >&2
exit 1
fi
else
@@ -27,7 +29,7 @@ remove_node_modules_vendor()
# If the directory is a symlink, skip it
if [ -L "$dir" ]; then
msgr msg "Skipping symlink $dir"
echo "Skipping symlink $dir"
return
fi
@@ -35,18 +37,18 @@ remove_node_modules_vendor()
if [ -d "$dir" ]; then
# If node_modules or vendor folder exists, remove it and all its contents
if [ -d "$dir/node_modules" ]; then
msgr run "Removing $dir/node_modules"
echo "Removing $dir/node_modules"
rm -rf "$dir/node_modules"
fi
if [ -d "$dir/vendor" ]; then
msgr run "Removing $dir/vendor"
echo "Removing $dir/vendor"
rm -rf "$dir/vendor"
fi
# Recursively check subdirectories
for item in "$dir"/*; do
remove_node_modules_vendor "$item"
[ -d "$item" ] && remove_node_modules_vendor "$item"
done
fi
}

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# List environment variables grouped by the first part before underscore
# protecting environment variables that possibly contain sensitive information.

View File

@@ -1,18 +1,26 @@
#!/usr/bin/env bash
#
# foreach <folder> <commands that should be run to each file>
# foreach "ls -d */" "git status" # run git status in each folder
# Run a command in each directory matching a pattern.
#
# Usage: x-foreach <listing-command> <command> [args...]
# x-foreach "ls -d */" "git status"
#
# Source: https://github.com/mvdan/dotfiles/blob/master/.bin/foreach
cmd=$1
set -euo pipefail
if [ $# -lt 2 ]; then
echo "Usage: $0 <listing-command> <command> [args...]"
exit 1
fi
listing=$1
shift
for dir in $($cmd); do
for dir in $(eval "$listing"); do
(
echo "$dir"
cd "$dir" || exit 1
# shellcheck disable=SC2294,SC2034
eval "$@" # allow multiple commands like "foo && bar"
"$@"
)
done

View File

@@ -1,4 +1,14 @@
#!/usr/bin/env bash
#
# Display external IP address.
#
# Source: https://github.com/thirtythreeforty/dotfiles/blob/master/bin/extip
curl icanhazip.com "${@}"
set -euo pipefail
if ! command -v curl &> /dev/null; then
echo "Error: curl is required" >&2
exit 1
fi
curl -sf icanhazip.com

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# x-localip: script to display the local IP addresses of the system
#

View File

@@ -1,50 +0,0 @@
#!/usr/bin/env bash
#
# Create a directory and cd into it
# Usage: x-mkd <dir>
set -euo pipefail
# Set verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
# Function to print usage information
usage()
{
echo "Usage: $0 <dir>"
exit 1
}
# Function to print messages if VERBOSE is enabled
# $1 - message (string)
msg()
{
[[ "$VERBOSE" -eq 1 ]] && echo "$1"
}
# Function to create a directory and cd into it
# $1 - directory to create and cd into (string)
mkcd()
{
local dir=$1
mkdir -p "$dir" && msg "Directory $dir created"
cd "$dir" || {
msg "Failed to cd into $dir"
exit 1
}
msg "Changed directory to $dir"
}
# Main function
main()
{
if [ "$#" -ne 1 ]; then
usage
fi
mkcd "$1"
}
main "$@"

View File

@@ -1,19 +0,0 @@
# x-mkd
Create a directory and immediately `cd` into it.
## Usage
```bash
x-mkd <dir>
```
Set `VERBOSE=1` for status messages.
## Example
```bash
x-mkd project && git init
```
<!-- vim: set ft=markdown spell spelllang=en_us cc=80 : -->

View File

@@ -39,7 +39,6 @@
# Defaults
LOOP=0
SLEEP=1
VERBOSE=0
TIMEOUT=5
usage()
@@ -60,8 +59,6 @@ while [[ $# -gt 0 ]]; do
exit 0
;;
--verbose)
# shellcheck disable=SC2034
VERBOSE=1
shift
;;
--loop | --forever)

View File

@@ -227,6 +227,9 @@ do_check()
fi
}
# If sourced, provide functions without executing main logic
(return 0 2> /dev/null) && return
#######################################
# Main routine: Parse subcommand and arguments, normalize PATH,
# and dispatch to the appropriate functionality.

View File

@@ -1,44 +1,17 @@
#!/usr/bin/env bash
#
# Optimized script to append directories to PATH.
# For each given directory, it removes all duplicate occurrences from PATH
# and then appends it if the directory exists.
# Thin wrapper — delegates to x-path append.
# Can be sourced (PATH changes propagate) or executed.
#
# Usage: x-path-append <directory1> [<directory2> ...]
#
# Enable verbose output by setting the environment variable VERBOSE=1.
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
# License: MIT
VERBOSE="${VERBOSE:-0}"
# Ensure that at least one directory is provided.
[ "$#" -lt 1 ] && {
echo "Usage: $0 <directory> [<directory> ...]"
exit 1
}
# shellcheck source=./x-path
. "$(dirname "${BASH_SOURCE[0]:-$0}")/x-path"
for dir in "$@"; do
# Check if the specified directory exists.
if [ ! -d "$dir" ]; then
[ "$VERBOSE" -eq 1 ] && echo "(?) Directory '$dir' does not exist. Skipping."
continue
fi
# Remove all duplicate occurrences of the directory from PATH.
case ":$PATH:" in
*":$dir:"*)
PATH=":${PATH}:"
PATH="${PATH//:$dir:/:}"
PATH="${PATH#:}"
PATH="${PATH%:}"
[ "$VERBOSE" -eq 1 ] && echo "Removed previous occurrences of '$dir' from PATH."
;;
*) ;;
esac
# Append the directory to PATH.
export PATH="${PATH:+$PATH:}$dir"
[ "$VERBOSE" -eq 1 ] && echo "Appended '$dir' to PATH."
done
normalize_path_var
do_append "$@"

View File

@@ -1,50 +1,17 @@
#!/usr/bin/env bash
#
# Optimized script to batch prepend directories to PATH.
# For each given directory, it removes all duplicate occurrences from PATH
# and then prepends it. Directories that do not exist are skipped.
# Thin wrapper — delegates to x-path prepend.
# Can be sourced (PATH changes propagate) or executed.
#
# Usage: x-path-prepend <directory1> [<directory2> ...]
#
# Enable verbose output by setting the environment variable VERBOSE=1.
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
# License: MIT
VERBOSE="${VERBOSE:-0}"
# Ensure that at least one argument is provided.
[ "$#" -lt 1 ] && {
echo "Usage: $0 <directory> [<directory> ...]"
exit 1
}
# shellcheck source=./x-path
. "$(dirname "${BASH_SOURCE[0]:-$0}")/x-path"
# Save the arguments in an array.
dirs=("$@")
# Process the directories in reverse order so that the first argument ends up leftmost in PATH.
for ((idx = ${#dirs[@]} - 1; idx >= 0; idx--)); do
dir="${dirs[idx]}"
# Check if the specified directory exists.
if [ ! -d "$dir" ]; then
[ "$VERBOSE" -eq 1 ] && echo "(?) Directory '$dir' does not exist. Skipping."
continue
fi
# Remove all duplicate occurrences of the directory from PATH using built-in string operations.
case ":$PATH:" in
*":$dir:"*)
PATH=":${PATH}:"
PATH="${PATH//:$dir:/:}"
PATH="${PATH#:}"
PATH="${PATH%:}"
[ "$VERBOSE" -eq 1 ] && echo "Removed duplicate occurrences of '$dir' from PATH."
;;
*) ;;
esac
# Prepend the directory to PATH.
export PATH="$dir${PATH:+":$PATH"}"
[ "$VERBOSE" -eq 1 ] && echo "Prepended '$dir' to PATH."
done
normalize_path_var
do_prepend "$@"

View File

@@ -1,41 +1,17 @@
#!/usr/bin/env bash
#
# Optimized script to remove directories from PATH.
# For each specified directory, all occurrences are removed from PATH.
# Thin wrapper — delegates to x-path remove.
# Can be sourced (PATH changes propagate) or executed.
#
# Usage: x-path-remove <directory1> [<directory2> ...]
#
# Enable verbose output by setting the environment variable VERBOSE=1.
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
# License: MIT
VERBOSE="${VERBOSE:-0}"
# Ensure that at least one directory is provided.
[ "$#" -lt 1 ] && {
echo "Usage: $0 <directory> [<directory> ...]"
exit 1
}
# shellcheck source=./x-path
. "$(dirname "${BASH_SOURCE[0]:-$0}")/x-path"
for dir in "$@"; do
# Remove trailing slash if present, unless the directory is "/"
[ "$dir" != "/" ] && dir="${dir%/}"
# Check if the directory is present in PATH.
case ":$PATH:" in
*":$dir:"*)
# Remove all occurrences of the directory from PATH using parameter expansion.
PATH=":${PATH}:"
PATH="${PATH//:$dir:/:}"
PATH="${PATH#:}"
PATH="${PATH%:}"
[ "$VERBOSE" -eq 1 ] && echo "Removed '$dir' from PATH."
;;
*)
[ "$VERBOSE" -eq 1 ] && echo "(?) '$dir' is not in PATH."
;;
esac
done
export PATH
normalize_path_var
do_remove "$@"

View File

@@ -35,7 +35,7 @@ msg()
# Notify function
notify()
{
notify-call --replace-file "$replace_id" "$@"
notify-send.sh --replace-file "$replace_id" "$@"
}
# Stop recording function

View File

@@ -37,7 +37,7 @@ The script automatically tries authentication methods in this order:
1. **Specific key** (if provided in host file)
2. **Auto-detected default keys** (`~/.ssh/id_ed25519`, `id_rsa`, `id_ecdsa`,
`id_dsa`)
`id_dsa`)
3. **SSH agent or system default authentication**
This means you can mix hosts with and without specific keys, and the script will
@@ -178,7 +178,7 @@ SSH_RETRIES=3
3. **Staged Rollout**: Test on non-critical hosts first
4. **Review Logs**: Check log files for detailed information
5. **Preserve Access**: Script ensures key-based auth works before disabling
passwords
passwords
## Version

View File

@@ -1,11 +1,13 @@
#!/usr/bin/env bash
#
# This file echoes a bunch of 24-bit color codes
# to the terminal to demonstrate its functionality.
# The foreground escape sequence is ^[38;2;<r>;<g>;<b>m
# The background escape sequence is ^[48;2;<r>;<g>;<b>m
# <r> <g> <b> range from 0 to 255 inclusive.
# The escape sequence ^[0m returns output to default
# Display 24-bit terminal color test.
#
# Usage: x-term-colors
#
# The foreground escape sequence is ^[38;2;<r>;<g>;<b>m
# The background escape sequence is ^[48;2;<r>;<g>;<b>m
# <r> <g> <b> range from 0 to 255 inclusive.
# The escape sequence ^[0m returns output to default
setBackgroundColor()
{

View File

@@ -1,68 +0,0 @@
#!/usr/bin/env bash
#
# This script contains a helper for sha256 validating your downloads
#
# Source: https://gist.github.com/onnimonni/b49779ebc96216771a6be3de46449fa1
# Author: Onni Hakala
# License: MIT
#
# Updated by Ismo Vuorinen <https://github.com/ivuorinen> 2022
##
set -euo pipefail
# Stop program and give error message
# $1 - error message (string)
error()
{
echo "(!) ERROR: $1" >&2
exit 1
}
# Check for sha256sum command
if ! command -v sha256sum &> /dev/null; then
error "sha256sum could not be found, please install it first"
fi
# Return sha256sum for file
# $1 - filename (string)
get_sha256sum()
{
sha256sum "$1" | head -c 64
}
# Validate input arguments
validate_inputs()
{
if [ -z "${filename:-}" ]; then
error "You need to provide filename as the first parameter"
fi
if [ -z "${file_hash:-}" ]; then
error "You need to provide sha256sum as the second parameter"
fi
}
# Main validation logic
validate_file()
{
if [ ! -f "$filename" ]; then
error "File $filename doesn't exist"
elif [ "$(get_sha256sum "$filename")" = "$file_hash" ]; then
echo "(*) Success: $filename matches provided sha256sum"
else
error "$filename doesn't match provided sha256sum"
fi
}
# Main function
main()
{
filename=$1
file_hash=$2
validate_inputs
validate_file
}
main "$@"

View File

@@ -1,14 +0,0 @@
# x-validate-sha256sum.sh
This script contains a helper for sha256 validating your downloads
## Usage
```bash
x-validate-sha256sum.sh file sha256sum
```
The script computes the SHA256 hash of `file` and compares it to the
expected value. It exits non-zero if the sums differ.
<!-- vim: set ft=markdown spell spelllang=en_us cc=80 : -->

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
#
# Wait until a given host is down (determined by ping) then execute the
# given command

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
#
# Wait until a given host is online (determined by ping) then execute the
# given command

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Create file containing key mappings for Neovim
# Usage: ./create-nvim-keymaps.sh
#
@@ -15,7 +16,7 @@ main()
printf "\`\`\`txt"
} > "$DEST"
nvim -c "redir! >> $DEST" -c 'silent verbose map' -c 'redir END' -c 'q'
nvim -c "redir! >> \"$DEST\"" -c 'silent verbose map' -c 'redir END' -c 'q'
printf "\n\`\`\`\n\n- Generated on %s\n" "$(date)" >> "$DEST"

View File

@@ -11,10 +11,10 @@ scripts/install-cargo-packages.sh
## What it does
1. If `cargo-install-update` is available, updates all existing packages first
and tracks which packages are already installed.
and tracks which packages are already installed.
2. Installs each package from the inline list using `cargo install`,
skipping any already handled by the update step.
Builds run in parallel using available CPU cores (minus two).
skipping any already handled by the update step.
Builds run in parallel using available CPU cores (minus two).
3. Runs package-specific post-install steps.
4. Cleans the cargo cache with `cargo cache --autoclean`.

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Install cargo/rust packages.
#
# shellcheck source=shared.sh
source "$DOTFILES/config/shared.sh"
msgr run "Starting to install rust/cargo packages"

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Update pure-bash-bible cheatsheets
# shellcheck disable=SC2231,SC2034,SC2181,SC2068
# shellcheck source=shared.sh
@@ -85,7 +86,7 @@ process_chapters()
if [ '---' != "$(head -1 < "$cheat_file")" ]; then
local metadata
metadata="$PBB_SYNTAX\n$PBB_TAGS\n$PBB_SOURCE\n"
echo -e "---\n$metadata---\n$(cat "$cheat_file")" > "$cheat_file"
printf '%s\n%b%s\n%s' "---" "$metadata" "---" "$(cat "$cheat_file")" > "$cheat_file"
fi
done
}

View File

@@ -1,8 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Install PHP Package Manager Composer
#
# shellcheck source="shared.sh"
source "$HOME/.dotfiles/config/shared.sh"
source "$DOTFILES/config/shared.sh"
if ! command -v php &> /dev/null; then
msg_err "PHP Not Available, cannot install composer"
@@ -22,5 +23,7 @@ fi
php composer-setup.php --quiet
RESULT=$?
rm composer-setup.php
mv composer.phar ~/.local/bin/composer
if [ $RESULT -eq 0 ]; then
mv composer.phar ~/.local/bin/composer
fi
exit $RESULT

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Install NerdFonts
#
# shellcheck source="shared.sh"
@@ -21,7 +22,7 @@ clone_or_update_repo()
git clone --quiet --filter=blob:none --sparse --depth=1 "$GIT_REPO" "$TMP_PATH"
fi
cd "$TMP_PATH" || msgr err "No such folder $TMP_PATH"
cd "$TMP_PATH" || { msgr err "No such folder $TMP_PATH"; exit 1; }
}
# Function to add fonts to sparse-checkout

View File

@@ -1,12 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Install GitHub CLI extensions
#
# shellcheck source="shared.sh"
source "${DOTFILES}/config/shared.sh"
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
msgr run "Installing gh (GitHub Client) extensions"
if ! command -v gh &> /dev/null; then

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Install git-crypt
#
# NOTE: Experimental, wip
@@ -6,21 +7,17 @@
# shellcheck source=shared.sh
source "${DOTFILES}/config/shared.sh"
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
msgr run "Installing git-crypt"
if ! command -v git-crypt &> /dev/null; then
REPO_URL="https://github.com/AGWA/git-crypt.git"
CHECK_PATH="${XDG_BIN_HOME}/git-crypt"
BUILD_PATH="/tmp/git-crypt"
BUILD_PATH="$(mktemp -d)"
trap 'rm -rf "$BUILD_PATH"' EXIT
rm -rf "$BUILD_PATH"
if [ ! -d "$CHECK_PATH" ]; then
git clone --depth 1 "$REPO_URL" "$BUILD_PATH" || true
cd "$BUILD_PATH" || msg_err "$BUILD_PATH not found"
if [ ! -f "$CHECK_PATH" ]; then
git clone --depth 1 "$REPO_URL" "$BUILD_PATH" || { msgr err "Failed to clone $REPO_URL"; exit 1; }
cd "$BUILD_PATH" || { msgr err "$BUILD_PATH not found"; exit 1; }
make && make install PREFIX="$HOME/.local"
else
msgr run_done "git-crypt ($CHECK_PATH) already installed"

View File

@@ -1,12 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Install Go packages
#
# shellcheck source=shared.sh
source "$DOTFILES/config/shared.sh"
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
msgr run "Installing go packages"
! x-have "go" && msgr err "go hasn't been installed yet." && exit 0

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env bash
set -uo pipefail
# @description Sets macOS Defaults that I like
#
# This script contains large portions from following scripts:
@@ -7,7 +8,7 @@
[ "$(uname)" != "Darwin" ] && echo "Not a macOS system" && exit 0
# shellcheck source=shared.sh
source "$HOME/.dotfiles/config/shared.sh"
source "$DOTFILES/config/shared.sh"
msgr run "Starting to set macOS defaults, these require sudo privileges:"
@@ -23,12 +24,12 @@ while true; do
done 2> /dev/null &
# Skip when shell is fish
if [[ $SHELL != $(which fish) ]]; then
if [[ $SHELL != "$(command -v fish)" ]]; then
msgr nested "Change user shell to zsh if it is available and not the current"
# Change user shell to zsh if not that already.
if hash zsh 2> /dev/null; then
[[ $SHELL != $(which zsh) ]] && chsh -s "$(which zsh)"
[[ $SHELL != "$(command -v zsh)" ]] && chsh -s "$(command -v zsh)"
fi
fi

View File

@@ -1,12 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Install npm packages globally.
#
# shellcheck source=shared.sh
source "$DOTFILES/config/shared.sh"
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
msgr msg "Starting to install npm packages"
if ! command -v npm &> /dev/null; then

View File

@@ -1,12 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Install ntfy
#
# shellcheck source=shared.sh
source "$DOTFILES/config/shared.sh"
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
# Check if ntfy is already installed
if x-have "ntfy"; then
msgr "done" "ntfy already installed"
@@ -23,28 +21,31 @@ case $(dfm check arch) in
;;
*)
msgr err "Unsupported OS"
exit 1
;;
esac
NTFY_VERSION="$(x-gh-get-latest-version binwiederhier/ntfy)"
NTFY_URL="https://github.com/binwiederhier/ntfy"
NTFY_DEST="/tmp/ntfy_${NTFY_VERSION}_${NTFY_ARCH}"
NTFY_TARBALL="ntfy_${NTFY_VERSION}_${NTFY_ARCH}.tar.gz"
NTFY_DIR="ntfy_${NTFY_VERSION}_${NTFY_ARCH}"
# Download and extract ntfy
install_ntfy()
{
curl -L "$NTFY_URL/releases/download/v${NTFY_VERSION}/${NTFY_DEST}.tar.gz" -o "${NTFY_DEST}.tar.gz"
tar zxvf "${NTFY_DEST}.tar.gz"
cp -a "${NTFY_DEST}/ntfy" ~/.local/bin/ntfy
local tmpdir
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
curl -L "$NTFY_URL/releases/download/v${NTFY_VERSION}/${NTFY_TARBALL}" -o "$tmpdir/${NTFY_TARBALL}"
tar zxvf "$tmpdir/${NTFY_TARBALL}" -C "$tmpdir"
cp -a "$tmpdir/${NTFY_DIR}/ntfy" ~/.local/bin/ntfy
mkdir -p ~/.config/ntfy
# Copy config only if it does not exist
if [ ! -f "$HOME/.config/ntfy/client.yml" ]; then
cp "${NTFY_DEST}/client/client.yml" ~/.config/ntfy/client.yml
cp "$tmpdir/${NTFY_DIR}/client/client.yml" ~/.config/ntfy/client.yml
fi
# Clean up
rm -rf "${NTFY_DEST}" "${NTFY_DEST}.tar.gz"
}
main()

View File

@@ -1,12 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Install Python packages using uv.
#
# shellcheck source=shared.sh
source "$DOTFILES/config/shared.sh"
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
msgr run "Starting to install Python packages"
# Ensure uv is available
@@ -18,7 +16,8 @@ fi
# CLI tools — installed isolated with `uv tool install`
tools=(
ansible # IT automation and configuration management
ansible # IT automation and configuration management
openapi-python-client # Generate Python API clients from OpenAPI specs
)
# Library packages — installed into system Python with `uv pip install --system`

View File

@@ -1,11 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Install XCode CLI Tools with osascript magic.
# Ismo Vuorinen <https://github.com/ivuorinen> 2018
#
# Enable verbosity with VERBOSE=1
VERBOSE="${VERBOSE:-0}"
# Check if the script is running on macOS
if [ "$(uname)" != "Darwin" ]; then
msgr warn "Not a macOS system"
@@ -31,7 +29,7 @@ keep_alive_sudo()
done 2> /dev/null &
}
XCODE_TOOLS_PATH=$(xcode-select -p)
XCODE_TOOLS_PATH="$(xcode-select -p)"
XCODE_SWIFT_PATH="$XCODE_TOOLS_PATH/usr/bin/swift"
# Function to prompt for XCode CLI Tools installation

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail
# @description Install z
#
# shellcheck source=shared.sh

View File

@@ -4,17 +4,8 @@
# Helper env variables. Use like this: VERBOSE=1 ./script.sh
: "${VERBOSE:=0}"
# Set variable that checks if the shared.sh script has been
# sourced only once If the script has been sourced more than once,
# the script not be sourced again.
[ -z "$SHARED_SCRIPTS_SOURCED" ] && {
# Source the main shared config if not already loaded
if [ -z "${SHARED_SCRIPTS_SOURCED:-}" ]; then
source "${DOTFILES}/config/shared.sh"
# Warn the user if the shared configuration hasn't been loaded yet
msgr warn "(!) shared.sh not sourced"
# Set variable that checks if the shared.sh script has been
# sourced only once.
# shellcheck disable=SC2034
export SHARED_SCRIPTS_SOURCED=1
}
fi

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env bats
@test "x-mkd creates directory" {
dir="$BATS_TMPDIR/mkd-test"
run env VERBOSE=1 bash local/bin/x-mkd "$dir"
[ "$status" -eq 0 ]
[ -d "$dir" ]
}
@test "x-mkd with no args shows usage" {
run bash local/bin/x-mkd
[ "$status" -eq 1 ]
[[ "$output" == "Usage:"* ]]
}

Submodule tools/dotbot-pip deleted from 4d0cc116e8

View File

@@ -1 +0,0 @@
openapi-python-client