refactor: use ansible

This commit is contained in:
Marc 2024-05-20 15:20:58 -04:00
parent 7a71ab38f4
commit 67320b4e5d
Signed by: marc
GPG key ID: 048E042F22B5DC79
10 changed files with 70 additions and 342 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.venv

1
.python-version Normal file
View file

@ -0,0 +1 @@
3.12.3

View file

@ -4,38 +4,7 @@ Environment tweaks for everyday happiness.
## Setup ## Setup
```bash Use the `bootstrap.sh` script to set up a virtual environment with Ansible and its dependencies, then `setup.sh`!
git clone git@github.com:mcataford/env.git <path-of-your-choosing> | ./bootstrap.sh
```
The setup script will look for pre-existing managed blocks and will not update the file if one is found.
### Updating existing setups
Since the managed blocks only `source` the files in this repository, pulling in updates from remote should bring in any
new tweaks you want to apply. If changes are made to the managed blocks, you will need to first remove them from where
they live and rerun the setup script.
## Profiles
A profile must be provided via `$ENV_PROFILE`. This can be used by steps to determine variants of a file to copy over.
Files with profile specificity should be named `file.<profile>.<extension>`.
## Structure
The package is structured as such:
```
env/
bootstrap.sh # Adds bootstrap block to your shell's config file.
files/
shell_extras # Functions, aliases and exports for the shell.
extras.vim # Common config for neovim.
git_config # Configuration commands for git
... Other configuration templates
```
Adding code to `shell_extras` will add code that gets executed on shell-start.
## Contributing ## Contributing

View file

@ -1,299 +1,9 @@
#!/bin/bash #!/usr/bin/bash
########################################################### VENV=env.venv
#
# Marc's environment bootstrap script.
#
# Table of contents
#
# 1. Helpers and utilities
# These functions are used by individual bootstrap
# steps and are reused all over.
# 2. Steps
# Functions implementing a specific action in the
# bootstrap process.
# 3. Bootstrap sequence and callsite
# Where the magic happens.
# This is where the ordered sequence of steps
# is defined and run.
#
###########################################################
CURRENT_TIME=$(date +%T) python -m venv "$VENV"
########################################################### . "$VENV/bin/activate"
#
# 1. Helpers and utilities
#
###########################################################
STEP_COUNT=0 pip install -U pip ansible~=9.5
SUBSTEP_COUNT=0
# Pretty-print step headers.
pre_step() {
STEP_COUNT=$((STEP_COUNT + 1))
SUBSTEP_COUNT=0
echo -e "\e[1m[$STEP_COUNT/$TOTAL_STEPS] <====== $1 =======>\e[0m"
}
# Pretty-prints substep headers.
pre_substep() {
SUBSTEP_COUNT=$((SUBSTEP_COUNT + 1))
echo -e "\e[1m[$STEP_COUNT.$SUBSTEP_COUNT] <====== $1 =======>\e[0m"
}
# Copies a file from $1 to $2.
#
# If $2 exists, checks if $1 == $2 and asks what to do.
# From there, the user providing "O" will overwrite (proceed with copy),
# "S" will skip the file and leave the destination as-is, and anyting else
# will skip the copy altogether (i.e. "S").
copy_file() {
source_path=$1
dest_path=$2
if [ ! -e "$dest_path" ]; then
cp "$source_path" "$dest_path"
echo "Copied $source_path > $dest_path"
return 0
fi
difference=$(diff "$dest_path" "$source_path")
if [ -z "$difference" ]; then
echo "$dest_path already exists, but is the same as $source_path - skipping."
return 0
fi
echo "Differences detected between $source_path and $dest_path:"
diff --color "$dest_path" "$source_path"
read -p "$dest_path already exists. What should be done? [O:overwrite,S:skip,B:save backup and copy] " -r action
if [[ $action == "O" ]]; then
cp "$source_path" "$dest_path"
echo "Overwrote $source_path > $dest_path"
return 0
fi
if [[ $action == "S" ]]; then
echo "Skipped and left $dest_path as is."
return 0
fi
if [[ $action == "B" ]]; then
cp "$dest_path" "$dest_path".old
echo "Backed up $dest_path up to $dest_path.old"
cp "$source_path" "$dest_path"
echo "Overwrote $source_path > $dest_path"
return 0
fi
echo "Unrecognized action, doing nothing."
}
##########################################################
#
# 2. Steps
#
##########################################################
# Ensures that all existing Apt packages are up-to-date.
ensure_apt_up_to_date() {
pre_step "Ensuring apt packages are up-to-date"
if [ -z "$(apt --version 2> /dev/null)" ]; then
echo -e "\e[33mApt not installed, skipping updates.\e[0m"
else
echo -e "\e[1mEnsuring system packages are up-to-date...\e[0m"
sudo apt update && sudo apt upgrade -y --autoremove
echo -e "\e[1;32mSystem packages up-to-date.\e[0m"
fi
}
# Installs packages as specified in apt.txt
ensure_apt_dependencies() {
pre_step "Installing extra packages"
if [ -z "$(apt --version 2> /dev/null)" ]; then
echo -e "\e[33mApt not installed, skipping packages.\e[0m"
else
echo -e "\e[1mInstalling packages...\e[0m"
sudo apt install "$(cat ./files/apt.txt)" -y --autoremove
echo -e "\e[1;32mSystem packages installed.\e[0m"
fi
}
# Installs the rustup toolchain if not installed.
# If installed, the toolchain is updated.
install_rust() {
pre_step "Install and configure Rust toolchain"
if [ -z "$(rustup --version 2> /dev/null)" ]; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
else
rustup update
fi
}
install_omz() {
pre_step "Installs Oh My ZSH"
curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh | bash
}
# Installs the Starship prompt and adds an initialization
# command to the shell configuration file.
#
# Requires: install_rust
install_and_configure_starship() {
pre_step "Install and configure Starship"
pre_substep "Install Starship via cargo"
cargo install starship --locked
pre_substep "Add initialization command to shell configuration"
if [ -z "$(rg "starship init zsh" ~/.zshrc)" ]; then
printf "#Initialize Starship prompt\neval \"\$(starship init zsh)\"" >> ~/.zshrc
fi
pre_substep "Copy configuration in configuration directory"
copy_file ./files/starship.toml ~/.config/starship.toml
}
install_nvm() {
pre_step "Installing nvm to manage node version"
pre_substep "Installing NVM from remote"
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
pre_substep "Ensuring that NVM can be run right away"
# Ensuring that nvm is usable right away without restarting the shell
export NVM_DIR="$HOME/.nvm"
# shellcheck disable=SC1091
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
# shellcheck disable=SC1091
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
}
install_gh_plugins() {
pre_step "Installing gh cli plugins"
gh extension install nektos/gh-act
gh extension install dlvhdr/gh-dash
copy_file ./files/gh-dash_config."$ENV_PROFILE".yml ~/.config/gh-dash/config.yml
gh extension upgrade --all
}
install_pyenv() {
pre_step "Install and configure pyenv"
curl https://pyenv.run | bash
}
# Injects a managed block in the shell configuration.
inject_shell_configuration() {
pre_step "Injecting managed block in shell configuration"
BLOCK_DELIMITER_PATTERN="mcataford/env"
WORKING_PATH=$(git rev-parse --show-toplevel)
SHELL_CONFIG_PATH="$HOME/.zshrc"
echo "Setting up shell configuration extras..."
if ! grep -q "$BLOCK_DELIMITER_PATTERN" < "$SHELL_CONFIG_PATH"; then
TEMPORARY_PATH=/tmp/init_vim_$CURRENT_TIME
copy_file "$SHELL_CONFIG_PATH" "$TEMPORARY_PATH"
printf "# %s:start\nsource %s/files/shell_extras\n# %s:end" \
"$BLOCK_DELIMITER_PATTERN" "$WORKING_PATH" "$BLOCK_DELIMITER_PATTERN" \
>> "$TEMPORARY_PATH"
copy_file "$TEMPORARY_PATH" "$SHELL_CONFIG_PATH"
echo "✅ Added managed block to $SHELL_CONFIG_PATH"
rm "$TEMPORARY_PATH"
else
echo "No changes to apply!"
fi
}
# Injects a managed block in the vim configuration
inject_vim_configuration() {
pre_step "Inject managed block in vim configuration"
EDITOR_CONFIG=$HOME/.config/nvim
EDITOR_CONFIG_FILE=$EDITOR_CONFIG/init.vim
WORKING_PATH=$(git rev-parse --show-toplevel)
if [[ -f $EDITOR_CONFIG_FILE ]]; then
echo "Setting up NVIM configuration extras..."
if ! grep -q "$BLOCK_DELIMITER_PATTERN" < "$EDITOR_CONFIG_FILE"; then
TEMPORARY_PATH=/tmp/init_vim_$CURRENT_TIME
printf "\" %s:start\nsource %s/files/extras.vim\n\" %s:end\n\n" \
"$BLOCK_DELIMITER_PATTERN" "$WORKING_PATH" "$BLOCK_DELIMITER_PATTERN" \
>> "$TEMPORARY_PATH"
cat "$EDITOR_CONFIG_FILE" >> "$TEMPORARY_PATH"
copy_file "$EDITOR_CONFIG_FILE" "$EDITOR_CONFIG_FILE".old
copy_file "$TEMPORARY_PATH" "$EDITOR_CONFIG_FILE"
echo "✅ Added managed block to $EDITOR_CONFIG_FILE"
rm "$TEMPORARY_PATH"
else
echo "No changes to apply!"
fi
fi
echo "Setting up git configuration..."
source "$WORKING_PATH"/files/git_config
echo "✅ Set up git configuration, see $WORKING_PATH/files/git_config for details!"
}
###########################################################
#
# 3. Bootstrap sequence
#
###########################################################
bootstrap_home() {
TOTAL_STEPS=10
# System updates
ensure_apt_up_to_date
ensure_apt_dependencies
# Development tooling and SDKs
install_rust
install_pyenv
install_nvm
install_gh_plugins
# Shell & prompt setup
install_omz
install_and_configure_starship
inject_shell_configuration
inject_vim_configuration
}
bootstrap_work() {
TOTAL_STEPS=4
install_gh_plugins
install_omz
install_and_configure_starship
inject_shell_configuration
inject_vim_configuration
}
if [[ $ENV_PROFILE == "home" ]]; then
bootstrap_home
elif [[ $ENV_PROFILE == "work" ]]; then
bootstrap_work
else
echo "Unknown \$ENV_PROFILE. :shrug:"
fi

View file

@ -1,6 +0,0 @@
zsh
tmux
postgresql
postgresql-contrib
gh
shellcheck

View file

@ -1,7 +0,0 @@
#!/bin/bash
# Always sign commits.
git config --global commit.gpgsign true
# Prune stale refs on fetch.
git config --global fetch.prune true

View file

@ -1,5 +1,3 @@
#!/usr/bin/bash
################ ################
# ALIASES # # ALIASES #
################ ################

59
playbook.yml Normal file
View file

@ -0,0 +1,59 @@
---
- name: Local environment
hosts: localhost
tasks:
- name: Ensure system up-to-date
become: yes
apt:
update-cache: yes
upgrade: yes
- name: Install terminal & shell
apt:
pkg:
- zsh
- tmux
- name: Install CLI tooling
apt:
pkg:
- shellcheck
- gh
- name: Install gh CLI extensions (gh-dash)
command: gh extension install dlvhdr/gh-dash
- name: Install DB-related tooling
apt:
pkg:
- postgresql
- postgresql-contrib
- name: Add zsh managed block
blockinfile:
path: "{{ lookup('ansible.builtin.env', 'HOME') }}/.zshrc"
marker: "# Marc's env managed block - {mark}"
block: "{{ lookup('ansible.builtin.file', 'files/shell_extras') }}"
- name: Add nvim managed block
blockinfile:
path: "{{ lookup('ansible.builtin.env', 'HOME') }}/.config/nvim/init.vim"
marker: "\" Marc's env managed block - {mark}"
block: "{{ lookup('ansible.builtin.file', 'files/extras.vim') }}"
- name: Add starship managed block
blockinfile:
path: "{{ lookup('ansible.builtin.env', 'HOME') }}/.config/starship.toml"
marker: "# Marc's env managed block - {mark}"
block: "{{ lookup('ansible.builtin.file', 'files/starship.toml') }}"
- name: Ensure gh-dash config directory exists
file:
path: "{{ lookup('ansible.builtin.env', 'HOME') }}/.config/gh-dash"
state: directory
- name: Ensure gh-dash config exists
file:
path: "{{ lookup('ansible.builtin.env', 'HOME') }}/.config/gh-dash/config.yml"
state: touch
- name: Add gh-dash configuration managed block
blockinfile:
path: "{{ lookup('ansible.builtin.env', 'HOME') }}/.config/gh-dash/config.yml"
marker: "# Marc's env managed block - {mark}"
block: "{{ lookup('ansible.builtin.file', 'files/gh-dash.yml') }}"
- name: Configure git
shell: |
git config --global commit.gpgsign true
git config --global fetch.prune true

3
setup.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/bash
ansible-playbook playbook.yml -v --ask-become-pass