Files
dotfiles/todo_ansible.md
2025-08-11 21:47:44 +02:00

5.3 KiB

Here's how such a role-based Ansible dotfiles configuration would work:

Directory Structure

dotfiles/
├── playbook.yml                 # Main playbook
├── group_vars/
│   └── all.yml                 # Your config with default_roles
├── roles/
│   ├── system/
│   │   ├── tasks/main.yml
│   │   ├── vars/main.yml
│   │   └── files/
│   ├── git/
│   │   ├── tasks/main.yml
│   │   ├── templates/
│   │   │   └── .gitconfig.j2
│   │   └── vars/main.yml
│   ├── neovim/
│   │   ├── tasks/main.yml
│   │   └── files/
│   └── zsh/
│       ├── tasks/main.yml
│       ├── files/
│       │   └── .zshrc
│       └── vars/main.yml
└── inventory

Main Configuration (group_vars/all.yml)

# Your system configuration
default_roles:
  - system
  - git
  - neovim
  - zsh
  - docker

# Global variables
dotfiles_dir: "{{ ansible_env.HOME }}/dotfiles"
config_dir: "{{ ansible_env.HOME }}/.config"

# Git configuration
git_user_name: "Johannes"
git_user_email: "johannes@example.com"
git_editor: "nvim"

# System packages to install
system_packages:
  - curl
  - wget
  - unzip
  - tree

Main Playbook (playbook.yml)

---
- name: Setup development environment
  hosts: localhost
  connection: local
  become: yes
  become_method: sudo

  pre_tasks:
    - name: Create btrfs snapshot before changes
      shell: |
        sudo btrfs subvolume snapshot / /.snapshots/before-dotfiles-$(date +%Y%m%d-%H%M%S)
      ignore_errors: yes
      tags: [snapshot]

  roles: "{{ default_roles }}"

  post_tasks:
    - name: Summary of installed roles
      debug:
        msg: "Completed setup for: {{ default_roles | join(', ') }}"

Example Roles

System Role (roles/system/tasks/main.yml)

---
- name: Install system packages
  package:
    name: "{{ system_packages }}"
    state: present

- name: Ensure .config directory exists
  file:
    path: "{{ config_dir }}"
    state: directory
    mode: '0755'

- name: Set up shell as default
  user:
    name: "{{ ansible_env.USER }}"
    shell: /usr/bin/zsh
  when: "'zsh' in default_roles"

Git Role (roles/git/tasks/main.yml)

---
- name: Install git
  package:
    name: git
    state: present

- name: Check if custom gitconfig exists
  stat:
    path: "{{ dotfiles_dir }}/git/.gitconfig"
  register: custom_gitconfig

- name: Use custom gitconfig if available
  file:
    src: "{{ dotfiles_dir }}/git/.gitconfig"
    dest: "{{ ansible_env.HOME }}/.gitconfig"
    state: link
    force: yes
  when: custom_gitconfig.stat.exists

- name: Generate gitconfig from template if no custom config
  template:
    src: .gitconfig.j2
    dest: "{{ ansible_env.HOME }}/.gitconfig"
    mode: '0644'
  when: not custom_gitconfig.stat.exists

Git Template (roles/git/templates/.gitconfig.j2)

[user]
    name = {{ git_user_name }}
    email = {{ git_user_email }}

[core]
    editor = {{ git_editor }}
    autocrlf = input

[init]
    defaultBranch = main

[push]
    default = simple

Neovim Role (roles/neovim/tasks/main.yml)

---
- name: Install neovim
  package:
    name: neovim
    state: present

- name: Check for custom neovim config
  stat:
    path: "{{ dotfiles_dir }}/nvim"
  register: nvim_config

- name: Symlink neovim config
  file:
    src: "{{ dotfiles_dir }}/nvim"
    dest: "{{ config_dir }}/nvim"
    state: link
    force: yes
  when: nvim_config.stat.exists

- name: Create basic neovim config if none exists
  copy:
    content: |
      -- Basic Neovim configuration
      vim.opt.number = true
      vim.opt.expandtab = true
      vim.opt.tabstop = 2
      vim.opt.shiftwidth = 2
    dest: "{{ config_dir }}/nvim/init.lua"
    mode: '0644'
  when: not nvim_config.stat.exists

ZSH Role (roles/zsh/tasks/main.yml)

---
- name: Install zsh
  package:
    name: zsh
    state: present

- name: Install oh-my-zsh
  shell: |
    sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" --unattended
  args:
    creates: "{{ ansible_env.HOME }}/.oh-my-zsh"

- name: Check for custom zshrc
  stat:
    path: "{{ dotfiles_dir }}/zsh/.zshrc"
  register: custom_zshrc

- name: Symlink custom zshrc
  file:
    src: "{{ dotfiles_dir }}/zsh/.zshrc"
    dest: "{{ ansible_env.HOME }}/.zshrc"
    state: link
    force: yes
  when: custom_zshrc.stat.exists

Usage

To install everything:

ansible-playbook -i inventory playbook.yml --ask-become-pass

To install only specific roles:

ansible-playbook -i inventory playbook.yml --ask-become-pass --tags "git,neovim"

To override roles temporarily:

ansible-playbook -i inventory playbook.yml --ask-become-pass -e "default_roles=['system','git']"

Benefits of This Approach

  1. Modular: Each tool is a separate role
  2. Configurable: Easy to enable/disable tools in all.yml
  3. Reusable: Roles can be shared across different machines
  4. Flexible: Can override variables per host/group
  5. Fallback configs: Generates basic configs when custom ones don't exist
  6. Scalable: Easy to add new tools without touching existing code

This approach lets you manage your entire development environment as code while keeping it organized and maintainable!