chore: initial commit
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env bash
|
||||
# run_once_linux_configure-shell.sh
|
||||
# Configures zsh as the default shell and sets up the shell environment.
|
||||
# This script runs once (unless deleted from ~/.local/share/chezmoi).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "==> Configuring shell environment (Linux)..."
|
||||
|
||||
# --- Set zsh as default shell ---
|
||||
ZSH_PATH=$(which zsh 2>/dev/null || echo "")
|
||||
if [ -z "$ZSH_PATH" ]; then
|
||||
echo " ERROR: zsh is not installed. Run the package install script first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CURRENT_SHELL=$(getent passwd "$USER" | cut -d: -f7)
|
||||
if [ "$CURRENT_SHELL" != "$ZSH_PATH" ]; then
|
||||
echo " Setting zsh as default shell..."
|
||||
chsh -s "$ZSH_PATH"
|
||||
echo " Default shell set to: $ZSH_PATH"
|
||||
else
|
||||
echo " zsh is already the default shell"
|
||||
fi
|
||||
|
||||
# --- Set up Rust (cargo) in environment ---
|
||||
CARGO_ENV="$HOME/.cargo/env"
|
||||
if [ -f "$CARGO_ENV" ]; then
|
||||
RUST_ZSHENV_LINE='. "$HOME/.cargo/env"'
|
||||
ZSHENV="$HOME/.zshenv"
|
||||
if ! grep -qF "$RUST_ZSHENV_LINE" "$ZSHENV" 2>/dev/null; then
|
||||
echo "$RUST_ZSHENV_LINE" >> "$ZSHENV"
|
||||
echo " Added Rust cargo env to .zshenv"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Set up Go in environment ---
|
||||
if [ -d "/usr/local/go" ]; then
|
||||
GO_ZSHENV_LINE='export PATH=$PATH:/usr/local/go/bin'
|
||||
ZSHENV="$HOME/.zshenv"
|
||||
if ! grep -qF "go/bin" "$ZSHENV" 2>/dev/null; then
|
||||
echo "$GO_ZSHENV_LINE" >> "$ZSHENV"
|
||||
echo " Added Go to PATH in .zshenv"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "==> Shell configuration complete!"
|
||||
echo " NOTE: Log out and back in (or restart your terminal) for shell changes to take effect."
|
||||
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env bash
|
||||
# run_once_setup-ssh-keys.sh.tmpl
|
||||
# Pulls SSH PRIVATE keys from Bitwarden and writes them to ~/.ssh/.
|
||||
#
|
||||
# Public keys (.pub files) are committed directly to the repo in dot_ssh/
|
||||
# and are applied automatically by chezmoi — no Bitwarden needed for those.
|
||||
#
|
||||
# Requires: bw (Bitwarden CLI) to be logged in and unlocked.
|
||||
# To unlock Bitwarden before running chezmoi:
|
||||
# export BW_SESSION=$(bw unlock --raw)
|
||||
# chezmoi apply
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "==> Setting up SSH keys from Bitwarden..."
|
||||
|
||||
SSH_DIR="$HOME/.ssh"
|
||||
mkdir -p "$SSH_DIR"
|
||||
chmod 700 "$SSH_DIR"
|
||||
|
||||
write_key() {
|
||||
local name="$1"
|
||||
local bw_item_name="$2"
|
||||
local key_path="$SSH_DIR/$name"
|
||||
|
||||
if [ -f "$key_path" ]; then
|
||||
echo " Key already exists: $name (skipping)"
|
||||
return
|
||||
fi
|
||||
|
||||
echo " Fetching key: $bw_item_name -> $name"
|
||||
# bw get notes "Item Name" returns the secure note content
|
||||
bw get notes "$bw_item_name" 2>/dev/null > "$key_path" || {
|
||||
echo " WARNING: Could not fetch '$bw_item_name' from Bitwarden. Skipping."
|
||||
rm -f "$key_path"
|
||||
return
|
||||
}
|
||||
|
||||
if [ ! -s "$key_path" ]; then
|
||||
echo " WARNING: Key content was empty for '$bw_item_name'. Removing."
|
||||
rm -f "$key_path"
|
||||
return
|
||||
fi
|
||||
|
||||
chmod 600 "$key_path"
|
||||
echo " Wrote: $key_path"
|
||||
}
|
||||
|
||||
# --- Add your SSH keys below ---
|
||||
# Format: write_key "filename_in_~/.ssh" "Bitwarden secure note name"
|
||||
#
|
||||
# Example:
|
||||
# write_key "stevan@freeborn.cloud" "SSH Key - stevan@freeborn.cloud"
|
||||
# write_key "ftp_stevanfreeborn_com" "SSH Key - ftp_stevanfreeborn_com"
|
||||
# write_key "tangled" "SSH Key - tangled"
|
||||
# write_key "tinker" "SSH Key - tinker"
|
||||
# write_key "gitea.freeborn.cloud" "SSH Key - gitea.freeborn.cloud"
|
||||
|
||||
write_key "bit_bastion.key" "SSH Key - bit_bastion.key"
|
||||
write_key "stevan@freeborn.cloud" "SSH Key - stevan@freeborn.cloud"
|
||||
write_key "ftp_stevanfreeborn_com" "SSH Key - ftp_stevanfreeborn_com"
|
||||
write_key "tangled" "SSH Key - tangled"
|
||||
write_key "zenbook_tinker" "SSH Key - zenbook_tinker"
|
||||
write_key "gitea.freeborn.cloud" "SSH Key - gitea.freeborn.cloud"
|
||||
write_key "id_ed25519" "SSH Key - id_ed25519"
|
||||
write_key "macbookair" "SSH Key - macbookair"
|
||||
write_key "macbookpro" "SSH Key - macbookpro"
|
||||
write_key "truenas" "SSH Key - truenas"
|
||||
write_key "blog.stevanfreeborn.com_github_actions" "SSH Key - blog.stevanfreeborn.com_github_actions"
|
||||
write_key "commands_github_actions" "SSH Key - commands_github_actions"
|
||||
write_key "onspring_qa_playwright_reports_render" "SSH Key - onspring_qa_playwright_reports_render"
|
||||
write_key "onx_graph_github_actions" "SSH Key - onx_graph_github_actions"
|
||||
write_key "restapiplayground.stevanfreeborn.com_github_actions" "SSH Key - restapiplayground.stevanfreeborn.com_github_actions"
|
||||
write_key "steves_bot_github_actions" "SSH Key - steves_bot_github_actions"
|
||||
|
||||
echo "==> SSH key setup complete!"
|
||||
echo " NOTE: Store your SSH private keys as Bitwarden Secure Notes with the names listed above."
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# run_once_windows_configure-shell.ps1
|
||||
# Installs PowerShell modules and configures the shell environment.
|
||||
# This script runs once (unless deleted from ~/.local/share/chezmoi).
|
||||
|
||||
$ErrorActionPreference = "Continue"
|
||||
|
||||
Write-Host "==> Configuring PowerShell shell environment..." -ForegroundColor Cyan
|
||||
|
||||
# --- Install PowerShell modules ---
|
||||
$modules = @("PSReadLine", "Terminal-Icons", "posh-git")
|
||||
|
||||
foreach ($module in $modules) {
|
||||
if (-not (Get-Module -ListAvailable -Name $module)) {
|
||||
Write-Host " Installing module: $module..." -ForegroundColor Yellow
|
||||
Install-Module -Name $module -Force -Scope CurrentUser -SkipPublisherCheck -ErrorAction SilentlyContinue
|
||||
Write-Host " Installed: $module" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " Module already installed: $module" -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
|
||||
# --- Set PowerShell execution policy ---
|
||||
$policy = Get-ExecutionPolicy -Scope CurrentUser
|
||||
if ($policy -ne "RemoteSigned" -and $policy -ne "Unrestricted") {
|
||||
Write-Host " Setting execution policy to RemoteSigned for CurrentUser..." -ForegroundColor Yellow
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
|
||||
}
|
||||
|
||||
# --- Ensure profile directory exists ---
|
||||
$profileDir = Split-Path $PROFILE -Parent
|
||||
if (-not (Test-Path $profileDir)) {
|
||||
New-Item -ItemType Directory -Path $profileDir -Force | Out-Null
|
||||
Write-Host " Created profile directory: $profileDir" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host "==> Shell configuration complete!" -ForegroundColor Cyan
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# run_once_windows_setup-ssh-keys.ps1.tmpl
|
||||
# Pulls SSH private keys from Bitwarden and writes them to ~/.ssh/.
|
||||
#
|
||||
# Public keys (.pub files) are committed directly to the repo in dot_ssh/
|
||||
# and are applied automatically by chezmoi — no Bitwarden needed for those.
|
||||
#
|
||||
# Requires: bw (Bitwarden CLI) to be logged in and unlocked.
|
||||
# To unlock Bitwarden before running chezmoi:
|
||||
# $env:BW_SESSION = bw unlock --raw
|
||||
# chezmoi apply
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Host "==> Setting up SSH keys from Bitwarden..." -ForegroundColor Cyan
|
||||
|
||||
$SshDir = Join-Path $env:USERPROFILE ".ssh"
|
||||
New-Item -ItemType Directory -Force $SshDir | Out-Null
|
||||
|
||||
function Write-Key($name, $bwItemName) {
|
||||
$keyPath = Join-Path $SshDir $name
|
||||
|
||||
if (Test-Path $keyPath) {
|
||||
Write-Host " Key already exists: $name (skipping)" -ForegroundColor DarkGray
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host " Fetching key: $bwItemName -> $name" -NoNewline
|
||||
|
||||
try {
|
||||
$content = bw get notes "$bwItemName" 2>&1
|
||||
if ($LASTEXITCODE -ne 0) { throw $content }
|
||||
[System.IO.File]::WriteAllText($keyPath, $content)
|
||||
& icacls $keyPath /inheritance:r /grant "$env:USERNAME:(R,W)" /q 2>&1 | Out-Null
|
||||
Write-Host "" -NoNewline
|
||||
Write-Host " Wrote: $keyPath" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "" -NoNewline
|
||||
Write-Host " WARNING: Could not fetch '$bwItemName' from Bitwarden. Skipping." -ForegroundColor Yellow
|
||||
if (Test-Path $keyPath) { Remove-Item $keyPath -Force }
|
||||
}
|
||||
}
|
||||
|
||||
# --- Add your SSH keys below ---
|
||||
# Format: Write-Key "filename_in_~/.ssh" "Bitwarden secure note name"
|
||||
#
|
||||
# Example:
|
||||
# Write-Key "stevan@freeborn.cloud" "SSH Key - stevan@freeborn.cloud"
|
||||
|
||||
Write-Key "bit_bastion.key" "SSH Key - bit_bastion.key"
|
||||
Write-Key "stevan@freeborn.cloud" "SSH Key - stevan@freeborn.cloud"
|
||||
Write-Key "ftp_stevanfreeborn_com" "SSH Key - ftp_stevanfreeborn_com"
|
||||
Write-Key "tangled" "SSH Key - tangled"
|
||||
Write-Key "zenbook_tinker" "SSH Key - zenbook_tinker"
|
||||
Write-Key "gitea.freeborn.cloud" "SSH Key - gitea.freeborn.cloud"
|
||||
Write-Key "id_ed25519" "SSH Key - id_ed25519"
|
||||
Write-Key "macbookair" "SSH Key - macbookair"
|
||||
Write-Key "macbookpro" "SSH Key - macbookpro"
|
||||
Write-Key "truenas" "SSH Key - truenas"
|
||||
Write-Key "blog.stevanfreeborn.com_github_actions" "SSH Key - blog.stevanfreeborn.com_github_actions"
|
||||
Write-Key "commands_github_actions" "SSH Key - commands_github_actions"
|
||||
Write-Key "onspring_qa_playwright_reports_render" "SSH Key - onspring_qa_playwright_reports_render"
|
||||
Write-Key "onx_graph_github_actions" "SSH Key - onx_graph_github_actions"
|
||||
Write-Key "restapiplayground.stevanfreeborn.com_github_actions" "SSH Key - restapiplayground.stevanfreeborn.com_github_actions"
|
||||
Write-Key "steves_bot_github_actions" "SSH Key - steves_bot_github_actions"
|
||||
|
||||
Write-Host "==> SSH key setup complete!" -ForegroundColor Cyan
|
||||
Write-Host " NOTE: Store your SSH private keys as Bitwarden Secure Notes with the names listed above." -ForegroundColor Yellow
|
||||
@@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env bash
|
||||
# run_onchange_linux_install-packages.sh
|
||||
# Installs packages on Ubuntu/Debian via apt and manual installs for tools
|
||||
# not available (or outdated) in apt.
|
||||
# This script re-runs whenever packages/linux.txt changes.
|
||||
#
|
||||
# Hash of packages file (forces re-run on change):
|
||||
# {{ include "packages/linux.txt" | sha256sum }}
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Ensure snap binaries are visible (chezmoi scripts may not inherit /snap/bin)
|
||||
[ -d "/snap/bin" ] && export PATH="$PATH:/snap/bin"
|
||||
|
||||
CHEZMOI_SOURCE_DIR="{{ .chezmoi.sourceDir }}"
|
||||
|
||||
echo "==> Updating apt package index..."
|
||||
sudo apt-get update -q
|
||||
|
||||
echo "==> Installing apt packages..."
|
||||
apt_packages=$(grep -v '^#' "$CHEZMOI_SOURCE_DIR/packages/linux.txt" | grep -v '^$' | tr '\n' ' ')
|
||||
# shellcheck disable=SC2086
|
||||
sudo apt-get install -y $apt_packages
|
||||
|
||||
# --- Tailscale ---
|
||||
if ! command -v tailscale &>/dev/null; then
|
||||
echo "==> Installing Tailscale..."
|
||||
curl -fsSL https://tailscale.com/install.sh | sh
|
||||
else
|
||||
echo "==> Tailscale already installed"
|
||||
fi
|
||||
|
||||
# --- Go ---
|
||||
GO_VERSION=$(curl -fsSL "https://go.dev/dl/?mode=json" | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['version'].lstrip('go'))")
|
||||
if ! command -v go &>/dev/null || [[ "$(go version 2>/dev/null | awk '{print $3}' | tr -d 'go')" != "$GO_VERSION" ]]; then
|
||||
echo "==> Installing Go $GO_VERSION..."
|
||||
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" -o /tmp/go.tar.gz
|
||||
sudo rm -rf /usr/local/go
|
||||
sudo tar -C /usr/local -xzf /tmp/go.tar.gz
|
||||
rm /tmp/go.tar.gz
|
||||
echo "export PATH=\$PATH:/usr/local/go/bin" >> "$HOME/.zshenv"
|
||||
else
|
||||
echo "==> Go already installed"
|
||||
fi
|
||||
|
||||
# --- Rust ---
|
||||
if ! command -v rustup &>/dev/null; then
|
||||
echo "==> Installing Rust via rustup..."
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
|
||||
source "$HOME/.cargo/env"
|
||||
else
|
||||
echo "==> Rust already installed"
|
||||
fi
|
||||
|
||||
# --- NVM (Node Version Manager) ---
|
||||
if [ ! -d "$HOME/.nvm" ]; then
|
||||
echo "==> Installing NVM..."
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
# shellcheck disable=SC1091
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"
|
||||
nvm install --lts
|
||||
else
|
||||
echo "==> NVM already installed"
|
||||
fi
|
||||
|
||||
# --- Oh My Zsh ---
|
||||
if [ ! -d "$HOME/.oh-my-zsh" ]; then
|
||||
echo "==> Installing Oh My Zsh..."
|
||||
RUNZSH=no CHSH=no sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
|
||||
else
|
||||
echo "==> Oh My Zsh already installed"
|
||||
fi
|
||||
|
||||
# --- Oh My Zsh plugins ---
|
||||
ZSH_CUSTOM="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}"
|
||||
|
||||
if [ ! -d "$ZSH_CUSTOM/plugins/zsh-autosuggestions" ]; then
|
||||
echo "==> Installing zsh-autosuggestions..."
|
||||
git clone https://github.com/zsh-users/zsh-autosuggestions "$ZSH_CUSTOM/plugins/zsh-autosuggestions"
|
||||
else
|
||||
echo "==> zsh-autosuggestions already installed"
|
||||
fi
|
||||
|
||||
if [ ! -d "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting" ]; then
|
||||
echo "==> Installing zsh-syntax-highlighting..."
|
||||
git clone https://github.com/zsh-users/zsh-syntax-highlighting "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting"
|
||||
else
|
||||
echo "==> zsh-syntax-highlighting already installed"
|
||||
fi
|
||||
|
||||
# --- Neovim ---
|
||||
if ! command -v nvim &>/dev/null; then
|
||||
echo "==> Installing Neovim (latest)..."
|
||||
curl -fsSL https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz -o /tmp/nvim.tar.gz
|
||||
sudo tar -C /opt -xzf /tmp/nvim.tar.gz
|
||||
sudo ln -sf /opt/nvim-linux-x86_64/bin/nvim /usr/local/bin/nvim
|
||||
rm /tmp/nvim.tar.gz
|
||||
else
|
||||
echo "==> Neovim already installed"
|
||||
fi
|
||||
|
||||
# --- lazygit ---
|
||||
if ! command -v lazygit &>/dev/null; then
|
||||
echo "==> Installing lazygit..."
|
||||
LAZYGIT_VERSION=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | grep -Po '"tag_name": "v\K[^"]*')
|
||||
curl -fsSL "https://github.com/jesseduffield/lazygit/releases/download/v${LAZYGIT_VERSION}/lazygit_${LAZYGIT_VERSION}_Linux_x86_64.tar.gz" -o /tmp/lazygit.tar.gz
|
||||
sudo tar xf /tmp/lazygit.tar.gz lazygit -C /usr/local/bin
|
||||
rm /tmp/lazygit.tar.gz
|
||||
else
|
||||
echo "==> lazygit already installed"
|
||||
fi
|
||||
|
||||
# --- watchexec ---
|
||||
if ! command -v watchexec &>/dev/null; then
|
||||
echo "==> Installing watchexec..."
|
||||
WE_VERSION=$(curl -s "https://api.github.com/repos/watchexec/watchexec/releases/latest" | grep -Po '"tag_name": "v\K[^"]*')
|
||||
curl -fsSL "https://github.com/watchexec/watchexec/releases/download/v${WE_VERSION}/watchexec-${WE_VERSION}-x86_64-unknown-linux-musl.tar.xz" -o /tmp/watchexec.tar.xz
|
||||
tar -xJf /tmp/watchexec.tar.xz -C /tmp "watchexec-${WE_VERSION}-x86_64-unknown-linux-musl/watchexec"
|
||||
sudo mv "/tmp/watchexec-${WE_VERSION}-x86_64-unknown-linux-musl/watchexec" /usr/local/bin/watchexec
|
||||
rm -rf /tmp/watchexec.tar.xz "/tmp/watchexec-${WE_VERSION}-x86_64-unknown-linux-musl"
|
||||
else
|
||||
echo "==> watchexec already installed"
|
||||
fi
|
||||
|
||||
# --- bottom (btm) ---
|
||||
if ! command -v btm &>/dev/null; then
|
||||
echo "==> Installing bottom (btm)..."
|
||||
curl -fsSLO https://github.com/ClementTsang/bottom/releases/latest/download/bottom_x86_64-unknown-linux-musl.tar.gz
|
||||
tar -xzf bottom_x86_64-unknown-linux-musl.tar.gz
|
||||
sudo mv btm /usr/local/bin/
|
||||
rm bottom_x86_64-unknown-linux-musl.tar.gz
|
||||
else
|
||||
echo "==> bottom already installed"
|
||||
fi
|
||||
|
||||
# --- Bitwarden CLI ---
|
||||
if ! command -v bw &>/dev/null; then
|
||||
echo "==> Installing Bitwarden CLI..."
|
||||
BW_VERSION=$(curl -s "https://api.github.com/repos/bitwarden/clients/releases" | grep -Po '"tag_name": "cli-v\K[^"]*' | head -1)
|
||||
if [ -z "$BW_VERSION" ]; then
|
||||
echo "WARNING: Could not determine Bitwarden CLI version, skipping install."
|
||||
else
|
||||
curl -fsSL "https://github.com/bitwarden/clients/releases/download/cli-v${BW_VERSION}/bw-linux-${BW_VERSION}.zip" -o /tmp/bw.zip
|
||||
unzip -o /tmp/bw.zip -d /tmp/bw
|
||||
sudo mv /tmp/bw/bw /usr/local/bin/bw
|
||||
sudo chmod +x /usr/local/bin/bw
|
||||
rm -rf /tmp/bw.zip /tmp/bw
|
||||
fi
|
||||
else
|
||||
echo "==> Bitwarden CLI already installed"
|
||||
fi
|
||||
|
||||
# --- Doppler ---
|
||||
if ! command -v doppler &>/dev/null; then
|
||||
echo "==> Installing Doppler..."
|
||||
curl -Ls --tlsv1.2 --proto "=https" --retry 3 https://cli.doppler.com/install.sh | sudo sh
|
||||
else
|
||||
echo "==> Doppler already installed"
|
||||
fi
|
||||
|
||||
# --- GitHub CLI ---
|
||||
if ! command -v gh &>/dev/null; then
|
||||
echo "==> Installing GitHub CLI..."
|
||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
|
||||
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
|
||||
sudo apt-get update -q
|
||||
sudo apt-get install gh -y
|
||||
else
|
||||
echo "==> GitHub CLI already installed"
|
||||
fi
|
||||
|
||||
# --- uv (Python package/project manager) ---
|
||||
if ! command -v uv &>/dev/null; then
|
||||
echo "==> Installing uv..."
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
else
|
||||
echo "==> uv already installed"
|
||||
fi
|
||||
|
||||
# --- Docker ---
|
||||
if ! command -v docker &>/dev/null; then
|
||||
echo "==> Installing Docker..."
|
||||
curl -fsSL https://get.docker.com | sh
|
||||
sudo usermod -aG docker "$USER"
|
||||
echo "NOTE: Log out and back in for Docker group membership to take effect."
|
||||
else
|
||||
echo "==> Docker already installed"
|
||||
fi
|
||||
|
||||
# --- .NET SDK (8 + 10) ---
|
||||
# Uses Microsoft's official dotnet-install.sh script
|
||||
DOTNET_INSTALL_DIR="$HOME/.dotnet"
|
||||
DOTNET_SCRIPT=$(mktemp /tmp/dotnet-install-XXXXXX.sh)
|
||||
curl -fsSL https://dot.net/v1/dotnet-install.sh -o "$DOTNET_SCRIPT"
|
||||
chmod +x "$DOTNET_SCRIPT"
|
||||
|
||||
for DOTNET_CHANNEL in "8.0" "10.0"; do
|
||||
MAJOR="${DOTNET_CHANNEL%%.*}"
|
||||
DOTNET_VERSION_INSTALLED=$(find "$DOTNET_INSTALL_DIR/sdk" -maxdepth 1 -name "${MAJOR}.*" 2>/dev/null | head -1 || echo "")
|
||||
if [ -z "$DOTNET_VERSION_INSTALLED" ]; then
|
||||
echo "==> Installing .NET SDK $DOTNET_CHANNEL..."
|
||||
"$DOTNET_SCRIPT" --channel "$DOTNET_CHANNEL" --install-dir "$DOTNET_INSTALL_DIR"
|
||||
else
|
||||
echo "==> .NET SDK $DOTNET_CHANNEL already installed"
|
||||
fi
|
||||
done
|
||||
|
||||
rm -f "$DOTNET_SCRIPT"
|
||||
|
||||
echo ""
|
||||
echo "==> Linux package installation complete!"
|
||||
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# run_onchange_windows_install-packages.ps1.tmpl
|
||||
# Installs all packages from packages/windows.json via winget.
|
||||
# This script re-runs whenever packages/windows.json changes.
|
||||
#
|
||||
# Hash of packages file (forces re-run on change):
|
||||
# {{ include "packages/windows.json" | sha256sum }}
|
||||
|
||||
$ErrorActionPreference = "Continue"
|
||||
|
||||
Write-Host "==> Installing packages via winget..." -ForegroundColor Cyan
|
||||
|
||||
# Use the chezmoi source packages file directly
|
||||
$sourcePackages = "{{ .chezmoi.sourceDir }}/packages/windows.json"
|
||||
$sourcePackages = [System.IO.Path]::GetFullPath($sourcePackages)
|
||||
|
||||
if (-not (Test-Path $sourcePackages)) {
|
||||
Write-Warning "packages/windows.json not found at: $sourcePackages"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$packageList = Get-Content $sourcePackages -Raw | ConvertFrom-Json
|
||||
$packages = $packageList.Sources[0].Packages
|
||||
|
||||
$total = $packages.Count
|
||||
$installed = 0
|
||||
$skipped = 0
|
||||
$failed = 0
|
||||
|
||||
foreach ($pkg in $packages) {
|
||||
$id = $pkg.PackageIdentifier
|
||||
Write-Host " Checking $id..." -NoNewline
|
||||
|
||||
# Check if already installed
|
||||
$check = winget list --id $id --exact --accept-source-agreements 2>$null | Select-String $id
|
||||
if ($check) {
|
||||
Write-Host " already installed" -ForegroundColor DarkGray
|
||||
$skipped++
|
||||
continue
|
||||
}
|
||||
|
||||
# Install
|
||||
Write-Host " installing..." -NoNewline
|
||||
$result = winget install --id $id --exact --silent --accept-package-agreements --accept-source-agreements 2>&1
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host " done" -ForegroundColor Green
|
||||
$installed++
|
||||
} else {
|
||||
Write-Host " FAILED (exit $LASTEXITCODE)" -ForegroundColor Red
|
||||
$failed++
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "==> Package install complete: $installed installed, $skipped already present, $failed failed" -ForegroundColor Cyan
|
||||
|
||||
# =============================================================================
|
||||
# Manual installs — tools not available on winget
|
||||
# =============================================================================
|
||||
|
||||
$LocalBin = Join-Path $env:USERPROFILE ".local\bin"
|
||||
if (-not (Test-Path $LocalBin)) {
|
||||
New-Item -ItemType Directory -Force $LocalBin | Out-Null
|
||||
}
|
||||
|
||||
# Ensure ~/.local/bin is in the user PATH
|
||||
$userPath = [System.Environment]::GetEnvironmentVariable("PATH", "User")
|
||||
if ($userPath -notlike "*$LocalBin*") {
|
||||
[System.Environment]::SetEnvironmentVariable("PATH", "$userPath;$LocalBin", "User")
|
||||
$env:PATH = "$env:PATH;$LocalBin"
|
||||
Write-Host " Added $LocalBin to user PATH." -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Install-GitHubBinary {
|
||||
param(
|
||||
[string]$Name,
|
||||
[string]$Repo,
|
||||
[string]$AssetPattern,
|
||||
[string]$BinaryName = "$Name.exe"
|
||||
)
|
||||
|
||||
$BinPath = Join-Path $LocalBin $BinaryName
|
||||
if (Test-Path $BinPath) {
|
||||
Write-Host " $Name already installed" -ForegroundColor DarkGray
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host " Installing $Name..." -NoNewline
|
||||
try {
|
||||
$release = Invoke-RestMethod "https://api.github.com/repos/$Repo/releases/latest"
|
||||
$asset = $release.assets | Where-Object { $_.name -like $AssetPattern } | Select-Object -First 1
|
||||
if (-not $asset) { throw "No matching asset found for pattern: $AssetPattern" }
|
||||
|
||||
$tmpZip = Join-Path $env:TEMP "$Name-$($release.tag_name).zip"
|
||||
$tmpDir = Join-Path $env:TEMP "$Name-$($release.tag_name)"
|
||||
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $tmpZip -UseBasicParsing
|
||||
Expand-Archive -Path $tmpZip -DestinationPath $tmpDir -Force
|
||||
$exe = Get-ChildItem -Recurse $tmpDir -Filter $BinaryName | Select-Object -First 1
|
||||
Copy-Item $exe.FullName $BinPath
|
||||
Remove-Item $tmpZip -Force
|
||||
Remove-Item $tmpDir -Recurse -Force
|
||||
Write-Host " done" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host " FAILED: $_" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "==> Installing manual (non-winget) packages..." -ForegroundColor Cyan
|
||||
|
||||
# watchexec — https://github.com/watchexec/watchexec
|
||||
Install-GitHubBinary -Name "watchexec" -Repo "watchexec/watchexec" -AssetPattern "*x86_64-pc-windows-msvc.zip"
|
||||
Reference in New Issue
Block a user