initial commit
This commit is contained in:
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# macOS
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Temporary files
|
||||
*.log
|
||||
*.tmp
|
||||
.cache/
|
||||
51
QUICKSTART.md
Normal file
51
QUICKSTART.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Quick Start
|
||||
|
||||
## One Command
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
xcode-select --install && \
|
||||
git clone https://git.sdf.org/jchenry/provision ~/.provision && \
|
||||
~/.provision/provision
|
||||
|
||||
# Linux
|
||||
git clone https://git.sdf.org/jchenry/provision ~/.provision && \
|
||||
~/.provision/provision
|
||||
```
|
||||
|
||||
## What Happens
|
||||
|
||||
1. Installs package manager (Homebrew/apt/pacman)
|
||||
2. Installs CLI tools (tmux, fzf, ripgrep, starship, etc.)
|
||||
3. Installs apps (VSCodium, 1Password, Obsidian, Chrome, Todoist)
|
||||
4. Installs Go to `/usr/local/go`
|
||||
5. Installs Plan9 to `/usr/local/plan9`
|
||||
6. Links config files
|
||||
|
||||
## After Installation
|
||||
|
||||
```bash
|
||||
# Restart shell
|
||||
exec $SHELL
|
||||
|
||||
# Edit git config
|
||||
nano ~/.gitconfig
|
||||
|
||||
# Install tmux plugins
|
||||
# In tmux: Ctrl+a then I
|
||||
```
|
||||
|
||||
## Skip Options
|
||||
|
||||
```bash
|
||||
# Skip apps (faster, CLI-only setup)
|
||||
provision --skip-apps
|
||||
|
||||
# Skip Go
|
||||
provision --skip-go
|
||||
|
||||
# Skip Plan9
|
||||
provision --skip-p9
|
||||
```
|
||||
|
||||
Done!
|
||||
76
README.md
Normal file
76
README.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Provision
|
||||
|
||||
Simple, idempotent provisioning for macOS and Linux.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
git clone https://git.sdf.org/jchenry/provision ~/.provision
|
||||
~/.provision/provision
|
||||
exec $SHELL
|
||||
```
|
||||
|
||||
## What Gets Installed
|
||||
|
||||
- **Packages**: git, curl, tmux, fzf, ripgrep, starship, zoxide, eza, fd, gh, jq
|
||||
- **Apps**: VSCodium, 1Password, Obsidian, Chrome, Todoist
|
||||
- **Go**: Latest version to `/usr/local/go`
|
||||
- **Plan9**: Installed to `/usr/local/plan9`
|
||||
- **Config**: bash, tmux, starship, git configs
|
||||
|
||||
## Options
|
||||
|
||||
```bash
|
||||
provision # Full provision
|
||||
provision --skip-apps # Skip GUI apps
|
||||
provision --skip-go # Skip Go installation
|
||||
provision --skip-p9 # Skip Plan9 installation
|
||||
provision --help # Show help
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
provision/
|
||||
├── provision # Main script
|
||||
├── lib/ # Utilities
|
||||
├── scripts/ # Install scripts
|
||||
│ ├── packages.sh # CLI tools
|
||||
│ ├── apps.sh # GUI applications
|
||||
│ ├── golang.sh # Go installation
|
||||
│ └── plan9port.sh # Plan9 installation
|
||||
└── config/ # Config files
|
||||
├── bashrc
|
||||
├── tmux.conf
|
||||
├── starship.toml
|
||||
├── gitconfig
|
||||
├── gitignore_global
|
||||
├── vscode-extensions.txt
|
||||
├── xinitrc # X11 init (TWM)
|
||||
├── Xresources # X11 resources
|
||||
└── twmrc # TWM window manager config
|
||||
```
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
- macOS (Homebrew)
|
||||
- Debian/Ubuntu (apt)
|
||||
- Arch Linux (pacman + AUR)
|
||||
|
||||
## Customization
|
||||
|
||||
Edit files in `config/` directory, then re-run:
|
||||
|
||||
```bash
|
||||
~/.provision/config/link-dotfiles.sh
|
||||
```
|
||||
|
||||
## After Installation
|
||||
|
||||
1. Edit `~/.gitconfig` - set your name and email
|
||||
2. In tmux, press `Ctrl+a` then `I` to install plugins
|
||||
3. Customize `~/.provision/config/` files as needed
|
||||
|
||||
## References
|
||||
|
||||
- Blog: https://jnsgr.uk/2025/06/from-nixos-to-ubuntu/
|
||||
65
SUMMARY.md
Normal file
65
SUMMARY.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Provision System - Final Summary
|
||||
|
||||
## What It Does
|
||||
|
||||
One-command provisioning for macOS and Linux with:
|
||||
- CLI tools (tmux, fzf, ripgrep, starship, zoxide, etc.)
|
||||
- GUI apps (VSCodium, 1Password, Obsidian, Chrome)
|
||||
- Go (tar.gz → /usr/local/go)
|
||||
- Plan9port (built → /usr/local/plan9)
|
||||
- Config files (bash, tmux, git, starship)
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
provision/
|
||||
├── provision # Main script (140 lines)
|
||||
├── README.md # 69 lines
|
||||
├── QUICKSTART.md # 52 lines
|
||||
│
|
||||
├── lib/ # Utilities
|
||||
│ ├── common.sh # Platform detection, logging
|
||||
│ └── package.sh # Package manager abstraction
|
||||
│
|
||||
├── scripts/ # 4 install scripts
|
||||
│ ├── packages.sh # All CLI tools
|
||||
│ ├── apps.sh # All GUI apps
|
||||
│ ├── golang.sh # Go from tar.gz
|
||||
│ └── plan9port.sh # Plan9 from git
|
||||
│
|
||||
└── config/ # Config files
|
||||
├── link-dotfiles.sh
|
||||
├── bashrc # Includes Go & Plan9 paths
|
||||
├── tmux.conf
|
||||
├── starship.toml
|
||||
├── gitconfig
|
||||
└── gitignore_global
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Full provision
|
||||
~/.provision/provision
|
||||
|
||||
# Skip components
|
||||
provision --skip-apps # No GUI apps
|
||||
provision --skip-go # No Go
|
||||
provision --skip-p9 # No Plan9
|
||||
```
|
||||
|
||||
## Platforms
|
||||
|
||||
- macOS (Homebrew + casks)
|
||||
- Debian/Ubuntu (apt + .deb downloads)
|
||||
- Arch Linux (pacman + AUR)
|
||||
|
||||
## Key Features
|
||||
|
||||
1. **Simple**: 4 scripts instead of 20+
|
||||
2. **Fast**: Parallel installs where possible
|
||||
3. **Idempotent**: Safe to re-run
|
||||
4. **Self-contained**: All config files included
|
||||
5. **Flexible**: Skip any component
|
||||
|
||||
Total: ~500 lines of shell script
|
||||
43
config/Xresources
Normal file
43
config/Xresources
Normal file
@@ -0,0 +1,43 @@
|
||||
! X11 Resources Configuration
|
||||
|
||||
! Dracula Xresources palette
|
||||
*.foreground: #F8F8F2
|
||||
*.background: #282A36
|
||||
*.color0: #000000
|
||||
*.color8: #4D4D4D
|
||||
*.color1: #FF5555
|
||||
*.color9: #FF6E67
|
||||
*.color2: #50FA7B
|
||||
*.color10: #5AF78E
|
||||
*.color3: #F1FA8C
|
||||
*.color11: #F4F99D
|
||||
*.color4: #BD93F9
|
||||
*.color12: #CAA9FA
|
||||
*.color5: #FF79C6
|
||||
*.color13: #FF92D0
|
||||
*.color6: #8BE9FD
|
||||
*.color14: #9AEDFE
|
||||
*.color7: #BFBFBF
|
||||
*.color15: #E6E6E6
|
||||
|
||||
|
||||
|
||||
! XTerm settings
|
||||
XTerm*termName: xterm-256color
|
||||
XTerm*locale: true
|
||||
XTerm*utf8: 1
|
||||
XTerm*saveLines: 10000
|
||||
XTerm*scrollBar: false
|
||||
XTerm*rightScrollBar: false
|
||||
|
||||
! XTerm fonts
|
||||
XTerm*faceName: Monospace
|
||||
XTerm*faceSize: 11
|
||||
|
||||
! TWM settings
|
||||
Twm*BorderWidth: 2
|
||||
Twm*TitleFont: -adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*
|
||||
Twm*MenuFont: -adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*
|
||||
Twm*IconFont: -adobe-helvetica-bold-r-normal--*-100-*-*-*-*-*-*
|
||||
|
||||
|
||||
81
config/bashrc
Normal file
81
config/bashrc
Normal file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
# Bash configuration
|
||||
|
||||
export BASH_SILENCE_DEPRECATION_WARNING=1
|
||||
|
||||
# XDG Base Directory
|
||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
|
||||
|
||||
# Homebrew (macOS)
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
if [ -f "/opt/homebrew/bin/brew" ]; then
|
||||
eval "$(/opt/homebrew/bin/brew shellenv)"
|
||||
elif [ -f "/usr/local/bin/brew" ]; then
|
||||
eval "$(/usr/local/bin/brew shellenv)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Go
|
||||
if [ -d "/usr/local/go" ]; then
|
||||
export PATH="$PATH:/usr/local/go/bin"
|
||||
export PATH="$PATH:$HOME/go/bin"
|
||||
fi
|
||||
|
||||
# Plan 9
|
||||
if [ -d "/usr/local/plan9" ]; then
|
||||
export PLAN9="/usr/local/plan9"
|
||||
export PATH="$PATH:$PLAN9/bin"
|
||||
fi
|
||||
|
||||
# History settings
|
||||
export HISTSIZE=10000
|
||||
export HISTFILESIZE=20000
|
||||
export HISTCONTROL=ignoredups:erasedups
|
||||
shopt -s histappend
|
||||
|
||||
# Aliases
|
||||
alias ll='ls -lah'
|
||||
alias la='ls -A'
|
||||
alias l='ls -CF'
|
||||
|
||||
# Modern replacements
|
||||
if command -v eza &> /dev/null; then
|
||||
alias ls='eza'
|
||||
alias ll='eza -la'
|
||||
alias lt='eza --tree'
|
||||
fi
|
||||
|
||||
if command -v bat &> /dev/null; then
|
||||
alias cat='bat'
|
||||
fi
|
||||
|
||||
# fd for Debian (named fd-find)
|
||||
if command -v fdfind &> /dev/null && ! command -v fd &> /dev/null; then
|
||||
alias fd='fdfind'
|
||||
fi
|
||||
|
||||
# Git completions
|
||||
if [ -f /usr/share/bash-completion/completions/git ]; then
|
||||
. /usr/share/bash-completion/completions/git
|
||||
fi
|
||||
|
||||
# Starship prompt
|
||||
if command -v starship &> /dev/null; then
|
||||
eval "$(starship init bash)"
|
||||
fi
|
||||
|
||||
# Zoxide (smarter cd)
|
||||
if command -v zoxide &> /dev/null; then
|
||||
eval "$(zoxide init bash)"
|
||||
fi
|
||||
|
||||
# fzf
|
||||
if command -v fzf &> /dev/null; then
|
||||
if [ -f ~/.fzf.bash ]; then
|
||||
source ~/.fzf.bash
|
||||
elif [ -f /usr/share/doc/fzf/examples/key-bindings.bash ]; then
|
||||
source /usr/share/doc/fzf/examples/key-bindings.bash
|
||||
fi
|
||||
fi
|
||||
28
config/gitconfig
Normal file
28
config/gitconfig
Normal file
@@ -0,0 +1,28 @@
|
||||
[user]
|
||||
name = YOUR_NAME
|
||||
email = YOUR_EMAIL
|
||||
|
||||
[core]
|
||||
excludesfile = ~/.gitignore_global
|
||||
editor = nano
|
||||
|
||||
[init]
|
||||
defaultBranch = main
|
||||
|
||||
[pull]
|
||||
rebase = false
|
||||
|
||||
[push]
|
||||
default = simple
|
||||
|
||||
[alias]
|
||||
st = status
|
||||
co = checkout
|
||||
br = branch
|
||||
ci = commit
|
||||
lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
|
||||
last = log -1 HEAD
|
||||
unstage = reset HEAD --
|
||||
|
||||
[color]
|
||||
ui = auto
|
||||
31
config/gitignore_global
Normal file
31
config/gitignore_global
Normal file
@@ -0,0 +1,31 @@
|
||||
# macOS
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
._*
|
||||
|
||||
# Linux
|
||||
*~
|
||||
.directory
|
||||
|
||||
# Editors
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
|
||||
# Compiled
|
||||
*.class
|
||||
*.pyc
|
||||
*.o
|
||||
*.so
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# Temporary
|
||||
tmp/
|
||||
temp/
|
||||
.cache/
|
||||
101
config/link-dotfiles.sh
Executable file
101
config/link-dotfiles.sh
Executable file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../lib/common.sh"
|
||||
|
||||
log_info "Linking configuration files"
|
||||
|
||||
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
|
||||
# Link bash configuration
|
||||
log_info "Setting up bash configuration"
|
||||
if ! grep -q "source $SCRIPT_DIR/bashrc" "$HOME/.bashrc" 2>/dev/null; then
|
||||
echo "" >> "$HOME/.bashrc"
|
||||
echo "# Added by provision" >> "$HOME/.bashrc"
|
||||
echo "source $SCRIPT_DIR/bashrc" >> "$HOME/.bashrc"
|
||||
log_success "Added bash configuration to ~/.bashrc"
|
||||
else
|
||||
log_info "Bash configuration already in ~/.bashrc"
|
||||
fi
|
||||
|
||||
if [ -f "$HOME/.bash_profile" ]; then
|
||||
if ! grep -q "source $SCRIPT_DIR/bashrc" "$HOME/.bash_profile" 2>/dev/null; then
|
||||
echo "" >> "$HOME/.bash_profile"
|
||||
echo "# Added by provision" >> "$HOME/.bash_profile"
|
||||
echo "source $SCRIPT_DIR/bashrc" >> "$HOME/.bash_profile"
|
||||
log_success "Added bash configuration to ~/.bash_profile"
|
||||
else
|
||||
log_info "Bash configuration already in ~/.bash_profile"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Link tmux configuration
|
||||
log_info "Setting up tmux configuration"
|
||||
ensure_dir "$XDG_CONFIG_HOME/tmux"
|
||||
safe_symlink "$SCRIPT_DIR/tmux.conf" "$XDG_CONFIG_HOME/tmux/tmux.conf"
|
||||
|
||||
# Link starship configuration
|
||||
log_info "Setting up starship configuration"
|
||||
safe_symlink "$SCRIPT_DIR/starship.toml" "$XDG_CONFIG_HOME/starship.toml"
|
||||
|
||||
# Link git configuration
|
||||
log_info "Setting up git configuration"
|
||||
if [ -f "$HOME/.gitconfig" ]; then
|
||||
log_warn "~/.gitconfig already exists, skipping (edit $SCRIPT_DIR/gitconfig and copy manually)"
|
||||
else
|
||||
safe_symlink "$SCRIPT_DIR/gitconfig" "$HOME/.gitconfig"
|
||||
log_warn "Remember to edit ~/.gitconfig and set your name and email!"
|
||||
fi
|
||||
safe_symlink "$SCRIPT_DIR/gitignore_global" "$HOME/.gitignore_global"
|
||||
|
||||
# Link X11 configuration (Linux only)
|
||||
if is_linux; then
|
||||
log_info "Setting up X11 configuration"
|
||||
|
||||
if [ -f "$SCRIPT_DIR/xinitrc" ]; then
|
||||
safe_symlink "$SCRIPT_DIR/xinitrc" "$HOME/.xinitrc"
|
||||
chmod +x "$HOME/.xinitrc"
|
||||
fi
|
||||
|
||||
if [ -f "$SCRIPT_DIR/Xresources" ]; then
|
||||
safe_symlink "$SCRIPT_DIR/Xresources" "$HOME/.Xresources"
|
||||
fi
|
||||
|
||||
if [ -f "$SCRIPT_DIR/twmrc" ]; then
|
||||
safe_symlink "$SCRIPT_DIR/twmrc" "$HOME/.twmrc"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Install VSCode extensions
|
||||
if command_exists codium || command_exists code; then
|
||||
if [ -f "$SCRIPT_DIR/vscode-extensions.txt" ]; then
|
||||
log_info "Installing VSCode/VSCodium extensions"
|
||||
|
||||
CODE_CMD="codium"
|
||||
if ! command_exists codium && command_exists code; then
|
||||
CODE_CMD="code"
|
||||
fi
|
||||
|
||||
while IFS= read -r extension; do
|
||||
# Skip empty lines and comments
|
||||
[[ -z "$extension" || "$extension" =~ ^[[:space:]]*# ]] && continue
|
||||
|
||||
if $CODE_CMD --list-extensions 2>/dev/null | grep -qi "^$extension$"; then
|
||||
log_info "Extension already installed: $extension"
|
||||
else
|
||||
log_info "Installing extension: $extension"
|
||||
$CODE_CMD --install-extension "$extension" --force 2>/dev/null || log_warn "Failed to install: $extension"
|
||||
fi
|
||||
done < "$SCRIPT_DIR/vscode-extensions.txt"
|
||||
fi
|
||||
else
|
||||
log_info "VSCode/VSCodium not installed, skipping extensions"
|
||||
fi
|
||||
|
||||
log_success "Configuration files linked successfully"
|
||||
log_info ""
|
||||
log_info "Next steps:"
|
||||
log_info " 1. Edit ~/.gitconfig to set your name and email"
|
||||
log_info " 2. Restart your shell: exec \$SHELL"
|
||||
log_info " 3. Install tmux plugins: press Ctrl+a then I in tmux"
|
||||
29
config/starship.toml
Normal file
29
config/starship.toml
Normal file
@@ -0,0 +1,29 @@
|
||||
# Starship prompt configuration
|
||||
|
||||
add_newline = false
|
||||
|
||||
[username]
|
||||
style_user = "white bold"
|
||||
format = "$user($style)"
|
||||
show_always = true
|
||||
|
||||
[hostname]
|
||||
ssh_only = false
|
||||
format = "@$hostname:"
|
||||
disabled = false
|
||||
|
||||
[directory]
|
||||
truncation_length = 3
|
||||
truncate_to_repo = true
|
||||
|
||||
[character]
|
||||
success_symbol = "[\\$](green)"
|
||||
error_symbol = "[\\$](red)"
|
||||
|
||||
[git_branch]
|
||||
symbol = " "
|
||||
|
||||
[git_status]
|
||||
ahead = "⇡${count}"
|
||||
diverged = "⇕⇡${ahead_count}⇣${behind_count}"
|
||||
behind = "⇣${count}"
|
||||
38
config/tmux.conf
Normal file
38
config/tmux.conf
Normal file
@@ -0,0 +1,38 @@
|
||||
# Tmux configuration
|
||||
# Based on: https://www.youtube.com/watch?v=B-1wGwvUwm8
|
||||
|
||||
# Remap prefix from 'C-b' to 'C-a'
|
||||
unbind C-b
|
||||
set -g prefix C-a
|
||||
bind C-a send-prefix
|
||||
|
||||
# Reload config
|
||||
unbind r
|
||||
bind r source-file ~/.config/tmux/tmux.conf \; display "Reloaded!"
|
||||
|
||||
# Split panes
|
||||
unbind h
|
||||
bind h split-window -v
|
||||
|
||||
unbind v
|
||||
bind v split-window -h
|
||||
|
||||
# Enable mouse mode (optional)
|
||||
# set -g mouse on
|
||||
|
||||
# Start windows and panes at 1, not 0
|
||||
set -g base-index 1
|
||||
setw -g pane-base-index 1
|
||||
|
||||
# TPM plugins
|
||||
set -g @plugin 'tmux-plugins/tpm'
|
||||
set -g @plugin 'tmux-plugins/tmux-sensible'
|
||||
|
||||
# Dracula theme
|
||||
set -g @plugin 'dracula/tmux'
|
||||
set -g @dracula-show-powerline true
|
||||
set -g @dracula-show-left-icon session
|
||||
set -g @dracula-plugins "cpu-usage ram-usage"
|
||||
|
||||
# Initialize TPM (keep this line at the very bottom)
|
||||
run '~/.config/tmux/plugins/tpm/tpm'
|
||||
120
config/twmrc
Normal file
120
config/twmrc
Normal file
@@ -0,0 +1,120 @@
|
||||
# TWM Configuration File
|
||||
|
||||
# Color settings
|
||||
Color
|
||||
{
|
||||
BorderColor "slategrey"
|
||||
DefaultBackground "rgb:2/a/9"
|
||||
DefaultForeground "gray85"
|
||||
TitleBackground "rgb:2/a/9"
|
||||
TitleForeground "gray85"
|
||||
MenuBackground "rgb:2/a/9"
|
||||
MenuForeground "gray85"
|
||||
MenuTitleBackground "gray70"
|
||||
MenuTitleForeground "rgb:2/a/9"
|
||||
IconBackground "rgb:2/a/9"
|
||||
IconForeground "gray85"
|
||||
IconBorderColor "gray85"
|
||||
IconManagerBackground "rgb:2/a/9"
|
||||
IconManagerForeground "gray85"
|
||||
}
|
||||
|
||||
# Fonts
|
||||
TitleFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*"
|
||||
ResizeFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*"
|
||||
MenuFont "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*"
|
||||
IconFont "-adobe-helvetica-bold-r-normal--*-100-*-*-*-*-*-*"
|
||||
IconManagerFont "-adobe-helvetica-bold-r-normal--*-100-*-*-*"
|
||||
|
||||
# Border and title settings
|
||||
BorderWidth 2
|
||||
TitleButtonBorderWidth 0
|
||||
ButtonIndent 0
|
||||
FramePadding 2
|
||||
TitlePadding 8
|
||||
|
||||
# Behavior
|
||||
DecorateTransients
|
||||
NoDefaults
|
||||
NoGrabServer
|
||||
RestartPreviousState
|
||||
RandomPlacement
|
||||
NoTitle
|
||||
{
|
||||
"TWM"
|
||||
}
|
||||
|
||||
# Icon Manager
|
||||
ShowIconManager
|
||||
IconManagerGeometry "200x-1-1+0" 1
|
||||
IconManagerDontShow
|
||||
{
|
||||
"xclock"
|
||||
"xload"
|
||||
}
|
||||
|
||||
# Auto raise
|
||||
AutoRaise
|
||||
{
|
||||
"XTerm"
|
||||
}
|
||||
|
||||
# Functions
|
||||
Function "move-or-lower" { f.move f.deltastop f.lower }
|
||||
Function "move-or-raise" { f.move f.deltastop f.raise }
|
||||
Function "move-or-iconify" { f.move f.deltastop f.iconify }
|
||||
|
||||
# Mouse Button Bindings
|
||||
Button1 = : root : f.menu "defops"
|
||||
Button2 = : root : f.menu "windowops"
|
||||
Button3 = : root : f.menu "TwmWindows"
|
||||
|
||||
Button1 = m : window|icon : f.function "move-or-lower"
|
||||
Button2 = m : window|icon : f.iconify
|
||||
Button3 = m : window|icon : f.function "move-or-raise"
|
||||
|
||||
Button1 = : title : f.function "move-or-raise"
|
||||
Button2 = : title : f.raiselower
|
||||
Button3 = : title : f.menu "windowops"
|
||||
|
||||
Button1 = : icon : f.function "move-or-iconify"
|
||||
Button2 = : icon : f.iconify
|
||||
Button3 = : icon : f.menu "windowops"
|
||||
|
||||
Button1 = : iconmgr : f.iconify
|
||||
Button2 = : iconmgr : f.iconify
|
||||
Button3 = : iconmgr : f.raiselower
|
||||
|
||||
# Menus
|
||||
menu "defops"
|
||||
{
|
||||
"TWM" f.title
|
||||
"XTerm" f.exec "xterm &"
|
||||
"" f.nop
|
||||
"Restart" f.restart
|
||||
"Exit" f.quit
|
||||
}
|
||||
|
||||
menu "windowops"
|
||||
{
|
||||
"Window Ops" f.title
|
||||
"Raise" f.raise
|
||||
"Lower" f.lower
|
||||
"Iconify" f.iconify
|
||||
"Resize" f.resize
|
||||
"Move" f.move
|
||||
"" f.nop
|
||||
"Focus" f.focus
|
||||
"Unfocus" f.unfocus
|
||||
"" f.nop
|
||||
"Delete" f.delete
|
||||
"Destroy" f.destroy
|
||||
}
|
||||
|
||||
# Key Bindings
|
||||
"F1" = : all : f.iconify
|
||||
"F2" = : all : f.raiselower
|
||||
"F3" = : all : f.fullzoom
|
||||
"F4" = : all : f.delete
|
||||
|
||||
# Startup commands (via .xinitrc instead)
|
||||
12
config/vscode-extensions.txt
Normal file
12
config/vscode-extensions.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
# VSCode/VSCodium Extensions
|
||||
# One extension ID per line
|
||||
# Lines starting with # are ignored
|
||||
|
||||
# Themes
|
||||
dracula-theme.theme-dracula
|
||||
|
||||
# Languages
|
||||
golang.go
|
||||
|
||||
# AI/Assistant
|
||||
anthropic.claude-code
|
||||
22
config/xinitrc
Executable file
22
config/xinitrc
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
# X11 initialization script
|
||||
|
||||
# Load X resources
|
||||
if [ -f "$HOME/.Xresources" ]; then
|
||||
xrdb -merge "$HOME/.Xresources"
|
||||
fi
|
||||
|
||||
# Set keyboard repeat rate
|
||||
xset r rate 200 30
|
||||
|
||||
# Disable screen blanking
|
||||
xset s off
|
||||
xset -dpms
|
||||
|
||||
# Start terminal emulator in background
|
||||
if command -v xterm >/dev/null 2>&1; then
|
||||
xterm &
|
||||
fi
|
||||
|
||||
# Start TWM window manager
|
||||
exec twm
|
||||
118
lib/common.sh
Executable file
118
lib/common.sh
Executable file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env bash
|
||||
# Common utility functions for provisioning scripts
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1" >&2
|
||||
}
|
||||
|
||||
# Platform detection
|
||||
detect_os() {
|
||||
case "$OSTYPE" in
|
||||
darwin*) echo "macos" ;;
|
||||
linux*)
|
||||
if [ -f /etc/arch-release ]; then
|
||||
echo "arch"
|
||||
elif [ -f /etc/debian_version ]; then
|
||||
echo "debian"
|
||||
else
|
||||
echo "linux"
|
||||
fi
|
||||
;;
|
||||
*) echo "unknown" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Check if command exists
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Check if running on macOS
|
||||
is_macos() {
|
||||
[ "$(detect_os)" = "macos" ]
|
||||
}
|
||||
|
||||
# Check if running on Debian/Ubuntu
|
||||
is_debian() {
|
||||
[ "$(detect_os)" = "debian" ]
|
||||
}
|
||||
|
||||
# Check if running on Arch
|
||||
is_arch() {
|
||||
[ "$(detect_os)" = "arch" ]
|
||||
}
|
||||
|
||||
# Check if running on Linux
|
||||
is_linux() {
|
||||
[[ "$OSTYPE" == "linux"* ]]
|
||||
}
|
||||
|
||||
# Create directory if it doesn't exist
|
||||
ensure_dir() {
|
||||
if [ ! -d "$1" ]; then
|
||||
mkdir -p "$1"
|
||||
log_info "Created directory: $1"
|
||||
fi
|
||||
}
|
||||
|
||||
# Create symlink, backing up existing file if needed
|
||||
safe_symlink() {
|
||||
local source="$1"
|
||||
local target="$2"
|
||||
|
||||
if [ -L "$target" ]; then
|
||||
# It's already a symlink
|
||||
if [ "$(readlink "$target")" = "$source" ]; then
|
||||
log_info "Symlink already exists: $target -> $source"
|
||||
return 0
|
||||
else
|
||||
log_warn "Replacing existing symlink: $target"
|
||||
rm "$target"
|
||||
fi
|
||||
elif [ -f "$target" ] || [ -d "$target" ]; then
|
||||
# File or directory exists, back it up
|
||||
local backup="${target}.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
log_warn "Backing up existing file to: $backup"
|
||||
mv "$target" "$backup"
|
||||
fi
|
||||
|
||||
ln -sf "$source" "$target"
|
||||
log_success "Created symlink: $target -> $source"
|
||||
}
|
||||
|
||||
# Execute command with sudo if not running as root
|
||||
maybe_sudo() {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
sudo "$@"
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if script is being sourced or executed
|
||||
is_sourced() {
|
||||
[ "${BASH_SOURCE[0]}" != "${0}" ]
|
||||
}
|
||||
|
||||
# Export OS detection for use in other scripts
|
||||
export OS_TYPE=$(detect_os)
|
||||
214
lib/package.sh
Executable file
214
lib/package.sh
Executable file
@@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env bash
|
||||
# Package manager abstraction functions
|
||||
|
||||
# Source common utilities if not already sourced
|
||||
if [ -z "$OS_TYPE" ]; then
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
fi
|
||||
|
||||
# Update package manager cache
|
||||
update_package_cache() {
|
||||
log_info "Updating package cache"
|
||||
|
||||
case "$OS_TYPE" in
|
||||
macos)
|
||||
if command_exists brew; then
|
||||
brew update
|
||||
else
|
||||
log_error "Homebrew not installed"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
debian)
|
||||
maybe_sudo apt-get update -qq
|
||||
;;
|
||||
arch)
|
||||
maybe_sudo pacman -Sy --noconfirm
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported OS: $OS_TYPE"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Install a package using the appropriate package manager
|
||||
install_package() {
|
||||
local package="$1"
|
||||
local package_debian="${2:-$package}"
|
||||
local package_arch="${3:-$package}"
|
||||
|
||||
log_info "Installing package: $package"
|
||||
|
||||
case "$OS_TYPE" in
|
||||
macos)
|
||||
if ! command_exists brew; then
|
||||
log_error "Homebrew not installed. Run system/macos-setup.sh first"
|
||||
return 1
|
||||
fi
|
||||
brew install "$package"
|
||||
;;
|
||||
debian)
|
||||
maybe_sudo apt-get install -y -qq "$package_debian"
|
||||
;;
|
||||
arch)
|
||||
maybe_sudo pacman -S --noconfirm --needed "$package_arch"
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported OS: $OS_TYPE"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Install a cask (macOS only)
|
||||
install_cask() {
|
||||
local cask="$1"
|
||||
|
||||
if ! is_macos; then
|
||||
log_warn "Cask installation only supported on macOS"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Installing cask: $cask"
|
||||
|
||||
if ! command_exists brew; then
|
||||
log_error "Homebrew not installed. Run system/macos-setup.sh first"
|
||||
return 1
|
||||
fi
|
||||
|
||||
brew install --cask "$cask"
|
||||
}
|
||||
|
||||
# Install from AUR (Arch only)
|
||||
install_aur() {
|
||||
local package="$1"
|
||||
|
||||
if ! is_arch; then
|
||||
log_warn "AUR installation only supported on Arch Linux"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Installing AUR package: $package"
|
||||
|
||||
# Check for yay first, then paru
|
||||
if command_exists yay; then
|
||||
yay -S --noconfirm --needed "$package"
|
||||
elif command_exists paru; then
|
||||
paru -S --noconfirm --needed "$package"
|
||||
else
|
||||
log_error "No AUR helper found. Install yay or paru first"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Install cargo package
|
||||
install_cargo() {
|
||||
local package="$1"
|
||||
|
||||
if ! command_exists cargo; then
|
||||
log_info "Installing Rust toolchain"
|
||||
install_package rustup rust cargo
|
||||
|
||||
if is_debian || is_arch; then
|
||||
rustup default stable
|
||||
fi
|
||||
fi
|
||||
|
||||
log_info "Installing cargo package: $package"
|
||||
cargo install "$package"
|
||||
}
|
||||
|
||||
# Install Python package with pip
|
||||
install_pip() {
|
||||
local package="$1"
|
||||
|
||||
if ! command_exists pip3; then
|
||||
log_info "Installing pip"
|
||||
install_package python3-pip python3-pip python-pip
|
||||
fi
|
||||
|
||||
log_info "Installing pip package: $package"
|
||||
pip3 install --user "$package"
|
||||
}
|
||||
|
||||
# Install npm package globally
|
||||
install_npm() {
|
||||
local package="$1"
|
||||
|
||||
if ! command_exists npm; then
|
||||
log_error "npm not installed. Install Node.js first"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Installing npm package: $package"
|
||||
npm install -g "$package"
|
||||
}
|
||||
|
||||
# Check if package is installed
|
||||
package_installed() {
|
||||
local package="$1"
|
||||
|
||||
case "$OS_TYPE" in
|
||||
macos)
|
||||
brew list "$package" >/dev/null 2>&1
|
||||
;;
|
||||
debian)
|
||||
dpkg -l "$package" 2>/dev/null | grep -q "^ii"
|
||||
;;
|
||||
arch)
|
||||
pacman -Q "$package" >/dev/null 2>&1
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Ensure Homebrew is installed (macOS only)
|
||||
ensure_homebrew() {
|
||||
if ! is_macos; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command_exists brew; then
|
||||
log_success "Homebrew already installed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Installing Homebrew"
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
|
||||
# Add Homebrew to PATH for Apple Silicon Macs
|
||||
if [ -f "/opt/homebrew/bin/brew" ]; then
|
||||
eval "$(/opt/homebrew/bin/brew shellenv)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Ensure AUR helper is installed (Arch only)
|
||||
ensure_aur_helper() {
|
||||
if ! is_arch; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command_exists yay || command_exists paru; then
|
||||
log_success "AUR helper already installed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Installing yay AUR helper"
|
||||
|
||||
# Install dependencies
|
||||
maybe_sudo pacman -S --noconfirm --needed git base-devel
|
||||
|
||||
# Clone and build yay
|
||||
local temp_dir=$(mktemp -d)
|
||||
git clone https://aur.archlinux.org/yay.git "$temp_dir/yay"
|
||||
cd "$temp_dir/yay"
|
||||
makepkg -si --noconfirm
|
||||
cd -
|
||||
rm -rf "$temp_dir"
|
||||
|
||||
log_success "yay installed"
|
||||
}
|
||||
138
provision
Executable file
138
provision
Executable file
@@ -0,0 +1,138 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/lib/common.sh"
|
||||
|
||||
usage() {
|
||||
cat << 'EOF'
|
||||
Usage: provision [OPTIONS]
|
||||
|
||||
Provision macOS or Linux desktop computers.
|
||||
|
||||
OPTIONS:
|
||||
-h, --help Show this help
|
||||
-s, --skip-go Skip Go installation
|
||||
-p, --skip-p9 Skip Plan9 installation
|
||||
-a, --skip-apps Skip GUI applications
|
||||
|
||||
EXAMPLES:
|
||||
provision # Full provision
|
||||
provision --skip-go # Skip Go
|
||||
provision --skip-p9 # Skip Plan9
|
||||
provision --skip-apps # Skip apps (VSCode, 1Password, etc.)
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
SKIP_GO=false
|
||||
SKIP_P9=false
|
||||
SKIP_APPS=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
-s|--skip-go)
|
||||
SKIP_GO=true
|
||||
shift
|
||||
;;
|
||||
-p|--skip-p9)
|
||||
SKIP_P9=true
|
||||
shift
|
||||
;;
|
||||
-a|--skip-apps)
|
||||
SKIP_APPS=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown option: $1"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
log_info "Starting provision for $OS_TYPE"
|
||||
echo ""
|
||||
|
||||
# System setup
|
||||
log_info "=== System Setup ==="
|
||||
source "$SCRIPT_DIR/lib/package.sh"
|
||||
|
||||
case "$OS_TYPE" in
|
||||
macos)
|
||||
# Install Xcode Command Line Tools
|
||||
if ! xcode-select -p >/dev/null 2>&1; then
|
||||
log_info "Installing Xcode Command Line Tools"
|
||||
xcode-select --install
|
||||
log_warn "Please complete Xcode CLI tools installation and re-run this script"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Install Homebrew
|
||||
ensure_homebrew
|
||||
brew update
|
||||
;;
|
||||
|
||||
debian)
|
||||
update_package_cache
|
||||
maybe_sudo apt-get upgrade -y
|
||||
maybe_sudo apt-get install -y build-essential curl wget git
|
||||
;;
|
||||
|
||||
arch)
|
||||
update_package_cache
|
||||
maybe_sudo pacman -Syu --noconfirm
|
||||
maybe_sudo pacman -S --noconfirm --needed base-devel git curl wget
|
||||
ensure_aur_helper
|
||||
;;
|
||||
|
||||
*)
|
||||
log_error "Unsupported OS: $OS_TYPE"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "System setup complete"
|
||||
echo ""
|
||||
|
||||
# Install packages
|
||||
log_info "=== Installing Packages ==="
|
||||
"$SCRIPT_DIR/scripts/packages.sh"
|
||||
echo ""
|
||||
|
||||
# Install apps
|
||||
if [ "$SKIP_APPS" = false ]; then
|
||||
log_info "=== Installing Applications ==="
|
||||
"$SCRIPT_DIR/scripts/apps.sh"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Install Go
|
||||
if [ "$SKIP_GO" = false ]; then
|
||||
log_info "=== Installing Go ==="
|
||||
"$SCRIPT_DIR/scripts/golang.sh"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Install Plan9
|
||||
if [ "$SKIP_P9" = false ]; then
|
||||
log_info "=== Installing Plan9 ==="
|
||||
"$SCRIPT_DIR/scripts/plan9port.sh"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Link config files
|
||||
log_info "=== Linking Config Files ==="
|
||||
"$SCRIPT_DIR/config/link-dotfiles.sh"
|
||||
echo ""
|
||||
|
||||
log_success "Provision complete!"
|
||||
echo ""
|
||||
log_info "Next steps:"
|
||||
log_info " 1. Restart your shell: exec \$SHELL"
|
||||
log_info " 2. Edit ~/.gitconfig to set your name and email"
|
||||
log_info " 3. In tmux, press Ctrl+a then I to install plugins"
|
||||
134
scripts/apps.sh
Executable file
134
scripts/apps.sh
Executable file
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../lib/common.sh"
|
||||
source "$SCRIPT_DIR/../lib/package.sh"
|
||||
|
||||
log_info "Installing applications"
|
||||
|
||||
# VSCodium
|
||||
if command_exists codium || command_exists code; then
|
||||
log_success "VSCodium/VSCode already installed"
|
||||
else
|
||||
log_info "Installing VSCodium"
|
||||
case "$OS_TYPE" in
|
||||
macos)
|
||||
install_cask vscodium
|
||||
;;
|
||||
debian)
|
||||
wget -qO - https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg \
|
||||
| gpg --dearmor \
|
||||
| maybe_sudo dd of=/usr/share/keyrings/vscodium-archive-keyring.gpg
|
||||
echo 'deb [ signed-by=/usr/share/keyrings/vscodium-archive-keyring.gpg ] https://download.vscodium.com/debs vscodium main' \
|
||||
| maybe_sudo tee /etc/apt/sources.list.d/vscodium.list
|
||||
update_package_cache
|
||||
install_package codium
|
||||
;;
|
||||
arch)
|
||||
install_aur vscodium-bin
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# 1Password
|
||||
if command_exists 1password || [ -d "/Applications/1Password.app" ] 2>/dev/null; then
|
||||
log_success "1Password already installed"
|
||||
else
|
||||
log_info "Installing 1Password"
|
||||
case "$OS_TYPE" in
|
||||
macos)
|
||||
install_cask 1password
|
||||
;;
|
||||
debian)
|
||||
curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
|
||||
maybe_sudo gpg --dearmor --output /usr/share/keyrings/1password-archive-keyring.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/$(dpkg --print-architecture) stable main" | \
|
||||
maybe_sudo tee /etc/apt/sources.list.d/1password.list
|
||||
maybe_sudo mkdir -p /etc/debsig/policies/AC2D62742012EA22/
|
||||
curl -sS https://downloads.1password.com/linux/debian/debsig/1password.pol | \
|
||||
maybe_sudo tee /etc/debsig/policies/AC2D62742012EA22/1password.pol
|
||||
maybe_sudo mkdir -p /usr/share/debsig/keyrings/AC2D62742012EA22
|
||||
curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
|
||||
maybe_sudo gpg --dearmor --output /usr/share/debsig/keyrings/AC2D62742012EA22/debsig.gpg
|
||||
update_package_cache
|
||||
install_package 1password
|
||||
;;
|
||||
arch)
|
||||
install_aur 1password
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Obsidian
|
||||
if command_exists obsidian || [ -d "/Applications/Obsidian.app" ] 2>/dev/null; then
|
||||
log_success "Obsidian already installed"
|
||||
else
|
||||
log_info "Installing Obsidian"
|
||||
case "$OS_TYPE" in
|
||||
macos)
|
||||
install_cask obsidian
|
||||
;;
|
||||
debian)
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
cd "$TEMP_DIR"
|
||||
wget -q "https://github.com/obsidianmd/obsidian-releases/releases/download/v1.5.3/obsidian_1.5.3_amd64.deb"
|
||||
maybe_sudo dpkg -i obsidian_*.deb
|
||||
maybe_sudo apt-get install -f -y
|
||||
cd -
|
||||
rm -rf "$TEMP_DIR"
|
||||
;;
|
||||
arch)
|
||||
install_aur obsidian
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Google Chrome
|
||||
if command_exists google-chrome || command_exists google-chrome-stable || [ -d "/Applications/Google Chrome.app" ] 2>/dev/null; then
|
||||
log_success "Google Chrome already installed"
|
||||
else
|
||||
log_info "Installing Google Chrome"
|
||||
case "$OS_TYPE" in
|
||||
macos)
|
||||
install_cask google-chrome
|
||||
;;
|
||||
debian)
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
cd "$TEMP_DIR"
|
||||
wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
||||
maybe_sudo dpkg -i google-chrome-stable_current_amd64.deb
|
||||
maybe_sudo apt-get install -f -y
|
||||
cd -
|
||||
rm -rf "$TEMP_DIR"
|
||||
;;
|
||||
arch)
|
||||
install_aur google-chrome
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Todoist
|
||||
if command_exists todoist || [ -d "/Applications/Todoist.app" ] 2>/dev/null; then
|
||||
log_success "Todoist already installed"
|
||||
else
|
||||
log_info "Installing Todoist"
|
||||
case "$OS_TYPE" in
|
||||
macos)
|
||||
install_cask todoist
|
||||
;;
|
||||
debian)
|
||||
# Install via snap
|
||||
if ! command_exists snap; then
|
||||
log_info "Installing snapd"
|
||||
maybe_sudo apt-get install -y snapd
|
||||
fi
|
||||
maybe_sudo snap install todoist
|
||||
;;
|
||||
arch)
|
||||
install_aur todoist-appimage
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
log_success "Applications installed"
|
||||
66
scripts/golang.sh
Executable file
66
scripts/golang.sh
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../lib/common.sh"
|
||||
|
||||
GO_VERSION="1.23.3"
|
||||
GO_INSTALL_DIR="/usr/local/go"
|
||||
|
||||
log_info "Installing Go ${GO_VERSION}"
|
||||
|
||||
if [ -d "$GO_INSTALL_DIR" ] && [ -f "$GO_INSTALL_DIR/bin/go" ]; then
|
||||
CURRENT_VERSION=$($GO_INSTALL_DIR/bin/go version | awk '{print $3}' | sed 's/go//')
|
||||
if [ "$CURRENT_VERSION" = "$GO_VERSION" ]; then
|
||||
log_success "Go ${GO_VERSION} already installed"
|
||||
exit 0
|
||||
else
|
||||
log_info "Upgrading Go from ${CURRENT_VERSION} to ${GO_VERSION}"
|
||||
maybe_sudo rm -rf "$GO_INSTALL_DIR"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Detect architecture
|
||||
ARCH=$(uname -m)
|
||||
case "$ARCH" in
|
||||
x86_64)
|
||||
GO_ARCH="amd64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
GO_ARCH="arm64"
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported architecture: $ARCH"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Detect OS
|
||||
if is_macos; then
|
||||
GO_OS="darwin"
|
||||
else
|
||||
GO_OS="linux"
|
||||
fi
|
||||
|
||||
GO_TARBALL="go${GO_VERSION}.${GO_OS}-${GO_ARCH}.tar.gz"
|
||||
GO_URL="https://go.dev/dl/${GO_TARBALL}"
|
||||
|
||||
log_info "Downloading Go from ${GO_URL}"
|
||||
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
cd "$TEMP_DIR"
|
||||
|
||||
if ! curl -fsSL -o "$GO_TARBALL" "$GO_URL"; then
|
||||
log_error "Failed to download Go"
|
||||
rm -rf "$TEMP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Extracting Go to ${GO_INSTALL_DIR}"
|
||||
maybe_sudo tar -C /usr/local -xzf "$GO_TARBALL"
|
||||
|
||||
cd -
|
||||
rm -rf "$TEMP_DIR"
|
||||
|
||||
log_success "Go ${GO_VERSION} installed to ${GO_INSTALL_DIR}"
|
||||
log_info "Add to PATH: export PATH=\$PATH:/usr/local/go/bin"
|
||||
108
scripts/packages.sh
Executable file
108
scripts/packages.sh
Executable file
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../lib/common.sh"
|
||||
source "$SCRIPT_DIR/../lib/package.sh"
|
||||
|
||||
log_info "Installing packages"
|
||||
|
||||
# Essential packages
|
||||
PACKAGES=(
|
||||
"git"
|
||||
"curl"
|
||||
"wget"
|
||||
"tmux"
|
||||
"jq"
|
||||
"fzf"
|
||||
"ripgrep"
|
||||
)
|
||||
|
||||
# Modern CLI tools
|
||||
MODERN_TOOLS=(
|
||||
"starship"
|
||||
"zoxide"
|
||||
"eza"
|
||||
"fd"
|
||||
"gh"
|
||||
)
|
||||
|
||||
# Install essential packages
|
||||
for pkg in "${PACKAGES[@]}"; do
|
||||
if command_exists "$pkg" || command_exists "${pkg}find" 2>/dev/null; then
|
||||
log_success "$pkg already installed"
|
||||
else
|
||||
log_info "Installing $pkg"
|
||||
case "$pkg" in
|
||||
fd)
|
||||
install_package fd fd-find fd
|
||||
;;
|
||||
*)
|
||||
install_package "$pkg"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
|
||||
# Install modern tools
|
||||
for tool in "${MODERN_TOOLS[@]}"; do
|
||||
if command_exists "$tool"; then
|
||||
log_success "$tool already installed"
|
||||
continue
|
||||
fi
|
||||
|
||||
log_info "Installing $tool"
|
||||
|
||||
case "$tool" in
|
||||
starship)
|
||||
if is_debian; then
|
||||
curl -sS https://starship.rs/install.sh | sh -s -- -y
|
||||
else
|
||||
install_package starship
|
||||
fi
|
||||
;;
|
||||
zoxide)
|
||||
if is_debian && ! package_installed zoxide; then
|
||||
install_cargo zoxide
|
||||
else
|
||||
install_package zoxide
|
||||
fi
|
||||
;;
|
||||
eza)
|
||||
if is_debian && ! package_installed eza; then
|
||||
if command_exists exa; then
|
||||
log_success "exa (predecessor) already installed"
|
||||
else
|
||||
install_cargo eza
|
||||
fi
|
||||
else
|
||||
install_package eza
|
||||
fi
|
||||
;;
|
||||
gh)
|
||||
if is_debian && ! package_installed gh; then
|
||||
maybe_sudo mkdir -p -m 755 /etc/apt/keyrings
|
||||
wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | maybe_sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | maybe_sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
|
||||
update_package_cache
|
||||
fi
|
||||
install_package gh gh github-cli
|
||||
;;
|
||||
*)
|
||||
install_package "$tool"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Install TPM (Tmux Plugin Manager)
|
||||
TPM_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/tmux/plugins/tpm"
|
||||
if [ ! -d "$TPM_DIR" ]; then
|
||||
log_info "Installing TPM (Tmux Plugin Manager)"
|
||||
ensure_dir "$(dirname "$TPM_DIR")"
|
||||
git clone https://github.com/tmux-plugins/tpm "$TPM_DIR"
|
||||
log_success "TPM installed"
|
||||
else
|
||||
log_success "TPM already installed"
|
||||
fi
|
||||
|
||||
log_success "All packages installed"
|
||||
60
scripts/plan9port.sh
Executable file
60
scripts/plan9port.sh
Executable file
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/../lib/common.sh"
|
||||
|
||||
PLAN9_INSTALL_DIR="/usr/local/plan9"
|
||||
|
||||
log_info "Installing plan9port"
|
||||
|
||||
if [ -d "$PLAN9_INSTALL_DIR" ] && [ -f "$PLAN9_INSTALL_DIR/bin/9" ]; then
|
||||
log_success "plan9port already installed at ${PLAN9_INSTALL_DIR}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Install build dependencies
|
||||
log_info "Installing build dependencies"
|
||||
if is_macos; then
|
||||
# macOS needs Xcode Command Line Tools
|
||||
if ! xcode-select -p >/dev/null 2>&1; then
|
||||
log_error "Xcode Command Line Tools required. Run: xcode-select --install"
|
||||
exit 1
|
||||
fi
|
||||
elif is_debian; then
|
||||
maybe_sudo apt-get install -y build-essential libx11-dev libxt-dev libxext-dev libfontconfig1-dev
|
||||
elif is_arch; then
|
||||
maybe_sudo pacman -S --noconfirm --needed base-devel xorg-server-devel fontconfig
|
||||
fi
|
||||
|
||||
log_info "Cloning plan9port repository"
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
cd "$TEMP_DIR"
|
||||
|
||||
if ! git clone https://github.com/9fans/plan9port.git plan9; then
|
||||
log_error "Failed to clone plan9port"
|
||||
rm -rf "$TEMP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd plan9
|
||||
|
||||
log_info "Building plan9port (this may take a while)"
|
||||
if ! ./INSTALL; then
|
||||
log_error "Failed to build plan9port"
|
||||
cd -
|
||||
rm -rf "$TEMP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Installing to ${PLAN9_INSTALL_DIR}"
|
||||
cd ..
|
||||
maybe_sudo mv plan9 "$PLAN9_INSTALL_DIR"
|
||||
|
||||
cd -
|
||||
rm -rf "$TEMP_DIR"
|
||||
|
||||
log_success "plan9port installed to ${PLAN9_INSTALL_DIR}"
|
||||
log_info "Add to environment:"
|
||||
log_info " export PLAN9=${PLAN9_INSTALL_DIR}"
|
||||
log_info " export PATH=\$PATH:\$PLAN9/bin"
|
||||
Reference in New Issue
Block a user