Compare commits

...

10 Commits

Author SHA1 Message Date
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
41 changed files with 313 additions and 536 deletions

View File

@@ -35,4 +35,4 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
- name: Run PR Lint - 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 issues: write
steps: 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 url = https://github.com/anishathalye/dotbot.git
ignore = dirty ignore = dirty
[submodule "dotbot-brew"]
path = tools/dotbot-brew
url = https://github.com/wren/dotbot-brew.git
ignore = dirty
[submodule "dotbot-include"] [submodule "dotbot-include"]
path = tools/dotbot-include path = tools/dotbot-include
url = https://gitlab.com/gnfzdz/dotbot-include.git url = https://gitlab.com/gnfzdz/dotbot-include.git
@@ -29,11 +24,6 @@
url = https://github.com/tmux-plugins/tmux-sessionist.git url = https://github.com/tmux-plugins/tmux-sessionist.git
ignore = dirty ignore = dirty
[submodule "dotbot-pip"]
path = tools/dotbot-pip
url = https://github.com/sobolevn/dotbot-pip.git
ignore = dirty
[submodule "tmux/tmux-suspend"] [submodule "tmux/tmux-suspend"]
path = config/tmux/plugins/tmux-suspend path = config/tmux/plugins/tmux-suspend
url = https://github.com/MunifTanjim/tmux-suspend.git url = https://github.com/MunifTanjim/tmux-suspend.git
@@ -63,6 +53,8 @@
[submodule "tmux/tmux-resurrect"] [submodule "tmux/tmux-resurrect"]
path = config/tmux/plugins/tmux-resurrect path = config/tmux/plugins/tmux-resurrect
url = https://github.com/tmux-plugins/tmux-resurrect.git url = https://github.com/tmux-plugins/tmux-resurrect.git
ignore = dirty
[submodule "tmux/catppuccin"] [submodule "tmux/catppuccin"]
path = config/tmux/plugins/catppuccin path = config/tmux/plugins/catppuccin
url = https://github.com/catppuccin/tmux.git url = https://github.com/catppuccin/tmux.git
ignore = dirty

View File

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

View File

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

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": { "vcs": {
"enabled": true, "enabled": true,
"clientKind": "git", "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" brew "php@8.3"
# Pins GitHub Actions to full hashes and versions # Pins GitHub Actions to full hashes and versions
brew "pinact" brew "pinact"
# Execute binaries from Python packages in isolated environments
brew "pipx"
# Python version management # Python version management
brew "pyenv" brew "pyenv"
# Migrate pip packages from one Python version to another # Migrate pip packages from one Python version to another

View File

@@ -40,7 +40,8 @@ return {
operators = {}, operators = {},
-- miscs = {}, -- Uncomment to turn off hard-coded styles -- 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 = { virtual_text = {
errors = { 'italic' }, errors = { 'italic' },
hints = { 'italic' }, hints = { 'italic' },
@@ -72,7 +73,8 @@ return {
enabled = true, enabled = true,
indentscope_color = '', 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', 'dmtrKovalenko/fff.nvim',
build = function() 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) -- (if you are using lazy you can use gb for rebuilding a plugin if needed)
require('fff.download').download_or_build_binary() require('fff.download').download_or_build_binary()
end, end,
@@ -124,7 +127,8 @@ return {
opts = { -- (optional) opts = { -- (optional)
debug = { debug = {
enabled = true, -- we expect your collaboration at least during the beta 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. -- No need to lazy-load with lazy.nvim.

View File

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

View File

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

View File

@@ -15,37 +15,36 @@
SCRIPT=$(basename "$0") SCRIPT=$(basename "$0")
# Detect the current shell # Require bash 4.0+ for associative arrays and mapfile
CURRENT_SHELL=$(ps -p $$ -ocomm= | awk -F/ '{print $NF}') if ((BASH_VERSINFO[0] < 4)); then
echo "dfm requires bash 4.0+, found ${BASH_VERSION}"
# Function to source files based on the shell if [[ "$(uname)" == "Darwin" ]]; then
source_file() if ! command -v brew &> /dev/null; then
{ echo "Installing Homebrew..."
local file=$1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
case "$CURRENT_SHELL" in fi
fish) echo "Installing modern bash via Homebrew..."
if [[ -f "$file.fish" ]]; then brew install bash
# shellcheck disable=SC1090 echo "Done. Restart your shell and run dfm again."
source "$file.fish" else
else echo "Install bash 4.0+ and try again."
echo "Fish shell file not found: $file.fish"
exit 1
fi fi
;;
sh | bash | zsh)
# shellcheck disable=SC1090
source "$file"
;;
*)
echo "Unsupported shell: $CURRENT_SHELL"
exit 1 exit 1
;; fi
esac
}
# Modify the source commands to use the new function # shellcheck disable=SC1091
source_file "$DOTFILES/config/shared.sh" source "$DOTFILES/config/shared.sh"
source_file "${DOTFILES}/local/bin/msgr" # shellcheck disable=SC1090
source "${DOTFILES}/local/bin/msgr"
# Get description from a script file's @description tag
get_script_description()
{
local file="$1"
local desc
desc=$(sed -n '/@description/s/.*@description *\(.*\)/\1/p' "$file" | head -1)
echo "${desc:-No description available}"
}
# Menu builder # Menu builder
menu_builder() menu_builder()
@@ -54,9 +53,9 @@ menu_builder()
local commands=("${@:2}") local commands=("${@:2}")
local width=60 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 "%-${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 for cmd in "${commands[@]}"; do
local name=${cmd%%:*} local name=${cmd%%:*}
@@ -80,7 +79,6 @@ section_install()
"imagick:Install ImageMagick CLI" "imagick:Install ImageMagick CLI"
"macos:Setup nice macOS defaults" "macos:Setup nice macOS defaults"
"npm-packages:Install NPM Packages" "npm-packages:Install NPM Packages"
"ntfy:Install ntfy"
"nvm-latest:Install latest lts node using nvm" "nvm-latest:Install latest lts node using nvm"
"nvm:Install Node Version Manager (nvm)" "nvm:Install Node Version Manager (nvm)"
"z:Install z" "z:Install z"
@@ -100,6 +98,7 @@ section_install()
$0 install npm-packages $0 install npm-packages
$0 install z $0 install z
msgr msg "Reloading configurations again..." msgr msg "Reloading configurations again..."
# shellcheck disable=SC1091
source "$DOTFILES/config/shared.sh" source "$DOTFILES/config/shared.sh"
msgr yay "All done!" msgr yay "All done!"
;; ;;
@@ -208,7 +207,11 @@ section_brew()
"untracked:List untracked brew packages" "untracked:List untracked brew packages"
) )
x-have brew && { if ! x-have brew; then
msgr warn "brew not available, skipping"
return 0
fi
case "$1" in case "$1" in
install) install)
brew bundle install --file="$BREWFILE" --force --quiet && msgr yay "Done!" brew bundle install --file="$BREWFILE" --force --quiet && msgr yay "Done!"
@@ -265,10 +268,10 @@ section_brew()
array_diff BREW_LIST_UNTRACKED BREW_LIST_TRACKED_WITHOUT_DEPS BREW_LIST_BUNDLED array_diff BREW_LIST_UNTRACKED BREW_LIST_TRACKED_WITHOUT_DEPS BREW_LIST_BUNDLED
# If there are no untracked packages, exit # If there are no untracked packages, return
if [ ${#BREW_LIST_UNTRACKED[@]} -eq 0 ]; then if [ ${#BREW_LIST_UNTRACKED[@]} -eq 0 ]; then
msgr yay "No untracked packages found!" msgr yay "No untracked packages found!"
exit 0 return 0
fi fi
echo "Untracked:" echo "Untracked:"
@@ -286,9 +289,6 @@ section_brew()
*) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;; *) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;;
esac esac
}
! x-have brew && menu_builder "$USAGE_PREFIX" "brew not available on this system"
} }
section_helpers() section_helpers()
@@ -305,10 +305,10 @@ section_helpers()
"wezterm:Show wezterm keybindings" "wezterm:Show wezterm keybindings"
) )
CMD="$1" CMD="${1:-}"
shift [[ $# -gt 0 ]] && shift
SECTION="$1" SECTION="${1:-}"
shift [[ $# -gt 0 ]] && shift
case "$CMD" in case "$CMD" in
path) path)
@@ -379,7 +379,11 @@ section_apt()
"clean:Clean apt cache" "clean:Clean apt cache"
) )
x-have apt && { if ! x-have apt; then
msgr warn "apt not available, skipping"
return 0
fi
case "$1" in case "$1" in
upkeep) upkeep)
sudo apt update \ sudo apt update \
@@ -389,8 +393,11 @@ section_apt()
;; ;;
install) install)
# if apt.txt is not found, exit # if apt.txt is not found, return with error
[ ! -f "$DOTFILES/tools/apt.txt" ] && msgr err "apt.txt not found" && exit 0 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. # Load apt.txt, remove comments (even if trailing comment) and empty lines.
# #
@@ -426,8 +433,6 @@ section_apt()
clean) sudo apt clean ;; clean) sudo apt clean ;;
*) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;; *) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;;
esac esac
}
! x-have apt && menu_builder "$USAGE_PREFIX" "apt not available on this system"
} }
section_docs() section_docs()
@@ -534,13 +539,13 @@ section_check()
case "$1" in case "$1" in
a | arch) a | arch)
[[ $2 == "" ]] && echo "$X_ARCH" && exit 0 [[ $2 == "" ]] && echo "$X_ARCH" && return 0
[[ $X_ARCH == "$2" ]] && exit 0 || exit 1 [[ $X_ARCH == "$2" ]] && return 0 || return 1
;; ;;
h | host | hostname) h | host | hostname)
[[ $2 == "" ]] && echo "$X_HOSTNAME" && exit 0 [[ $2 == "" ]] && echo "$X_HOSTNAME" && return 0
[[ $X_HOSTNAME == "$2" ]] && exit 0 || exit 1 [[ $X_HOSTNAME == "$2" ]] && return 0 || return 1
;; ;;
*) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;; *) menu_builder "$USAGE_PREFIX" "${MENU[@]}" ;;
@@ -551,33 +556,18 @@ section_scripts()
{ {
USAGE_PREFIX="$SCRIPT scripts <command>" 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 # Collect scripts and their descriptions
declare -A SCRIPT_MENU local menu_items=()
for script in "$DOTFILES/scripts/install-"*.sh; do for script in "$DOTFILES/scripts/install-"*.sh; do
if [ -f "$script" ]; then if [ -f "$script" ]; then
name=$(basename "$script" .sh | sed 's/install-//') name=$(basename "$script" .sh | sed 's/install-//')
desc=$(get_script_description "$script") desc=$(get_script_description "$script")
SCRIPT_MENU[$name]="$desc" menu_items+=("$name:$desc")
fi fi
done done
case "$1" in 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[@]}" menu_builder "$USAGE_PREFIX" "${menu_items[@]}"
;; ;;
*) *)
@@ -609,7 +599,7 @@ section_tests()
echo " $i" echo " $i"
done done
;; ;;
msg) msgr)
# shellcheck disable=SC1010 # shellcheck disable=SC1010
msgr done "msgr done" msgr done "msgr done"
msgr done_suffix "msgr done_suffix" msgr done_suffix "msgr done_suffix"
@@ -633,7 +623,7 @@ usage()
{ {
echo "" echo ""
msgr prompt "Usage: $SCRIPT <section> <command>" msgr prompt "Usage: $SCRIPT <section> <command>"
echo $" Empty <command> prints <section> help." echo " Empty <command> prints <section> help."
echo "" echo ""
section_install section_install
echo "" echo ""
@@ -654,8 +644,8 @@ usage()
main() main()
{ {
SECTION="$1" SECTION="${1:-}"
shift [[ $# -gt 0 ]] && shift
# The main loop. The first keyword after $0 triggers section, or help. # The main loop. The first keyword after $0 triggers section, or help.
case "$SECTION" in case "$SECTION" in
install) section_install "$@" ;; install) section_install "$@" ;;
@@ -667,7 +657,7 @@ main()
docs) section_docs "$@" ;; docs) section_docs "$@" ;;
scripts) section_scripts "$@" ;; scripts) section_scripts "$@" ;;
tests) section_tests "$@" ;; tests) section_tests "$@" ;;
*) usage && exit 0 ;; *) usage && return 0 ;;
esac esac
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,14 @@
#!/usr/bin/env bash #!/usr/bin/env bash
#
# Display external IP address.
#
# Source: https://github.com/thirtythreeforty/dotfiles/blob/master/bin/extip # 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 # 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 # Defaults
LOOP=0 LOOP=0
SLEEP=1 SLEEP=1
VERBOSE=0
TIMEOUT=5 TIMEOUT=5
usage() usage()
@@ -60,8 +59,6 @@ while [[ $# -gt 0 ]]; do
exit 0 exit 0
;; ;;
--verbose) --verbose)
# shellcheck disable=SC2034
VERBOSE=1
shift shift
;; ;;
--loop | --forever) --loop | --forever)

View File

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

View File

@@ -1,44 +1,17 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Optimized script to append directories to PATH. # Thin wrapper — delegates to x-path append.
# For each given directory, it removes all duplicate occurrences from PATH # Can be sourced (PATH changes propagate) or executed.
# and then appends it if the directory exists.
# #
# Usage: x-path-append <directory1> [<directory2> ...] # Usage: x-path-append <directory1> [<directory2> ...]
# #
# Enable verbose output by setting the environment variable VERBOSE=1.
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024 # Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
# License: MIT # License: MIT
VERBOSE="${VERBOSE:-0}" VERBOSE="${VERBOSE:-0}"
# Ensure that at least one directory is provided. # shellcheck source=./x-path
[ "$#" -lt 1 ] && { . "$(dirname "${BASH_SOURCE[0]:-$0}")/x-path"
echo "Usage: $0 <directory> [<directory> ...]"
exit 1
}
for dir in "$@"; do normalize_path_var
# Check if the specified directory exists. do_append "$@"
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

View File

@@ -1,50 +1,17 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# Optimized script to batch prepend directories to PATH. # Thin wrapper — delegates to x-path prepend.
# For each given directory, it removes all duplicate occurrences from PATH # Can be sourced (PATH changes propagate) or executed.
# and then prepends it. Directories that do not exist are skipped.
# #
# Usage: x-path-prepend <directory1> [<directory2> ...] # Usage: x-path-prepend <directory1> [<directory2> ...]
# #
# Enable verbose output by setting the environment variable VERBOSE=1.
#
# Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024 # Author: Ismo Vuorinen <https://github.com/ivuorinen> 2024
# License: MIT # License: MIT
VERBOSE="${VERBOSE:-0}" VERBOSE="${VERBOSE:-0}"
# Ensure that at least one argument is provided. # shellcheck source=./x-path
[ "$#" -lt 1 ] && { . "$(dirname "${BASH_SOURCE[0]:-$0}")/x-path"
echo "Usage: $0 <directory> [<directory> ...]"
exit 1
}
# Save the arguments in an array. normalize_path_var
dirs=("$@") do_prepend "$@"
# 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

View File

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

View File

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

View File

@@ -1,7 +1,9 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# #
# This file echoes a bunch of 24-bit color codes # Display 24-bit terminal color test.
# to the terminal to demonstrate its functionality. #
# Usage: x-term-colors
#
# The foreground escape sequence is ^[38;2;<r>;<g>;<b>m # The foreground escape sequence is ^[38;2;<r>;<g>;<b>m
# The background escape sequence is ^[48;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. # <r> <g> <b> range from 0 to 255 inclusive.

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 #!/usr/bin/env bash
set -euo pipefail
# #
# Wait until a given host is down (determined by ping) then execute the # Wait until a given host is down (determined by ping) then execute the
# given command # given command

View File

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

View File

@@ -19,6 +19,7 @@ fi
# CLI tools — installed isolated with `uv tool install` # CLI tools — installed isolated with `uv tool install`
tools=( 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` # Library packages — installed into system Python with `uv pip install --system`

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