--- - name: Discover dotfile packages ansible.builtin.find: paths: "{{ role_path }}" file_type: directory depth: 1 excludes: ['tasks', 'templates', 'files', 'vars', 'defaults', 'meta', 'handlers'] register: dotfiles_packages delegate_to: localhost - name: Build complete file list ansible.builtin.set_fact: dotfiles_files: "{{ dotfiles_files | default([]) + lookup('community.general.filetree', item.path, wantlist=True) | selectattr('state', 'equalto', 'file') | list }}" loop: "{{ dotfiles_packages.files }}" delegate_to: localhost - name: Ensure dotfile directories exist ansible.builtin.file: path: "{{ ansible_facts.env.HOME }}/{{ item.path | dirname }}" state: directory mode: "0755" loop: "{{ dotfiles_files }}" - name: Deploy dotfiles (local with symlinks) ansible.builtin.file: src: "{{ item.src }}" dest: "{{ ansible_facts.env.HOME }}/{{ item.path }}" state: link force: true loop: "{{ dotfiles_files | rejectattr('path', 'match', '.*\\.j2$') | list }}" when: ansible_connection == 'local' - name: Deploy dotfiles (remote with copy) ansible.builtin.copy: src: "{{ item.src }}" dest: "{{ ansible_facts.env.HOME }}/{{ item.path }}" mode: preserve loop: "{{ dotfiles_files | rejectattr('path', 'match', '.*\\.j2$') | list }}" when: ansible_connection != 'local' - name: Render dotfile templates ansible.builtin.template: src: "{{ item.src }}" dest: "{{ ansible_facts.env.HOME }}/{{ item.path | replace('.j2', '') }}" mode: preserve loop: "{{ dotfiles_files | selectattr('path', 'match', '.*\\.j2$') | list }}"