diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000000..6173d380dd64 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,46 @@ +FROM --platform=$BUILDPLATFORM ubuntu:24.04 +ARG TARGETARCH + +RUN DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get update && \ + apt-get install -y \ + alsa-utils \ + # Includes basic building tools + build-essential \ + ninja-build \ + # Used by most OpenSource LSPs extensions + clangd \ + # Debugger + gdb \ + # VCS + git \ + # Audio integration + pipewire \ + pipewire-alsa \ + pulseaudio-utils \ + # Required for pre-commit + python3-pip \ + # Default Qt QPA + qt6-wayland \ + # Allow privileges escalation in container (e.g to install custom deps) + sudo \ + # Allow udev rules debug and test + udev \ + # Convenience for git interactive commands + vim && \ + pip3 install pre-commit --break-system-packages + +COPY tools/debian_buildenv.sh /tmp/ + +RUN /tmp/debian_buildenv.sh setup + +RUN userdel -f -r ubuntu && \ + mkdir /home/developer && echo "developer ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/developer && \ + mkdir -p \ + /home/developer/.cache/pre-commit \ + /home/developer/.devcontainer \ + /home/developer/.mixxx \ + /tmp/ccache && \ + touch /home/developer/.devcontainer/.bash_history && \ + chown -R 1000:1000 /home/developer/ /tmp/ccache && \ + echo ".cache\n.vscode\n.node_modules" >> /home/developer/.gitignore && \ + echo ". /etc/bash_completion\nexport PROMPT_COMMAND='history -a'\nexport HISTFILE='/home/developer/.devcontainer/.bash_history'" >> /home/developer/.bashrc diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..5713687d3ee8 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,65 @@ +{ + "name": "mixxx", + "build": { + "cacheFrom": "ghcr.io/mixxxdj/mixxx/devcontainer:latest", + "dockerfile": "Dockerfile", + "context": ".." + }, + "runArgs": [ + "--network=host" // This is needed for native X.org support + ], + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "installZsh": "false", + "username": "developer", + "userUid": "1000", + "userGid": "1000", + "upgradePackages": "false" + } + }, + "initializeCommand": "touch ${localEnv:HOME}${localEnv:USERPROFILE}/.gitignore", + "customizations": { + "vscode": { + "extensions": [ + "llvm-vs-code-extensions.vscode-clangd", + "twxs.cmake", + "ms-vscode.cmake-tools", + "streetsidesoftware.code-spell-checker", + "vadimcn.vscode-lldb", + "GitHub.vscode-pull-request-github", + "eamodio.gitlens" + ] + } + }, + "remoteEnv": { + "SSH_AUTH_SOCK": "${localEnv:SSH_AUTH_SOCK}", + "PATH": "/usr/lib/qt6/bin/:${containerEnv:PATH}", + "DISPLAY": "${localEnv:DISPLAY::0}", + "XDG_SESSION_DESKTOP": "${localEnv:XDG_SESSION_DESKTOP:gnome}", + "XDG_SESSION_TYPE": "${localEnv:XDG_SESSION_TYPE:wayland}", + "XAUTHORITY": "${localEnv:XAUTHORITY}", + "WAYLAND_DISPLAY": "${localEnv:WAYLAND_DISPLAY:wayland-0}", + "XDG_SESSION_CLASS": "${localEnv:XDG_SESSION_CLASS:user}", + "XDG_RUNTIME_DIR": "${localEnv:XDG_RUNTIME_DIR:/run/user/1000}", + "QT_QPA_PLATFORM": "${localEnv:QT_QPA_PLATFORM:wayland}", // Default to Wayland session, can also use 'xcb' to use X.org instead + "CLAZY_CHECKS": "level2,container-inside-loop,heap-allocated-small-trivial-type,isempty-vs-count,qhash-with-char-pointer-key,qproperty-type-mismatch,tr-non-literal,no-rule-of-two-soft,no-non-pod-global-static,no-qproperty-without-notify,no-qstring-allocations,no-function-args-by-value,no-copyable-polymorphic,no-ctor-missing-parent-argument,no-missing-qobject-macro,no-rule-of-three,no-returning-void-expression", + "CLAZY_IGNORE_DIRS": "lib/.*" + }, + "remoteUser": "developer", + "postCreateCommand": "git config --global core.excludesFile '/home/developer/.gitignore' && git config --global --add safe.directory ${containerWorkspaceFolder} && pre-commit install --overwrite --install-hooks", + "mounts": [ + "type=bind,source=${localEnv:HOME},target=${localEnv:HOME},rslave", + "type=bind,source=${localEnv:XDG_RUNTIME_DIR},target=${localEnv:XDG_RUNTIME_DIR}", + "type=bind,source=/var/run/dbus/system_bus_socket,target=/var/run/dbus/system_bus_socket", + "type=bind,source=/dev,target=/dev,rslave", + "type=bind,source=/media,target=/media,rslave", + "type=bind,source=/mnt,target=/mnt,rslave", + "type=bind,source=/run/media,target=/run/media,rslave", + // Dev volumes used for persistence between containers + "type=volume,source=mixxx-bashistory,target=/home/developer/.devcontainer", + "type=volume,source=mixxx-precommit,target=/home/developer/.cache/pre-commit", + "type=volume,source=mixxx-config,target=/home/developer/.mixxx", + "type=volume,source=mixxx-ccache,target=/tmp/ccache", + "type=volume,source=mixxx-build,target=/workspaces/mixxx/build" + ] +} diff --git a/.github/labeler.yml b/.github/labeler.yml index 998d317dc647..a499dcb5d010 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -6,6 +6,12 @@ build: - build/** - cmake/** +dev container: + - changed-files: + - any-glob-to-any-file: + - .devcontainer/** + - tools/debian_buildenv.sh + cmake: - changed-files: - any-glob-to-any-file: diff --git a/.github/workflows/devcontainer.yml b/.github/workflows/devcontainer.yml new file mode 100644 index 000000000000..53d5ef2299d0 --- /dev/null +++ b/.github/workflows/devcontainer.yml @@ -0,0 +1,40 @@ +name: Docker + +on: + push: + branches: ["main"] + + pull_request: + branches: [main] + types: + - opened + - synchronize + - labeled + +permissions: + contents: read + packages: write + +jobs: + devcontainer: + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'mixxxdj/mixxx' || contains(github.event.pull_request.labels.*.name, 'dev container') }} + runs-on: ubuntu-latest + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + file: .devcontainer/Dockerfile + platforms: linux/arm64,linux/amd64 + pull: true + push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository == 'mixxxdj/mixxx' }} + tags: ghcr.io/mixxxdj/mixxx/devcontainer:latest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b0dfc1176c41..b7db33219f67 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,6 +38,7 @@ repos: exclude: ^.*(\.cbproj|\.groupproj|\.props|\.sln|\.vcxproj|\.vcxproj.filters|UTF-8-BOM.txt)$ - id: check-case-conflict - id: check-json + exclude: ^(.devcontainer/devcontainer.json)$ # Contains JSON comment, which isn't supported by the hook - id: check-merge-conflict - id: check-xml - id: check-yaml diff --git a/README.md b/README.md index 6c583fbddcca..721bbe9a905d 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,33 @@ run. Alternatively, can generate a package using `cpack`. Detailed build instructions for each target OS can be found [on the wiki](https://github.com/mixxxdj/mixxx/wiki#compile-mixxx-from-source-code) +### Using Dev Container + +> [!NOTE] +> Dev container has recently been introduced and it is likely incomplete! Currently, it's been tested with `devpod` on Zed and Codium exclusively + +We provide a Dev Container definition for Mixxx, based on Ubuntu 24.04 to ensure a close similarity with the CI. + +> [!TIP] +> New to [Development Containers](https://containers.dev/)? If you use VS Code, the IDE should offer you to use Dev Container when you open the Mixxx working copy folder. Otherwise, +you may consider using [devpod](https://devpod.sh/docs/developing-in-workspaces/create-a-workspace#create-a-workspace) + +You can build and run Mixxx using the following command: + +```bash +cd build +cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON # Needed for clangd +cmake --build . -j $(nproc) +./mixxx +``` + +#### Using your device in Dev Container + +Similar to [Fedora Toolbox's](https://github.com/containers/toolbox/blob/4f4c3c9d19d1027537f69920de46b9cf09c799b9/src/cmd/create.go#L460), the default configuration provide a comprehensive definition of mounts which will allow you to use Mixxx seamlessly in the container. (UI, audio, ...) +If you are not comfortable with this for security concern, you may want to remove some or all of the binding before starting the container. + +Devices should be supported by default, thanks to the provided binds. Note that if you are encountering permission issue, check that you are not using SELinux, as this is currently not well supported in Dev Container + ## Documentation For help using Mixxx, there are a variety of options: