--- - name: Base user configuration tags: [user:base] block: - ansible.builtin.set_fact: user_groups: - libvirt - wheel - wireshark - docker - sudonopw - games - kvm - video - name: Create user group ansible.builtin.group: name: "{{ user.name }}" state: present become: true become_user: root - name: Create user ansible.builtin.user: name: "{{ user.name }}" state: present home: "/home/{{ user.name }}" create_home: true group: "{{ user.name }}" groups: "{{ ['dotfiles'] + user_groups }}" shell: /usr/bin/zsh skeleton: /dev/null become: true become_user: root - name: Create systemd directory ansible.builtin.file: state: directory path: "{{ item }}" owner: "{{ user.name }}" group: "{{ user.name }}" loop: - "/home/{{ user.name }}/.config/" - "/home/{{ user.name }}/.config/systemd/" - "/home/{{ user.name }}/.config/systemd/user/" - name: Configure autologin when: user.autologin|default(true) is sameas True block: - name: Create directory for getty autologin ansible.builtin.file: state: directory path: /etc/systemd/system/getty@tty{{ user.vt }}.service.d owner: root group: root mode: "0755" become: true become_user: root - name: Enable getty autologin ansible.builtin.copy: dest: /etc/systemd/system/getty@tty{{ user.vt }}.service.d/override.conf owner: root group: root mode: "0644" content: | [Service] ExecStart= ExecStart=-/sbin/agetty --autologin {{ user.name }} --noclear %I $TERM become: true become_user: root - name: Configure dotfiles tags: - user:dotfiles block: - name: Load dotfile list ansible.builtin.include_vars: file: dotfiles.yml - name: Get state of empty directories ansible.builtin.stat: path: ~/{{ item.name }} register: empty_dir_stat with_items: "{{ empty_directories }}" check_mode: false loop_control: label: "{{ item.name }}" - name: Remove symlinks ansible.builtin.file: path: "{{ item.stat.path }}" state: absent when: item.stat.exists and item.stat.islnk with_items: "{{ empty_dir_stat.results }}" loop_control: label: "{{ item.item.name }}" - name: Create empty directories for dotfiles ansible.builtin.file: state: directory path: ~/{{ item.name }} mode: "{{ item.mode | default('0755') }}" with_items: "{{ empty_directories }}" loop_control: label: "{{ item.name }}" - name: Link this folder to ~/.dotfiles ansible.builtin.file: state: link force: true follow: false owner: "{{ user.name }}" group: "{{ user.name }}" path: "/home/{{ user.name }}/.dotfiles" src: "{{ playbook_dir }}" become: true become_user: root - name: Get state of copy targets ansible.builtin.stat: path: ~/{{ item.to }} register: copy_stat when: not item.template|default(false) with_items: "{{ dotfiles }}" check_mode: false loop_control: label: "{{ item.to }}" - name: Remove invalid copy target (symlinks) ansible.builtin.file: path: "{{ item.stat.path }}" state: absent when: - not item.skipped is defined or not item.skipped - item.stat.exists - item.stat.islnk with_items: "{{ copy_stat.results }}" loop_control: label: "{{ item.item.from }}" - name: Make sure target directories exist ansible.builtin.file: state: directory path: "{{ (['/home', user.name, item.to] | join('/')) | dirname }}" owner: "{{ user.name }}" group: "{{ user.name }}" with_items: "{{ dotfiles }}" become: true become_user: root loop_control: label: "{{ item.to }}" - name: Copy dotfiles ansible.builtin.copy: dest: "/home/{{ user.name }}/{{ item.to }}" src: /var/lib/dotfiles/{{ item.from }} owner: "{{ user.name }}" group: "{{ user.name }}" when: not item.template|default(false) and not item.dir|default(false) with_items: "{{ dotfiles }}" become: true become_user: root loop_control: label: "{{ item.to }}" - name: Copy directories ansible.posix.synchronize: dest: "/home/{{ user.name }}/{{ item.to }}/" src: /var/lib/dotfiles/{{ item.from }}/ archive: false owner: false group: false links: true perms: false times: false recursive: true checksum: true delete: true when: item.dir|default(false) with_items: "{{ dotfiles }}" become: true become_user: root loop_control: label: "{{ item.to }}" - name: Apply directory permissions ansible.builtin.file: dest: "/home/{{ user.name }}/{{ item.to }}/" owner: "{{ user.name }}" group: "{{ user.name }}" recurse: true when: item.dir|default(false) with_items: "{{ dotfiles }}" become: true become_user: root loop_control: label: "{{ item.to }}" - name: Get state of template targets ansible.builtin.stat: path: ~/{{ item.to }} register: template_stat when: item.template|default(false) with_items: "{{ dotfiles }}" check_mode: false loop_control: label: "{{ item.to }}" - name: Remove invalid template target (directory or symlink) ansible.builtin.file: path: "{{ item.stat.path }}" state: absent when: - not item.skipped is defined or not item.skipped - item.stat.exists - not item.stat.isreg with_items: "{{ template_stat.results }}" loop_control: label: "{{ item.item.to }}" - name: Deploy dotfiles templates ansible.builtin.template: src: /var/lib/dotfiles/{{ item.from }}.j2 dest: "/home/{{ user.name }}/{{ item.to }}" owner: "{{ user.name }}" group: "{{ user.name }}" force: true become: true become_user: root when: item.template|default(false) with_items: "{{ dotfiles }}" loop_control: label: "{{ item.to }}" - name: Remove dotfiles ansible.builtin.file: state: absent path: "/home/{{ user.name }}/{{ item }}" loop: "{{ dotfiles_remove }}" - name: Create directories ansible.builtin.file: state: directory path: "{{ item }}" with_items: - ~/tmp - name: Stat ~/bin ansible.builtin.stat: path: "/home/{{ user.name }}/bin" register: bin_stat check_mode: false - name: Remove ~/bin if not a link ansible.builtin.file: state: absent path: "/home/{{ user.name }}/bin" when: - bin_stat.stat.exists - not bin_stat.stat.islnk - name: Link bin directory ansible.builtin.file: state: link force: true follow: false path: "/home/{{ user.name }}/bin" src: /var/lib/dotfiles/bin owner: "{{ user.name }}" group: "{{ user.name }}" - name: Firefox tags: - user:firefox block: - name: Create firefox base directories ansible.builtin.file: path: "{{ item }}" state: directory mode: "0755" loop: - "~/.mozilla/" - "~/.mozilla/firefox/" - name: Create firefox profile directories ansible.builtin.file: path: "~/.mozilla/firefox/profile-{{ item.key }}" state: directory mode: "0755" loop: "{{ user.firefox_profiles | dict2items }}" loop_control: label: "{{ item.key }}" - name: Create chrome directory ansible.builtin.file: path: "~/.mozilla/firefox/profile-{{ item.key }}/chrome/" state: directory mode: "0755" loop: "{{ user.firefox_profiles | dict2items }}" loop_control: label: "{{ item.key }}" - name: Configure firefox custom css ansible.builtin.copy: dest: "~/.mozilla/firefox/profile-{{ item.key }}/chrome/userChrome.css" # from https://www.kvakil.me/posts/2023-09-12-my-tree-style-tab-configuration.html content: | // Hide the title bar. #titlebar { appearance: none !important; height: 0px; } #titlebar > #toolbar-menubar { margin-top: 0px; } // Hide regular tab toolbar. #main-window[tabsintitlebar="true"]:not([extradragspace="true"]) #TabsToolbar > .toolbar-items { opacity: 0; pointer-events: none; } #main-window:not([tabsintitlebar="true"]) #TabsToolbar { visibility: collapse !important; } // Hide the side toolbar noise. #TabsToolbar { min-width: 0 !important; min-height: 0 !important; } #TabsToolbar > .titlebar-buttonbox-container { display: block; position: absolute; top: 12px; left: 0px; } #sidebar-box[sidebarcommand="treestyletab_piro_sakura_ne_jp-sidebar-action"] #sidebar-header { display: none; } when: - item.value.manage_css is sameas True loop: "{{ user.firefox_profiles | dict2items }}" loop_control: label: "{{ item.key }}" - name: Handle user units tags: - user:units block: - name: Link user service files ansible.builtin.file: state: link force: true follow: false path: "/home/{{ user.name }}/.config/systemd/user/{{ item | basename }}" src: "{{ item }}" owner: "{{ user.name }}" group: "{{ user.name }}" with_fileglob: /var/lib/dotfiles/services/* - name: Handle autostart units tags: - user:autostart block: - name: Create systemd user directory ansible.builtin.file: state: directory path: ~/{{ item }} loop: - .config/ - .config/systemd/ - .config/systemd/user/ - name: Link autostart service files ansible.builtin.file: state: link force: true follow: false path: "/home/{{ user.name }}/.config/systemd/user/{{ item | basename }}" src: "{{ item }}" owner: "{{ user.name }}" group: "{{ user.name }}" with_fileglob: /var/lib/dotfiles/autostart/services/* - name: Get state of autostart.target ansible.builtin.stat: path: "/home/{{ user.name }}/.config/systemd/user/autostart.target" register: autostart_target_stat - name: Remove invalid autostart.target ansible.builtin.file: path: "/home/{{ user.name }}/.config/systemd/user/autostart.target" state: absent when: - autostart_target_stat.stat.exists - not autostart_target_stat.stat.isreg - name: Deploy autostart.target ansible.builtin.template: src: ./autostart/autostart.target.j2 dest: "/home/{{ user.name }}/.config/systemd/user/autostart.target" owner: "{{ user.name }}" group: "{{ user.name }}" force: true follow: false - name: Gpg tags: - user:gpg when: user.gpg_key is defined block: - name: Import gpg key ansible.builtin.command: gpg --import ./gpgkeys/{{ user.gpg_key.email }}.gpg.asc register: gpg_import_output changed_when: not ("unchanged" in gpg_import_output.stderr) - name: Trust gpg key ansible.builtin.shell: "gpg --import-ownertrust <<< {{ user.gpg_key.fingerprint }}:6" args: executable: /bin/bash # required for <<< register: gpg_trust_output changed_when: gpg_trust_output.stderr_lines|length > 0