feat: Auto updator
This commit is contained in:
50
b.sh
50
b.sh
@@ -15,19 +15,45 @@ b() {
|
||||
local last_update=0
|
||||
[ -f "$last_update_file" ] && last_update=$(cat "$last_update_file" 2>/dev/null || echo 0)
|
||||
|
||||
# Update everything once every 24 hours, or if routes.sh is missing
|
||||
if [ $((current_time - last_update)) -gt 86400 ] || [ ! -f "$routes_file" ]; then
|
||||
local bootstrap_url="https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master/bootstrap.sh"
|
||||
local tmp_bootstrap
|
||||
tmp_bootstrap="$(mktemp)"
|
||||
|
||||
# Download and run the bootstrap installer to update all CLI files
|
||||
if curl -fsSL "$bootstrap_url" -o "$tmp_bootstrap" 2>/dev/null || wget -qO "$tmp_bootstrap" "$bootstrap_url" 2>/dev/null; then
|
||||
if bash "$tmp_bootstrap"; then
|
||||
echo "$current_time" > "$last_update_file"
|
||||
# Version comparison helper (returns 0 if $1 < $2, 1 otherwise)
|
||||
_version_lt() {
|
||||
[ "$1" = "$2" ] && return 1
|
||||
local IFS=.
|
||||
local i ver1=($1) ver2=($2)
|
||||
for ((i=${#ver1[@]}; i<3; i++)); do ver1[i]=0; done
|
||||
for ((i=${#ver2[@]}; i<3; i++)); do ver2[i]=0; done
|
||||
for ((i=0; i<3; i++)); do
|
||||
if ((10#${ver1[i]} < 10#${ver2[i]})); then
|
||||
return 0
|
||||
elif ((10#${ver1[i]} > 10#${ver2[i]})); then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Auto-update check: once every 24 hours, or if routes.sh or VERSION is missing
|
||||
if [ $((current_time - last_update)) -gt 86400 ] || [ ! -f "$routes_file" ] || [ ! -f "$routes_dir/VERSION" ]; then
|
||||
# Update the timestamp immediately to prevent spamming on connection errors
|
||||
echo "$current_time" > "$last_update_file"
|
||||
|
||||
local base_url="https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master"
|
||||
local local_ver="0.0.0"
|
||||
[ -f "$routes_dir/VERSION" ] && local_ver=$(cat "$routes_dir/VERSION" 2>/dev/null | tr -d '[:space:]')
|
||||
|
||||
local remote_ver
|
||||
if remote_ver=$(curl -fsSL "$base_url/VERSION" 2>/dev/null || wget -qO- "$base_url/VERSION" 2>/dev/null); then
|
||||
remote_ver=$(echo "$remote_ver" | tr -d '[:space:]')
|
||||
if [ -n "$remote_ver" ] && _version_lt "$local_ver" "$remote_ver"; then
|
||||
echo "New version $remote_ver available (local: $local_ver). Auto-updating..." >&2
|
||||
local tmp_bootstrap
|
||||
tmp_bootstrap="$(mktemp)"
|
||||
if curl -fsSL "$base_url/bootstrap.sh" -o "$tmp_bootstrap" 2>/dev/null || wget -qO "$tmp_bootstrap" "$base_url/bootstrap.sh" 2>/dev/null; then
|
||||
bash "$tmp_bootstrap" >/dev/null 2>&1
|
||||
fi
|
||||
rm -f "$tmp_bootstrap"
|
||||
fi
|
||||
fi
|
||||
rm -f "$tmp_bootstrap"
|
||||
fi
|
||||
|
||||
if [ ! -f "$routes_file" ]; then
|
||||
@@ -48,7 +74,7 @@ _b_completion() {
|
||||
|
||||
# If completing the first argument after 'b'
|
||||
if [ "$COMP_CWORD" -eq 1 ]; then
|
||||
opts="all con bye"
|
||||
opts="all con bye up"
|
||||
|
||||
local routes_file="$HOME/.config/bootstrap/routes.sh"
|
||||
if [ -f "$routes_file" ]; then
|
||||
|
||||
13
bootstrap.sh
13
bootstrap.sh
@@ -88,6 +88,7 @@ install_bootstrap() {
|
||||
|
||||
# List of all files to download/copy
|
||||
local files=(
|
||||
"VERSION"
|
||||
"b.sh"
|
||||
"routes.sh"
|
||||
"lib/common.sh"
|
||||
@@ -96,6 +97,7 @@ install_bootstrap() {
|
||||
"commands/help.sh"
|
||||
"commands/con.sh"
|
||||
"commands/uninstall.sh"
|
||||
"commands/up.sh"
|
||||
)
|
||||
|
||||
if [ -f "$_SCRIPT_DIR/b.sh" ] && [ -f "$_SCRIPT_DIR/routes.sh" ]; then
|
||||
@@ -180,6 +182,17 @@ EOF
|
||||
# Initialize the last update timestamp to prevent immediate update on first execution (Fix 2)
|
||||
local last_update_file="$routes_dir/.last_b_update"
|
||||
date +%s 2>/dev/null > "$last_update_file" || date +%s > "$last_update_file"
|
||||
|
||||
# Set up pre-commit hook if in a git repository locally
|
||||
if [ -d "$_SCRIPT_DIR/.git" ]; then
|
||||
log_info "Setting up git pre-commit hook..."
|
||||
mkdir -p "$_SCRIPT_DIR/.git/hooks"
|
||||
if [ -f "$_SCRIPT_DIR/scripts/pre-commit" ]; then
|
||||
cp "$_SCRIPT_DIR/scripts/pre-commit" "$_SCRIPT_DIR/.git/hooks/pre-commit"
|
||||
chmod +x "$_SCRIPT_DIR/.git/hooks/pre-commit"
|
||||
log_success "Pre-commit hook installed to .git/hooks/pre-commit"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Only execute installation if not sourced (Fix 3)
|
||||
|
||||
@@ -5,6 +5,7 @@ echo "Available bootstrap commands:"
|
||||
# Non-installers first (aligned to 6 chars width)
|
||||
printf " %-6s - %s\n" "all" "List all available commands"
|
||||
printf " %-6s - %s\n" "con" "Edit config (e.g. b con nvim)"
|
||||
printf " %-6s - %s\n" "up" "Check for updates and update Bootstrap CLI"
|
||||
printf " %-6s - %s\n" "bye" "Uninstall Bootstrap CLI helper"
|
||||
|
||||
# Installers second
|
||||
|
||||
82
commands/up.sh
Normal file
82
commands/up.sh
Normal file
@@ -0,0 +1,82 @@
|
||||
# Command: up
|
||||
# Manually checks for updates and runs the updater if a newer version is found.
|
||||
|
||||
# Source libraries if needed
|
||||
if [ -z "${_LIB_COMMON_SOURCED:-}" ]; then
|
||||
_LIB_DIR="${BOOTSTRAP_DIR:-$HOME/.config/bootstrap}/lib"
|
||||
. "$_LIB_DIR/common.sh"
|
||||
fi
|
||||
|
||||
require_bash
|
||||
|
||||
log_info "Checking for updates..."
|
||||
|
||||
local_ver="0.0.0"
|
||||
version_file="${BOOTSTRAP_DIR:-$HOME/.config/bootstrap}/VERSION"
|
||||
if [ -f "$version_file" ]; then
|
||||
local_ver=$(cat "$version_file" | tr -d '[:space:]')
|
||||
fi
|
||||
|
||||
base_url="https://git.adityagupta.dev/sortedcord/bootstrap/raw/branch/master"
|
||||
remote_ver=$(curl -fsSL "$base_url/VERSION" 2>/dev/null || wget -qO- "$base_url/VERSION" 2>/dev/null)
|
||||
remote_ver=$(echo "$remote_ver" | tr -d '[:space:]')
|
||||
|
||||
if [ -z "$remote_ver" ]; then
|
||||
log_error "Failed to fetch remote version. Please check your internet connection."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Version comparison helper
|
||||
version_lt() {
|
||||
[ "$1" = "$2" ] && return 1
|
||||
local IFS=.
|
||||
local i ver1=($1) ver2=($2)
|
||||
for ((i=${#ver1[@]}; i<3; i++)); do ver1[i]=0; done
|
||||
for ((i=${#ver2[@]}; i<3; i++)); do ver2[i]=0; done
|
||||
for ((i=0; i<3; i++)); do
|
||||
if ((10#${ver1[i]} < 10#${ver2[i]})); then
|
||||
return 0
|
||||
elif ((10#${ver1[i]} > 10#${ver2[i]})); then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
log_info "Local version: $local_ver"
|
||||
log_info "Remote version: $remote_ver"
|
||||
|
||||
force_update=false
|
||||
if [ "${1:-}" = "--force" ] || [ "${1:-}" = "-f" ]; then
|
||||
force_update=true
|
||||
fi
|
||||
|
||||
if version_lt "$local_ver" "$remote_ver" || [ "$force_update" = true ]; then
|
||||
if [ "$force_update" = true ]; then
|
||||
log_info "Force updating..."
|
||||
else
|
||||
log_info "New version available! Updating..."
|
||||
fi
|
||||
|
||||
tmp_bootstrap="$(mktemp)"
|
||||
if curl -fsSL "$base_url/bootstrap.sh" -o "$tmp_bootstrap" || wget -qO "$tmp_bootstrap" "$base_url/bootstrap.sh"; then
|
||||
# Run bootstrap.sh in foreground
|
||||
if bash "$tmp_bootstrap"; then
|
||||
# Update the last update timestamp
|
||||
date +%s > "${BOOTSTRAP_DIR:-$HOME/.config/bootstrap}/.last_b_update" 2>/dev/null || true
|
||||
log_success "Bootstrap CLI successfully updated to version $remote_ver!"
|
||||
else
|
||||
log_error "Failed to execute bootstrap installer."
|
||||
rm -f "$tmp_bootstrap"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log_error "Failed to download update installer."
|
||||
rm -f "$tmp_bootstrap"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$tmp_bootstrap"
|
||||
else
|
||||
log_success "You are already on the latest version ($local_ver)."
|
||||
log_info "To force reinstall, run: b up --force"
|
||||
fi
|
||||
14
readme.md
14
readme.md
@@ -44,6 +44,13 @@ b con i3
|
||||
|
||||
It automatically fuzzy-finds the folder in case there is no exact match.
|
||||
|
||||
To check for updates and update the tool manually:
|
||||
|
||||
```bash
|
||||
b up
|
||||
# Or to force a reinstall of the CLI files:
|
||||
b up --force
|
||||
```
|
||||
|
||||
## Uninstallation
|
||||
|
||||
@@ -55,6 +62,13 @@ b bye
|
||||
|
||||
Then reload your shell configuration or run `unset -f b` to clear the function definition from your current terminal session.
|
||||
|
||||
## Development
|
||||
|
||||
If you are developing this tool locally:
|
||||
|
||||
1. Clone the repository.
|
||||
2. Run `./bootstrap.sh` to install the CLI from your local copy. This will also automatically install a Git pre-commit hook (`scripts/pre-commit`) that auto-increments the patch version in the `VERSION` file on each commit.
|
||||
|
||||
## Philosophy
|
||||
|
||||
These scripts are designed for my own systems first.
|
||||
|
||||
@@ -83,6 +83,14 @@ for script in "${SCRIPTS[@]}"; do
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
up)
|
||||
if [ -f "$BOOTSTRAP_DIR/commands/up.sh" ]; then
|
||||
. "$BOOTSTRAP_DIR/commands/up.sh" "$@"
|
||||
else
|
||||
log_error "Update command script not found."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
bye)
|
||||
if [ -f "$BOOTSTRAP_DIR/commands/uninstall.sh" ]; then
|
||||
. "$BOOTSTRAP_DIR/commands/uninstall.sh"
|
||||
|
||||
43
scripts/pre-commit
Normal file
43
scripts/pre-commit
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# Git pre-commit hook to automatically bump the patch version in VERSION file.
|
||||
# It only increments the version if files other than VERSION are staged for commit.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
VERSION_FILE="VERSION"
|
||||
|
||||
if [ ! -f "$VERSION_FILE" ]; then
|
||||
echo "1.0.0" > "$VERSION_FILE"
|
||||
git add "$VERSION_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if there are staged changes other than the VERSION file
|
||||
if ! git diff --cached --name-only | grep -qv "^$VERSION_FILE$"; then
|
||||
# No other files staged, skip version bump
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Read current version
|
||||
current_version=$(cat "$VERSION_FILE" | tr -d '[:space:]')
|
||||
|
||||
# Basic regex validation for semantic versioning (X.Y.Z)
|
||||
if [[ ! "$current_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Error: Current version '$current_version' in $VERSION_FILE is not in X.Y.Z format." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse version components
|
||||
IFS='.' read -r major minor patch <<< "$current_version"
|
||||
|
||||
# Increment patch version
|
||||
patch=$((patch + 1))
|
||||
new_version="$major.$minor.$patch"
|
||||
|
||||
# Write to VERSION file
|
||||
echo "$new_version" > "$VERSION_FILE"
|
||||
|
||||
# Add VERSION file to the commit
|
||||
git add "$VERSION_FILE"
|
||||
|
||||
echo "[pre-commit] Automatically bumped version from $current_version to $new_version"
|
||||
Reference in New Issue
Block a user