--- - name: Packages ansible.builtin.apt: name: - git - libvlc5 # runtime lib python-vlc (installed into the venv by uv) binds against - vlc-plugin-base - alsa-utils - samba cache_valid_time: 7200 - name: Ensure uv install directory exists ansible.builtin.file: path: "/opt/uv-{{ pi_musicmouse_uv_version }}-{{ pi_musicmouse_uv_target }}" state: directory mode: "0755" - name: Download and extract uv {{ pi_musicmouse_uv_version }} ansible.builtin.unarchive: src: "https://github.com/astral-sh/uv/releases/download/{{ pi_musicmouse_uv_version }}/uv-{{ pi_musicmouse_uv_target }}.tar.gz" dest: "/opt/uv-{{ pi_musicmouse_uv_version }}-{{ pi_musicmouse_uv_target }}" remote_src: true extra_opts: ["--strip-components=1"] creates: "/opt/uv-{{ pi_musicmouse_uv_version }}-{{ pi_musicmouse_uv_target }}/uv" - name: Symlink uv/uvx into /usr/local/bin ansible.builtin.file: src: "/opt/uv-{{ pi_musicmouse_uv_version }}-{{ pi_musicmouse_uv_target }}/{{ item }}" dest: "/usr/local/bin/{{ item }}" state: link force: true loop: - uv - uvx - name: Verify uv runs on this host ansible.builtin.command: cmd: /usr/local/bin/uv --version register: pi_musicmouse_uv_version_out changed_when: false - name: Checkout Musicmouse repo ansible.builtin.git: repo: "{{ pi_musicmouse_repo }}" dest: /opt/musicmouse version: "{{ musicmouse_version }}" accept_hostkey: true force: true notify: Reinstall musicmouse backend - name: Check the checkout has the layout this role knows ansible.builtin.stat: path: /opt/musicmouse/python-backend/pyproject.toml register: pi_musicmouse_pyproject # Meaningless under --check on a host that has never been deployed: the git task # above reports "changed" without writing anything, so there is nothing to stat. when: not ansible_check_mode - name: Fail on a pre-rearchitecture checkout ansible.builtin.fail: msg: >- {{ musicmouse_version }} has no python-backend/pyproject.toml, so it predates the rearchitecture and this role cannot install it - the venv, the systemd unit and the web/ build all live somewhere else on those commits. Point musicmouse_version at a branch that has it (deploy/musicdolphin), or set mediapi_install_kidsmusic to false for this host and leave whatever is installed alone. Stopping here rather than failing three tasks deeper with the real reason buried. when: not ansible_check_mode and not pi_musicmouse_pyproject.stat.exists - name: Create virtualenv with Python {{ pi_musicmouse_python_version }} ansible.builtin.command: cmd: "/usr/local/bin/uv venv --python {{ pi_musicmouse_python_version }} /opt/musicmouse/.venv" creates: /opt/musicmouse/.venv/bin/python - name: Create media directory ansible.builtin.file: path: /media/musicmouse state: directory mode: "0755" - name: Install config file ansible.builtin.copy: src: "{{ pi_musicmouse_config_file }}" dest: /media/musicmouse/config.yml mode: "0644" # Install-once: the app writes this file itself (parent mode's volume keys, the # remote-control mapping). See pi_musicmouse_force_config in defaults. force: "{{ pi_musicmouse_force_config }}" notify: Restart musicmouse - name: Install tippen curriculum ansible.builtin.copy: src: "{{ pi_musicmouse_curriculum_file }}" dest: /media/musicmouse/tippen-curriculum.yml mode: "0644" when: pi_musicmouse_curriculum_file | length > 0 notify: Restart musicmouse - name: Install systemd service file (from the checked-out repo, not a copy kept here) ansible.builtin.copy: src: /opt/musicmouse/python-backend/musicmouse.service dest: /etc/systemd/system/musicmouse.service mode: "0644" remote_src: true notify: Restart musicmouse - name: Add script to autostart and start now ansible.builtin.systemd: name: musicmouse state: started enabled: "yes" daemon_reload: "yes" - name: Ensure local frontend build cache directory exists ansible.builtin.file: path: "{{ pi_musicmouse_build_cache }}/{{ musicmouse_version | regex_replace('/', '_') }}" state: directory mode: "0755" delegate_to: localhost become: false vars: # `become: false` above is not enough on its own. pi_standard_setup's defaults set # `ansible_become: true`, role defaults are play-wide host variables, and the # `ansible_become` *variable* outranks the `become` *keyword* in Ansible's # precedence - so every task here tried to sudo on the control machine. Those # defaults are needed to bootstrap a fresh Pi (connect as `pi`, become root, enable # root login), so override the variable here rather than removing them. ansible_become: false - name: Checkout Musicmouse repo for frontend build (control machine) ansible.builtin.git: repo: "{{ pi_musicmouse_repo }}" dest: "{{ pi_musicmouse_build_cache }}/{{ musicmouse_version | regex_replace('/', '_') }}" version: "{{ musicmouse_version }}" accept_hostkey: true force: true delegate_to: localhost become: false vars: ansible_become: false # see the first delegated task in tasks/main.yml notify: Build frontend - name: Samba setup ansible.builtin.copy: src: smb.conf dest: /etc/samba/ mode: "0644" - name: Restart samba ansible.builtin.systemd: name: smbd state: restarted enabled: "yes" daemon_reload: "yes" # manual steps: # - set samba passwords with smbpasswd # - copy music into /media/musicmouse: scripts/sync-library.sh in the app repo, which # also carries the cover and analysis cache over (or use the samba share, and let # the device spend the DSP time itself)