#!/bin/bash # dot - a (mostly) one script dotfiles manager # # Copyright 2026 Edward Delaporte V # Licensed under AGPLv3 and later. # # Features # symlinks - any file in $HOME/dotfiles/files may be symlinked # # dot setup # install the necessary tools to $HOME/envs/dot # # dot list # list available roles # # dot check # check setup vs expected # # dot add ROLE # add ROLE to localhost # # dot apply # apply all added ROLES # set -v ENVS="$HOME/envs" ANSIBLE="$ENVS/ansible/bin/ansible-playbook" TASKFILE="$HOME/dot.$HOSTNAME.yaml" read -d '' EMPTY_TASKFILE << EOF --- - name: Set up dotfiles on $HOSTNAME gather_facts: no hosts: localhost connection: local tasks: - name: Do nothing ansible.builtin.shell: echo "Nothing to do." EOF if [ "$1" == "setup" ]; then if [[ ! -f "$ANSIBLE" ]]; then mkdir -p "$ENVS" echo "Setting up Ansible in ~/envs/ansible" cd $HOME/envs; python3 -m venv ansible $HOME/envs/ansible/bin/pip install ansible jinja2 fi if [[ -f "$ANSIBLE" ]]; then echo "[ ok ]: Ansible setup at $ANSIBLE" fi if [[ ! -f "$TASKFILE" ]]; then echo "Creating $TASKFILE" echo "$EMPTY_TASKFILE" >> $TASKFILE fi if [[ -f "$TASKFILE" ]]; then echo "[ ok ]: dot config at $TASKFILE" fi fi if [ "$1" == "reset" ]; then read -n1 -p "Reset $TASKFILE? [y,N]" input if [[ ! $input == "Y" && ! $input == "y" ]]; then echo "Aborted by user" exit 1 fi echo "$EMPTY_TASKFILE" > $TASKFILE fi if [ "$1" == "check" ]; then $ANSIBLE $TASKFILE --check --diff fi if [ "$1" == "list" ]; then echo "May symlink:" cd $HOME/dotfiles/files ls -p | grep -v / fi if [ "$1" == "link" ]; then if [ ! -n "$2" ]; then echo "May symlink:" cd $HOME/dotfiles/files ls -p | grep -v / fi read -d '' LINK_FILE << EOF --- tasks: - name: Create a symbolic link ansible.builtin.file: src: /file/to/link/to dest: /path/to/symlink owner: foo group: foo state: link EOF fi