diff --git a/.claude/skills/robostack-versions/SKILL.md b/.claude/skills/robostack-versions/SKILL.md index b7112665..ab45bab3 100644 --- a/.claude/skills/robostack-versions/SKILL.md +++ b/.claude/skills/robostack-versions/SKILL.md @@ -25,8 +25,10 @@ change, or on request) open PRs that already contain the bumps below. Do it by h `distros//conda_build_config.yaml`. - **The mutex** (`mutex_package` in `distros//vinca.yaml`): `ros2-distro-mutex` with `upper_bound: x.x`. Packages built with mutex 0.11 can't be installed with - 0.10 builds. Its `run_constraints` pin the ABI-relevant libraries for users' - environments and must agree with the rendered pins. + 0.10 builds. It has no `run_constraints` (`rs check` enforces it): library versions + come from the packages' own dependencies. When an environment resolves to a broken + combination, fix the metadata of the package that is wrong (a patch, + `pkg_additional_info.yaml`, or a conda-forge repodata patch), never the mutex. ## Update the snapshot @@ -53,12 +55,10 @@ pixi run rs create-snapshot pixi run rs update-pinning # = bot command: latest pinning + rebuild plan for pixi run rs update-pinning # the same for every distribution pixi run rs render-pinning # after editing shared/pinning or distro.yaml -pixi run rs check-deps # solve all non-ROS deps + mutex constraints, nothing built +pixi run rs check-deps # solve all non-ROS deps together, nothing built ``` `check-deps` reports: -- `PIN MISMATCH`: a mutex `run_constraints` entry contradicts the rendered pin. Fix - `vinca.yaml` or the pinning; never `conda_build_config.yaml`. - Per conflicting package: the recipes that need it, the clashing pin, the solver explanation and the conda-forge migration status. "no migration" means the feedstock only needs a rebuild upstream. @@ -78,9 +78,8 @@ host requirements, plus everything that depends on them (host or run, transitive are rebuilt; the rest keep their published builds. - **Partial rebuild** (the usual case): those packages get `build_number` = highest - released build + 1 in `distros//pkg_additional_info.yaml`, and when the mutex - `run_constraints` changed, the mutex gets a new build at the same version - (`mutex_package.build_number`), so all other published packages stay installable. + released build + 1 in `distros//pkg_additional_info.yaml`. The mutex stays as + it is, so all other published packages stay installable. - **Full rebuild** (more than half of the packages affected): the bump below. The PR lists the packages and why, the migrations used / waiting for our dependencies' @@ -102,11 +101,9 @@ rebuilt: 2. Mutex minor version + 1, e.g. `0.10.0` -> `0.11.0`. Nothing else hard-codes the mutex version. 3. Remove all per-package `build_number` entries in `distros//pkg_additional_info.yaml`. -4. Update mutex `run_constraints` to the new pins, then run `check-deps`. -5. `pixi run rs check`. +4. `pixi run rs check-deps`, then `pixi run rs check`. -The bot does 1–4. It only moves constraints of the form ` .*`; ranges -and other constraints are left for you to check. +The bot does 1–3. In the PR, CI uses its cache unless told otherwise. A full rebuild PR sets `full_rebuild: true` in `distros//ci.yaml` (reset after merging). @@ -123,15 +120,12 @@ In the PR, CI uses its cache unless told otherwise. A full rebuild PR sets ```bash pixi run rs find-stale # = bot find-stale-packages pixi run rs check-deps --stale # local artifacts -pixi run rs check-deps --stale --mutex-only # only mutex violations pixi run rs check-deps --stale --repodata https://conda.anaconda.org/ pixi run rs check-deps --stale --delete # delete stale local artifacts ``` For published stale builds, the report prints the `pkg_additional_info.yaml` -build-number snippet, a `mutex_package: build_number:` bump (re-publishes the mutex -with new constraints without changing its version), and the `anaconda remove` -commands for the old files. +build-number snippet and the `anaconda remove` commands for the old files. ## Bump vinca or rattler-build diff --git a/.github/workflows/testpr.yaml b/.github/workflows/testpr.yaml index 4d75786e..7a0a6329 100644 --- a/.github/workflows/testpr.yaml +++ b/.github/workflows/testpr.yaml @@ -65,6 +65,8 @@ jobs: cache-write: false # the build jobs save the pixi environment cache - name: Sanity checks (every distribution assembles, generated files up to date, sorted) run: pixi run rs check + - name: Unit tests of the tooling + run: pixi run test build: needs: plan diff --git a/README.md b/README.md index 4a6d2074..1b18869f 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ combines the two, and the files next to each: - **`vinca.yaml`:** - The package selection (`packages_select_by_deps`) lives in `shared/` for every distribution; vinca skips packages a distribution's rosdistro doesn't have. - Exceptions, in `shared/` or a distribution: `packages_exclude` (not built, dropped from other packages' dependencies) and `packages_skip` (not built, dependents keep the dependency), each as plain names or under `- if: `. ROS packages mapped to conda-forge in `robostack.yaml` are skipped automatically. - - `mutex_package`: name, `upper_bound` and the common `run_constraints` are shared. Each distribution sets its own `version`, and its `run_constraints` replace the shared constraint on the same package (e.g. jazzy's `libprotobuf 7.35.*`) or add new ones. + - `mutex_package`: name and `upper_bound` are shared; each distribution sets its own `version`. The mutex only keeps one distribution per environment and has no `run_constraints` (`rs check` enforces it): library versions come from the packages' own dependencies, and wrong ones are fixed in the package's metadata. - Other keys come from the distribution if it sets them, else from `shared/`. A distribution that differs from a shared setting just sets it. - Paths are relative to the file that sets them. `distros//work/vinca.yaml` (generated) extends the distribution's file and adds `skip_existing` (its channel). - **`pkg_additional_info.yaml` and `patch/dependencies.yaml`:** merged per package. The distribution's keys win, for example its own `build_number` on top of a shared `additional_cmake_args`. @@ -127,7 +127,7 @@ of a distribution uses `full_rebuild: true` there. A new build number goes into | `add-package ... [...]` | anyone | Adds ROS packages to the shared selection in `shared/vinca.yaml`, in sorted position; every distribution that has them builds them. Opens a PR listing, for the given (default: every) distribution, what will be built on linux-64 (and what is already published as a dependency). Valid ROS package names only, at most 10 per request. | | `update-rosdistro-snapshot [... \| all]` | maintainers | Snapshots the distribution's latest rosdistro sync (the release team's tag, e.g. `jazzy/2026-10-05`, recorded as `rosdistro_sync` in `distro.yaml`; rosdistro master for `rosdistro_sync: manual`, like rolling), then sets `build_number` to the highest build of the distribution's released packages + 1, bumps the mutex minor version and removes all per-package build numbers: a full rebuild. The PR links the sync's announcement and lists the version bumps. Runs daily for distributions with a new sync. | | `find-stale-packages [... \| all]` | maintainers | Published packages built against pins that no longer match, with the build-number snippet to rebuild them. Replies only. | -| `update-conda-forge-pinning [... \| all]` | maintainers | Moves the distribution's conda-forge pinning (`conda_forge_pinning_version` / `conda_forge_migrations` in `distro.yaml`, or `shared/pinning/conda_forge.yaml` for distributions that follow it) to the latest version, with the migrations that are done for the distribution's dependencies, and re-renders `conda_build_config.yaml`. Only packages that use a changed pin, and everything depending on them, are rebuilt (per-package build numbers, a new build of the mutex at the same version); more than half affected means a full rebuild. Mutex `run_constraints` of the form ` .*` follow the new pins. The PR lists the rebuilt packages, the migrations used and those waiting for feedstocks, and the dependency check; it is labelled `dependency-conflict` when the pins can't be installed together. Runs daily, one PR per distribution. | +| `update-conda-forge-pinning [... \| all]` | maintainers | Moves the distribution's conda-forge pinning (`conda_forge_pinning_version` / `conda_forge_migrations` in `distro.yaml`, or `shared/pinning/conda_forge.yaml` for distributions that follow it) to the latest version, with the migrations that are done for the distribution's dependencies, and re-renders `conda_build_config.yaml`. Only packages that use a changed pin, and everything depending on them, are rebuilt (per-package build numbers); more than half affected means a full rebuild. The PR lists the rebuilt packages, the migrations used and those waiting for feedstocks, and the dependency check; it is labelled `dependency-conflict` when the pins can't be installed together. Runs daily, one PR per distribution. | There are three ways to trigger a command: - a *Package request* or *robostack-bot command* issue; diff --git a/distros/humble/vinca.yaml b/distros/humble/vinca.yaml index 9354ff9d..c0b2a9ba 100644 --- a/distros/humble/vinca.yaml +++ b/distros/humble/vinca.yaml @@ -7,9 +7,9 @@ rosdistro_additional_recipes: rosdistro_additional_recipes.yaml build_number: 20 mutex_package: + # new build without run_constraints (same version as the published ones) + build_number: 21 version: "0.10.0" - run_constraints: - - krb5 1.22.* packages_exclude: diff --git a/distros/jazzy/vinca.yaml b/distros/jazzy/vinca.yaml index 4dbabd7a..3a7aaa5f 100644 --- a/distros/jazzy/vinca.yaml +++ b/distros/jazzy/vinca.yaml @@ -9,31 +9,9 @@ rosdistro_additional_recipes: rosdistro_additional_recipes.yaml build_number: 25 mutex_package: + # new build without run_constraints (same version as the published ones) + build_number: 26 version: "0.19.0" - run_constraints: - - libprotobuf 7.35.* - # ffmpeg (pulled in transitively by libopencv, needed by the whole image/gz - # stack) only supports libprotobuf 7.35 via libopenvino-tensorflow-frontend - # >=2026.3.0; older libopenvino/libopencv/ffmpeg builds still coexist in the - # channel needing libprotobuf 6.x, so pin this directly rather than relying - # on resolvo to find the compatible combination on its own. libopencv/ - # py-opencv are pinned too, since resolvo has shown trouble propagating the - # openvino constraint transitively through ffmpeg on its own. - - libopenvino-tensorflow-frontend >=2026.3.0 - - libopencv >=5.0.0 - - py-opencv >=5.0.0 - # Belt-and-suspenders for the same conflict: ffmpeg 8.1.2 builds that pull - # in the protobuf-6-only openvino also coexist in the channel. Pinning - # ffmpeg directly to major version 9 removes the ambiguity outright. - - ffmpeg 9.* - # libopencv 5.0.0 also depends on a *second*, separate openvino frontend - # package (tensorflow-LITE-frontend, distinct from tensorflow-frontend - # above) and every 5.0.0 build hardcodes it to the 2026.3.0.x line. Some - # ffmpeg 9.0.1/9.0.2 builds instead need 2026.3.1, which conflicts -- - # constrain lite-frontend to the same range libopencv needs so resolvo - # picks an ffmpeg 9.x build compatible with it. - - libopenvino-tensorflow-lite-frontend >=2026.3.0,<2026.3.1.0a0 - packages_exclude: diff --git a/distros/lyrical/vinca.yaml b/distros/lyrical/vinca.yaml index c1053175..dac40e31 100644 --- a/distros/lyrical/vinca.yaml +++ b/distros/lyrical/vinca.yaml @@ -6,13 +6,9 @@ rosdistro_additional_recipes: rosdistro_additional_recipes.yaml build_number: 27 mutex_package: + # new build without run_constraints (same version as the published ones) + build_number: 28 name: ros2-distro-mutex version: 0.21.0 upper_bound: x.x - run_constraints: - - libboost 1.90.* - - libboost-devel 1.90.* - - pcl 1.15.1.* - - libprotobuf 7.35.1.* - - vtk 9.7.0.* diff --git a/distros/rolling/vinca.yaml b/distros/rolling/vinca.yaml index 23f15ade..b0fe2da7 100644 --- a/distros/rolling/vinca.yaml +++ b/distros/rolling/vinca.yaml @@ -7,29 +7,9 @@ rosdistro_additional_recipes: rosdistro_additional_recipes.yaml build_number: 29 mutex_package: + # new build without run_constraints (same version as the published ones) + build_number: 30 version: "0.22.0" - run_constraints: - # ffmpeg (pulled in transitively by libopencv, needed by the whole image/gz - # stack) only supports libprotobuf 7.35 via libopenvino-tensorflow-frontend - # >=2026.3.0; older libopenvino/libopencv/ffmpeg builds still coexist in the - # channel needing libprotobuf 6.x, so pin this directly rather than relying - # on resolvo to find the compatible combination on its own. libopencv/ - # py-opencv are pinned too, since resolvo has shown trouble propagating the - # openvino constraint transitively through ffmpeg on its own. - - libopenvino-tensorflow-frontend >=2026.3.0 - - libopencv >=5.0.0 - - py-opencv >=5.0.0 - # Belt-and-suspenders for the same conflict: ffmpeg 8.1.2 builds that pull - # in the protobuf-6-only openvino also coexist in the channel. Pinning - # ffmpeg directly to major version 9 removes the ambiguity outright. - - ffmpeg 9.* - # libopencv 5.0.0 also depends on a *second*, separate openvino frontend - # package (tensorflow-LITE-frontend, distinct from tensorflow-frontend - # above) and every 5.0.0 build hardcodes it to the 2026.3.0.x line. Some - # ffmpeg 9.0.1/9.0.2 builds instead need 2026.3.1, which conflicts -- - # constrain lite-frontend to the same range libopencv needs so resolvo - # picks an ffmpeg 9.x build compatible with it. - - libopenvino-tensorflow-lite-frontend >=2026.3.0,<2026.3.1.0a0 packages_exclude: diff --git a/pixi.lock b/pixi.lock index 0f20154b..33a1b6c0 100644 --- a/pixi.lock +++ b/pixi.lock @@ -77,10 +77,19 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/yaml-0.2.5-hebe6cf0_3.conda - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_7.conda - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + - conda: https://prefix.dev/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://prefix.dev/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://prefix.dev/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.14-9_cp314.conda - conda: https://prefix.dev/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda + - conda: https://prefix.dev/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6#b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6 + - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=cf6833a12f36509a90ea33d25766709bcc1eb2cf#cf6833a12f36509a90ea33d25766709bcc1eb2cf - pypi: https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/74/ef303ec980ef962ffe548fa36cb138bb399d1d1315731ba7bb81da85f7e0/rosdistro-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl @@ -94,8 +103,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/3f/53/b5e80bac66d0db921ddbbe3c8d37198455c19302a29da1a434708c35c79d/catkin_pkg-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7e/cd/fe58041e9011f307c490e3e17dd48cc516448f7c698a3f2d9d9d65d7e6a8/networkx-3.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/db/d7282caf7ab03af44d5d6fdbaa019b35c7d7f1c90588b839c07cba640d6a/markupsafe-3.0.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl @@ -149,10 +156,19 @@ environments: - conda: https://prefix.dev/conda-forge/linux-aarch64/yaml-0.2.5-h29ee22c_3.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/zstd-1.5.7-h9d15635_7.conda - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + - conda: https://prefix.dev/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://prefix.dev/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://prefix.dev/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.14-9_cp314.conda - conda: https://prefix.dev/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda + - conda: https://prefix.dev/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6#b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6 + - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=cf6833a12f36509a90ea33d25766709bcc1eb2cf#cf6833a12f36509a90ea33d25766709bcc1eb2cf - pypi: https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/74/ef303ec980ef962ffe548fa36cb138bb399d1d1315731ba7bb81da85f7e0/rosdistro-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl @@ -164,8 +180,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/3f/53/b5e80bac66d0db921ddbbe3c8d37198455c19302a29da1a434708c35c79d/catkin_pkg-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7e/cd/fe58041e9011f307c490e3e17dd48cc516448f7c698a3f2d9d9d65d7e6a8/networkx-3.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7f/72/9c5e7707b57c8ddfa9ddf7b0b1d009d7fbab9e9e887d5b721060f37e307d/charset_normalizer-3.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl - pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl @@ -181,8 +195,17 @@ environments: - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl osx-64: - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + - conda: https://prefix.dev/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://prefix.dev/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://prefix.dev/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.14-9_cp314.conda - conda: https://prefix.dev/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda + - conda: https://prefix.dev/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://prefix.dev/conda-forge/osx-64/bzip2-1.0.8-h374f1ed_10.conda - conda: https://prefix.dev/conda-forge/osx-64/c-ares-1.34.8-had63097_2.conda @@ -217,7 +240,7 @@ environments: - conda: https://prefix.dev/conda-forge/osx-64/tk-8.6.13-ha6c374e_4.conda - conda: https://prefix.dev/conda-forge/osx-64/yaml-0.2.5-had63097_3.conda - conda: https://prefix.dev/conda-forge/osx-64/zstd-1.5.7-hbc1a06c_7.conda - - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6#b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6 + - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=cf6833a12f36509a90ea33d25766709bcc1eb2cf#cf6833a12f36509a90ea33d25766709bcc1eb2cf - pypi: https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/74/ef303ec980ef962ffe548fa36cb138bb399d1d1315731ba7bb81da85f7e0/rosdistro-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl @@ -230,9 +253,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/3f/53/b5e80bac66d0db921ddbbe3c8d37198455c19302a29da1a434708c35c79d/catkin_pkg-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6c/ab/2f8488f0f817a39fca068d2b17daf446bf5cdb3eae28c3720af534d873b4/markupsafe-3.0.4-cp314-cp314-macosx_10_15_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7c/8a/40db9aa9f5907bb0e6f8b6d64064bf8852fb33d4b813ff9414911df7647c/charset_normalizer-3.5.2-cp314-cp314-macosx_10_15_universal2.whl - pypi: https://files.pythonhosted.org/packages/7e/cd/fe58041e9011f307c490e3e17dd48cc516448f7c698a3f2d9d9d65d7e6a8/networkx-3.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl @@ -246,8 +267,17 @@ environments: - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl osx-arm64: - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda + - conda: https://prefix.dev/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://prefix.dev/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://prefix.dev/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.14-9_cp314.conda - conda: https://prefix.dev/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda + - conda: https://prefix.dev/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/bzip2-1.0.8-h4e30115_10.conda - conda: https://prefix.dev/conda-forge/osx-arm64/c-ares-1.34.8-h74c22ad_2.conda @@ -282,7 +312,7 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-hbeba79b_4.conda - conda: https://prefix.dev/conda-forge/osx-arm64/yaml-0.2.5-h74c22ad_3.conda - conda: https://prefix.dev/conda-forge/osx-arm64/zstd-1.5.7-hf451053_7.conda - - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6#b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6 + - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=cf6833a12f36509a90ea33d25766709bcc1eb2cf#cf6833a12f36509a90ea33d25766709bcc1eb2cf - pypi: https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/74/ef303ec980ef962ffe548fa36cb138bb399d1d1315731ba7bb81da85f7e0/rosdistro-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl @@ -294,8 +324,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/3f/53/b5e80bac66d0db921ddbbe3c8d37198455c19302a29da1a434708c35c79d/catkin_pkg-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7c/8a/40db9aa9f5907bb0e6f8b6d64064bf8852fb33d4b813ff9414911df7647c/charset_normalizer-3.5.2-cp314-cp314-macosx_10_15_universal2.whl - pypi: https://files.pythonhosted.org/packages/7e/cd/fe58041e9011f307c490e3e17dd48cc516448f7c698a3f2d9d9d65d7e6a8/networkx-3.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl @@ -311,10 +339,19 @@ environments: - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl win-64: - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.7.22-h4c7d964_0.conda + - conda: https://prefix.dev/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://prefix.dev/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/m2-msys2-runtime-3.6.1.4-hc364b38_6.conda - conda: https://prefix.dev/conda-forge/noarch/m2-patch-2.7.6.3-hc364b38_6.conda + - conda: https://prefix.dev/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://prefix.dev/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.14-9_cp314.conda - conda: https://prefix.dev/conda-forge/noarch/setuptools-81.0.0-pyh332efcf_0.conda + - conda: https://prefix.dev/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://prefix.dev/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_10.conda - conda: https://prefix.dev/conda-forge/win-64/cmake-3.31.8-hdcbee5b_0.conda @@ -347,7 +384,7 @@ environments: - conda: https://prefix.dev/conda-forge/win-64/vcomp14-14.51.36247-habf1de7_41.conda - conda: https://prefix.dev/conda-forge/win-64/yaml-0.2.5-h6a83c73_3.conda - conda: https://prefix.dev/conda-forge/win-64/zstd-1.5.7-h534d264_7.conda - - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6#b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6 + - pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=cf6833a12f36509a90ea33d25766709bcc1eb2cf#cf6833a12f36509a90ea33d25766709bcc1eb2cf - pypi: https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/74/ef303ec980ef962ffe548fa36cb138bb399d1d1315731ba7bb81da85f7e0/rosdistro-1.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl @@ -360,8 +397,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/3f/53/b5e80bac66d0db921ddbbe3c8d37198455c19302a29da1a434708c35c79d/catkin_pkg-1.1.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7e/cd/fe58041e9011f307c490e3e17dd48cc516448f7c698a3f2d9d9d65d7e6a8/networkx-3.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/80/f0/5792ff768a410f93ee3f84fc19345295ffc352d2c936b424cb37e514714c/markupsafe-3.0.4-cp314-cp314-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl @@ -1591,6 +1626,42 @@ packages: run_exports: {} size: 131780 timestamp: 1784754889428 +- conda: https://prefix.dev/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + sha256: ab29d57dc70786c1269633ba3dff20288b81664d3ff8d21af995742e2bb03287 + md5: 962b9857ee8e7018c22f2776ffa0b2d7 + depends: + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/colorama?source=hash-mapping + run_exports: {} + size: 27011 + timestamp: 1733218222191 +- conda: https://prefix.dev/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + sha256: ee6cf346d017d954255bbcbdb424cddea4d14e4ed7e9813e429db1d795d01144 + md5: 8e662bd460bda79b1ea39194e3c4c9ab + depends: + - python >=3.10 + - typing_extensions >=4.6.0 + license: MIT and PSF-2.0 + purls: + - pkg:pypi/exceptiongroup?source=hash-mapping + run_exports: {} + size: 21333 + timestamp: 1763918099466 +- conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + sha256: e1a9e3b1c8fe62dc3932a616c284b5d8cbe3124bbfbedcf4ce5c828cb166ee19 + md5: 9614359868482abba1bd15ce465e3c42 + depends: + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/iniconfig?source=hash-mapping + run_exports: {} + size: 13387 + timestamp: 1760831448842 - conda: https://prefix.dev/conda-forge/noarch/m2-msys2-runtime-3.6.1.4-hc364b38_6.conda sha256: 1f797d055ad856def2399d5c1c21d7a479fa68159ce5448f07b7c6cf4b9641d7 md5: fb7de65144b11c4c7284a00e3170c797 @@ -1614,6 +1685,67 @@ packages: run_exports: {} size: 125917 timestamp: 1748281166711 +- conda: https://prefix.dev/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda + sha256: c432626b16768b8dab228bfb706f7060c2d462a21c516d240f68f2f902b5a044 + md5: 936687ed80f295a1f5dbcf8bd34c252c + depends: + - python >=3.9 + - python + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/packaging?source=hash-mapping + run_exports: {} + size: 116363 + timestamp: 1785888127370 +- conda: https://prefix.dev/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + sha256: e14aafa63efa0528ca99ba568eaf506eb55a0371d12e6250aaaa61718d2eb62e + md5: d7585b6550ad04c8c5e21097ada2888e + depends: + - python >=3.9 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/pluggy?source=hash-mapping + run_exports: {} + size: 25877 + timestamp: 1764896838868 +- conda: https://prefix.dev/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda + sha256: f5f015ff1bc3e1b7fc08eee096b1865234189ae0b82bebdb86a5369116e42fa0 + md5: 2882dee445dfa45b0c5afce3ffb7730a + depends: + - python >=3.10 + - python + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/pygments?source=compressed-mapping + run_exports: {} + size: 959376 + timestamp: 1786995678795 +- conda: https://prefix.dev/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda + sha256: 430051d80765207a7d782b2b188230ba1489d35c6e75fd9903f76cb9fda4af16 + md5: 64c98a12c4e23eb238bf66bbecafdf3c + depends: + - colorama + - pygments >=2.7.2 + - python >=3.10 + - iniconfig >=1.0.1 + - packaging >=22 + - pluggy >=1.5,<2 + - tomli >=1 + - exceptiongroup >=1 + - python + constrains: + - pytest-faulthandler >=2 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pytest?source=hash-mapping + run_exports: {} + size: 306724 + timestamp: 1782127176429 - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.14-9_cp314.conda build_number: 9 sha256: e7f8e965bbfb98e08feb2365cacdad8bb218fa5b5a0a2752f747287f425f213c @@ -1638,6 +1770,32 @@ packages: run_exports: {} size: 676888 timestamp: 1770456470072 +- conda: https://prefix.dev/conda-forge/noarch/tomli-2.5.0-pyh5ded981_0.conda + sha256: 93b6f517fb7adff00b62be02b798d384a1b34d0e368fdb576fb248bcb3bb9ec7 + md5: 36d6a162326c52d6339c8b606f43932d + depends: + - python >=3.11 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/tomli?source=compressed-mapping + run_exports: {} + size: 21687 + timestamp: 1791394576814 +- conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda + sha256: 2d888f90af0686044882c74193ec80a90ec1943145d94a7b1b048958acda1848 + md5: c70ad746c22219b9700931707482992c + depends: + - python >=3.10 + - python + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/typing-extensions?source=hash-mapping + run_exports: {} + size: 52631 + timestamp: 1783002732887 - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda sha256: b928c30ddcb0e3f544c6eade8352737e6e610e263276b90232db6a578ef899d8 md5: fcb489df604d100968b737f2cb6076c6 @@ -3079,7 +3237,7 @@ packages: - zstd >=1.5.7,<1.6.0a0 size: 387535 timestamp: 1786599623274 -- pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6#b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6 +- pypi: git+https://github.com/Tobias-Fischer/vinca.git?rev=cf6833a12f36509a90ea33d25766709bcc1eb2cf#cf6833a12f36509a90ea33d25766709bcc1eb2cf name: vinca version: 0.2.0 requires_dist: @@ -3223,23 +3381,11 @@ packages: - markupsafe>=2.0 - babel>=2.7 ; extra == 'i18n' requires_python: '>=3.7' -- pypi: https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl - name: packaging - version: '26.3' - sha256: d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/6c/ab/2f8488f0f817a39fca068d2b17daf446bf5cdb3eae28c3720af534d873b4/markupsafe-3.0.4-cp314-cp314-macosx_10_15_x86_64.whl name: markupsafe version: 3.0.4 sha256: 4cf3468d5ec187ffffcaca8e61929a37448f215dafc1386a12c750a72fe53634 requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl - name: pygments - version: 2.21.0 - sha256: 2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9 - requires_dist: - - colorama>=0.4.6 ; extra == 'windows-terminal' - requires_python: '>=3.9' - pypi: https://files.pythonhosted.org/packages/7c/8a/40db9aa9f5907bb0e6f8b6d64064bf8852fb33d4b813ff9414911df7647c/charset_normalizer-3.5.2-cp314-cp314-macosx_10_15_universal2.whl name: charset-normalizer version: 3.5.2 diff --git a/pixi.toml b/pixi.toml index 3db21828..db72b417 100644 --- a/pixi.toml +++ b/pixi.toml @@ -24,6 +24,7 @@ rattler-index = ">=0.27.16" pyyaml = "*" # Some git repos need git-lfs, see https://github.com/RoboStack/ros-jazzy/issues/118 git-lfs = "*" +pytest = ">=9.1.1,<10" [target.win-64.dependencies] # patch is required by rattler-build @@ -33,12 +34,13 @@ git = "*" [pypi-dependencies] # One vinca for all distributions. -# Tobias-Fischer/vinca robostack-integration (RoboStack/vinca#162 + extends, test selectors, gha fix) until merged upstream -vinca = { git = "https://github.com/Tobias-Fischer/vinca.git", rev = "b5c524bfc06221d8f9345ad851f7d4d9fd9b79b6" } +# Tobias-Fischer/vinca robostack-integration (extends, test selectors, gha fix, rebuild planner, mutex build number: RoboStack/vinca#163-#169) until merged upstream +vinca = { git = "https://github.com/Tobias-Fischer/vinca.git", rev = "cf6833a12f36509a90ea33d25766709bcc1eb2cf" } # For local development, temporarily use (and regenerate pixi.lock): # vinca = { path = "../vinca", editable = true } [tasks] rs = { cmd = "python tools/robostack.py", description = "Run a task for one distribution: `pixi run rs ` (generate-recipes, build, build-one, check-patches, check-deps, create-snapshot, render-pinning, sort, ...)." } sort = { cmd = "sh -lc 'vinca-sort-vinca-lists $@ shared/vinca.yaml && vinca-sort-yaml-keys $@ shared/robostack.yaml shared/pkg_additional_info.yaml shared/patch/dependencies.yaml && for d in distros/*/; do (cd $d && vinca-sort-vinca-lists $@ vinca.yaml && vinca-sort-yaml-keys $@ pkg_additional_info.yaml rosdistro_additional_recipes.yaml $(ls patch/dependencies.yaml 2>/dev/null)) || exit 1; done' --", description = "Sort the YAML files of all distributions (`--check` to only check)." } +test = { cmd = "python -m pytest tools/tests", description = "Unit tests of the repository tooling (tools/tests)." } render-pinning = { cmd = "sh -lc 'for d in distros/*/; do python tools/robostack.py $(basename $d) render-pinning || exit 1; done'", description = "Regenerate every distribution's conda_build_config.yaml from shared/pinning and its distro.yaml." } diff --git a/shared/vinca.yaml b/shared/vinca.yaml index 9649eea4..1644937c 100644 --- a/shared/vinca.yaml +++ b/shared/vinca.yaml @@ -6,17 +6,16 @@ conda_index: - robostack.yaml patch_dir: patch -# The distro mutex: every distribution sets its own version; its run_constraints -# replace the shared constraint on the same package and add others. +# The distro mutex: every distribution sets its own version. It only keeps one ROS +# distribution per environment: no run_constraints. Library versions follow from +# the packages' own dependencies (run_exports); where those are wrong, fix the +# package's metadata (patch/, pkg_additional_info.yaml, or a conda-forge repodata +# patch) instead. Mutex constraints applied to every user environment, also to +# packages it doesn't use, and made solvers fall back to old ROS builds when +# another library needed a different version. `rs check` rejects them. mutex_package: name: "ros2-distro-mutex" upper_bound: "x.x" - run_constraints: - - libboost 1.90.* - - libboost-devel 1.90.* - - pcl 1.15.1.* - - libprotobuf 7.35.1.* - - vtk 9.7.0.* # pixi used by the generated build workflows; keep in sync with .github/workflows. setup_pixi_version: "0.11.0" diff --git a/tools/maintenance.py b/tools/maintenance.py index 1f5132a1..15700dfb 100644 --- a/tools/maintenance.py +++ b/tools/maintenance.py @@ -90,57 +90,6 @@ def _ruamel(): return ry -def sync_mutex_constraints(distro: str) -> list[str]: - """Move ` .*` run_constraints of the mutex to the rendered pin of - the same package in conda_build_config.yaml; a shared constraint that no longer - matches gets an override in the distribution's vinca.yaml. Other constraints stay - as they are.""" - path = rs.DISTROS / distro / "vinca.yaml" - pins = yaml.safe_load((rs.DISTROS / distro / "conda_build_config.yaml").read_text()) or {} - changes: list[str] = [] - - def repl(m: re.Match) -> str: - name, old = m.group(2), m.group(3) - pin = pins.get(name.replace("-", "_")) - if not (isinstance(pin, list) and pin): - return m.group(0) - # same precision as before (`libprotobuf 7.35.*` stays at major.minor) - new = ".".join(str(pin[0]).split(".")[: len(old.split("."))]) - if new == old: - return m.group(0) - changes.append(f"`{name}` {old}.* → {new}.*") - return f"{m.group(1)}{name} {new}.*" - - text = path.read_text() - head, sep, rest = text.partition("run_constraints:") - if sep: - block = re.match(r"(?:[ \t]*(?:-.*|#.*)?\n)*", rest).group(0) - block_new = re.sub(r"(?m)^([ \t]*-[ \t]+)([A-Za-z0-9_.-]+) ([0-9][0-9.]*)\.\*[ \t]*$", repl, block) - text = head + sep + block_new + rest[len(block):] - - # constraints from shared/vinca.yaml that the distribution doesn't override: - # an outdated one gets an override in the distribution's file - own = (yaml.safe_load(text).get("mutex_package") or {}).get("run_constraints") or [] - own_names = {rs._constraint_name(c) for c in own} - shared = (rs.load_yaml(rs.SHARED / "vinca.yaml").get("mutex_package") or {}).get("run_constraints") or [] - overrides = [] - for constraint in shared: - m = re.fullmatch(r"([A-Za-z0-9_.-]+) ([0-9][0-9.]*)\.\*", str(constraint).strip()) - if not m or m.group(1) in own_names: - continue - line = repl(re.match(r"()(.*) (.*)", f"{m.group(1)} {m.group(2)}")) - if line != f"{m.group(1)} {m.group(2)}": - overrides.append(line) - if overrides: - lines = "".join(f" - {o}\n" for o in overrides) - if sep: - text = re.sub(r"(?m)^( run_constraints:\n)", lambda mm: mm.group(1) + lines, text, count=1) - else: - text = re.sub(r"(?m)^(mutex_package:\n(?:[ \t]+.*\n)*)", lambda mm: mm.group(1) + " run_constraints:\n" + lines, text, count=1) - path.write_text(text) - return changes - - REPODATA_SUBDIRS = ("noarch", "linux-64", "linux-aarch64", "osx-64", "osx-arm64", "win-64") @@ -240,10 +189,9 @@ def plan_rebuild(distro: str, old_cbc: str) -> tuple[dict[str, str], int]: return rebuild.plan(requirements, changed, prefix), len(requirements) -def bump_partial(distro: str, packages: dict[str, str], mutex_changed: bool) -> list[str]: +def bump_partial(distro: str, packages: dict[str, str]) -> list[str]: """Rebuild just these packages: a per-package build number above everything the - channel has, and, when its run_constraints changed, a new build of the mutex (its - version stays, so every other published package keeps working with it).""" + channel has. The mutex has no run_constraints, so it never needs a new build here.""" builds = released_builds(distro) current = int(re.search(r"(?m)^build_number:\s*(\d+)", (rs.DISTROS / distro / "vinca.yaml").read_text()).group(1)) released = released_build_number(distro, builds) @@ -260,29 +208,12 @@ def bump_partial(distro: str, packages: dict[str, str], mutex_changed: bool) -> entry["build_number"] = number with info.open("w") as fh: ry.dump(data, fh) - lines = [f"{len(packages)} packages get `build_number: {number}` in `distros/{distro}/pkg_additional_info.yaml`"] - - if mutex_changed: - path = rs.DISTROS / distro / "vinca.yaml" - text = path.read_text() - mutex = (rs.read_vinca(distro).get("mutex_package") or {}).get("name") - mutex_build = ((builds or {}).get(mutex, number - 1)) + 1 - block = re.search(r"(?m)^mutex_package:\n((?:[ \t]+.*\n|\n)*)", text) - if not block: - raise SystemExit(f"{path}: no mutex_package") - body = block.group(1) - if re.search(r"(?m)^ build_number:", body): - body = re.sub(r"(?m)^( build_number:\s*)\d+", rf"\g<1>{mutex_build}", body, count=1) - else: - body = f" build_number: {mutex_build}\n" + body - path.write_text(text[: block.start(1)] + body + text[block.end(1):]) - lines.append(f"mutex `{mutex}`: new build {mutex_build} with the updated run_constraints (same version)") - return lines + return [f"{len(packages)} packages get `build_number: {number}` in `distros/{distro}/pkg_additional_info.yaml`"] def dependency_conflicts(distro: str) -> set[str] | None: """Packages that can't be installed together with the rest of the distribution's - dependencies under its current pins and mutex constraints (check_dependency_compat.py, + dependencies under its current pins (check_dependency_compat.py, linux-64); None when the check itself failed.""" with tempfile.TemporaryDirectory() as tmp: out = Path(tmp) / "conflicts.json" @@ -494,22 +425,19 @@ def update_pinning(distro: str) -> Result: if cbc.read_text() == before_cbc: lines.append("The rendered pins don't change: nothing to rebuild.") else: - constraints = sync_mutex_constraints(distro) print(f"Planning the rebuild of {distro}", flush=True) packages, total = plan_rebuild(distro, before_cbc) - if not packages and not constraints: + if not packages: lines.append("The pins change, but no package uses them: nothing to rebuild.") elif total and len(packages) > FULL_REBUILD_SHARE * total: lines.append(f"**Full rebuild**: {len(packages)} of {total} packages use a changed pin or depend " "on one. " + "; ".join(bump_rebuild(distro))) else: lines.append(f"**Rebuild {len(packages)} of {total} packages** (they use a changed pin or depend " - "on one): " + "; ".join(bump_partial(distro, packages, bool(constraints)))) + "on one): " + "; ".join(bump_partial(distro, packages))) if packages: lines += ["", *_details(f"Packages to rebuild ({len(packages)})", [ f"- `{name}`: {reason}" for name, reason in sorted(packages.items())])] - if constraints: - lines += ["", "Mutex run_constraints: " + ", ".join(constraints)] conflicts_after = dependency_conflicts(distro) if conflicts_after is None or conflicts_before is None: conflicts = conflicts_after is None @@ -754,6 +682,15 @@ def _form_fields(body: str) -> dict[str, str]: return fields +def mutex_problems(vinca: dict) -> list[str]: + """The mutex only keeps one distribution per environment: library versions come + from the packages' own metadata (see shared/vinca.yaml), not from run_constraints.""" + if (vinca.get("mutex_package") or {}).get("run_constraints"): + return ["mutex_package.run_constraints must stay empty; fix the dependencies of the affected " + "packages instead (see shared/vinca.yaml)"] + return [] + + def check() -> Result: """Sanity checks: every distribution assembles and its generated files are consistent.""" problems: list[str] = [] @@ -781,6 +718,7 @@ def check() -> Result: for key in ("build_number", "mutex_package", "packages_select_by_deps"): if not vinca.get(key): problems.append(f"{distro}: vinca.yaml has no {key}") + problems += [f"{distro}: {p}" for p in mutex_problems(vinca)] for patch in (d / "patch").glob("*.patch"): if not re.match(r"^ros2-[a-z0-9-]+(\.(osx|linux|win|unix|emscripten))?\.patch$", patch.name): problems.append(f"{distro}: patch {patch.name} should be named ros2-[.].patch") diff --git a/tools/robostack.py b/tools/robostack.py index 2dd515ba..40ddd722 100644 --- a/tools/robostack.py +++ b/tools/robostack.py @@ -141,10 +141,6 @@ def load_yaml(path: Path) -> dict: return (yaml.safe_load(path.read_text()) or {}) if path.is_file() else {} -def _constraint_name(spec: str) -> str: - return re.split(r"[\s=<>!~]", str(spec).strip(), maxsplit=1)[0] - - # package lists of vinca.yaml (import_distro strips the shared entries) LIST_KEYS = ("packages_select_by_deps", "packages_exclude", "packages_skip") diff --git a/tools/tests/conftest.py b/tools/tests/conftest.py new file mode 100644 index 00000000..687490bc --- /dev/null +++ b/tools/tests/conftest.py @@ -0,0 +1,5 @@ +import sys +from pathlib import Path + +# the tools are scripts, not a package +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) diff --git a/tools/tests/test_mutex.py b/tools/tests/test_mutex.py new file mode 100644 index 00000000..641858d9 --- /dev/null +++ b/tools/tests/test_mutex.py @@ -0,0 +1,46 @@ +"""The distro mutex keeps one ROS distribution per environment and nothing else: +library versions come from the packages' own dependencies.""" + +import pytest + +import maintenance +import robostack as rs + + +def test_mutex_without_constraints_is_fine(): + assert maintenance.mutex_problems({"mutex_package": {"name": "ros2-distro-mutex", "run_constraints": []}}) == [] + assert maintenance.mutex_problems({"mutex_package": {"name": "ros2-distro-mutex"}}) == [] + assert maintenance.mutex_problems({}) == [] + + +def test_mutex_constraints_are_rejected(): + problems = maintenance.mutex_problems({"mutex_package": {"run_constraints": ["libprotobuf 7.35.*"]}}) + assert len(problems) == 1 + assert "run_constraints must stay empty" in problems[0] + + +@pytest.mark.parametrize("distro", rs.distros()) +def test_no_distribution_constrains_its_mutex(distro): + # shared/vinca.yaml and the distribution's vinca.yaml as vinca combines them + vinca = rs.read_vinca(distro, "linux-64") + assert maintenance.mutex_problems(vinca) == [] + + +def test_partial_rebuild_leaves_the_mutex_alone(tmp_path, monkeypatch): + distro = tmp_path / "distros" / "testdistro" + distro.mkdir(parents=True) + vinca = "ros_distro: testdistro\nbuild_number: 5\n\nmutex_package:\n version: \"0.3.0\"\n" + (distro / "vinca.yaml").write_text(vinca) + (distro / "pkg_additional_info.yaml").write_text("rclcpp:\n build_number: 3\n add_host: [foo]\n") + monkeypatch.setattr(rs, "DISTROS", tmp_path / "distros") + monkeypatch.setattr(maintenance, "released_builds", lambda d: { + "ros2-rclcpp": 7, "ros-testdistro-std-msgs": 6, "ros2-distro-mutex": 40, "libfoo": 99}) + monkeypatch.setattr(rs, "read_vinca", lambda d, platform=None: {"mutex_package": {"name": "ros2-distro-mutex"}}) + + lines = maintenance.bump_partial("testdistro", {"rclcpp": "uses libboost", "std_msgs": "depends on rclcpp"}) + + # above every released ROS package (7), ignoring the mutex and non-ROS packages + assert lines == ["2 packages get `build_number: 8` in `distros/testdistro/pkg_additional_info.yaml`"] + info = maintenance.yaml.safe_load((distro / "pkg_additional_info.yaml").read_text()) + assert info == {"rclcpp": {"build_number": 8, "add_host": ["foo"]}, "std_msgs": {"build_number": 8}} + assert (distro / "vinca.yaml").read_text() == vinca