Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions .github/workflows/testpr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ jobs:
# while uploads go to a test channel, packages already there aren't built again
ROBOSTACK_UPLOAD_CHANNEL: ${{ vars.ROBOSTACK_UPLOAD_CHANNEL }}
# rattler-build writes to distros/<d>/work/output, or to CONDA_BLD_PATH (win-64)
CACHE_DIR: ${{ matrix.target.platform == 'win-64' && 'C:/bld/win-64' || format('distros/{0}/work/output/{1}', matrix.distro, matrix.target.platform) }}
CACHE_DIR: ${{ matrix.target.platform == 'win-64' && 'D:/bld/win-64' || format('distros/{0}/work/output/{1}', matrix.distro, matrix.target.platform) }}
steps:
- uses: actions/checkout@v6
with:
Expand All @@ -167,6 +167,11 @@ jobs:
# (e.g. vinca's), which breaks every later run restoring that cache
- name: Disable git auto-maintenance
run: git config --global maintenance.auto false && git config --global gc.auto 0 && git config --global core.longpaths true
# pixi's package cache on D:, with the builds' (see the Windows step below)
- name: "pixi's cache on D:"
if: runner.os == 'Windows'
shell: pwsh
run: '"PIXI_CACHE_DIR=D:\pixi-cache" | Out-File -FilePath $env:GITHUB_ENV -Append'
- uses: prefix-dev/setup-pixi@v0.11.0
with:
locked: true # the lock file must match pixi.toml
Expand All @@ -177,12 +182,25 @@ jobs:
if: runner.os == 'Windows'
shell: pwsh
run: |
"CONDA_BLD_PATH=C:\bld\" | Out-File -FilePath $env:GITHUB_ENV -Append
New-Item -ItemType Directory -Force -Path C:\bld | Out-Null
# Defender's real-time scan slows down installing and deleting the environments'
# files several times over; the runner is thrown away after the job
Set-MpPreference -DisableRealtimeMonitoring $true
# the builds, rattler's package cache (on the same drive, for hardlinks) and the
# temporary files on D:, about three times as fast as C: on GitHub's runners
"CONDA_BLD_PATH=D:\bld\", "RATTLER_CACHE_DIR=D:\rattler", "TMP=D:\tmp", "TEMP=D:\tmp" |
Out-File -FilePath $env:GITHUB_ENV -Append
New-Item -ItemType Directory -Force -Path D:\bld, D:\rattler, D:\tmp | Out-Null
Get-PSDrive C, D | Format-Table Name, @{n="free GB"; e={[math]::Round($_.Free / 1GB)}}
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
Remove-Item -Recurse -Force C:\Strawberry -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force "C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0" -ErrorAction SilentlyContinue

# Spotlight indexes every file the environments and builds write, using up to a
# core or two of the runner's three or four; the runner is thrown away after the job
- name: Turn off Spotlight
if: runner.os == 'macOS'
run: sudo mdutil -a -i off || true

- name: Clean up PATH
if: runner.os == 'Windows'
uses: egor-tensin/cleanup-path@v5
Expand Down Expand Up @@ -242,6 +260,9 @@ jobs:
extra=()
# shorter work dirs for MAX_PATH on Windows
[ "$PLATFORM" == "win-64" ] && extra+=(--no-build-id)
# independent recipes side by side, with a shared jobserver keeping them at the
# runner's cores in total; Windows has no jobserver, and was no faster with two
[ "$PLATFORM" != "win-64" ] && extra+=(--parallel-builds "3:$(getconf _NPROCESSORS_ONLN)")
pixi run rs "$DISTRO" build --target-platform "$PLATFORM" "${extra[@]}" 2>&1 | tee rattler-build.log
status=${PIPESTATUS[0]}
echo "exit-code=${status}" >> "$GITHUB_OUTPUT"
Expand Down
13 changes: 8 additions & 5 deletions .scripts/build_unix.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,19 @@ export "CONDA_BLD_PATH=$HOME/conda-bld/"

if [[ "$target" == *"osx"* ]]; then
echo "osx"
# Spotlight indexes every file the environments and builds write, using up to a
# core or two of the runner's three or four; the runner is thrown away after the job
sudo mdutil -a -i off || true
export PATH=$(echo $PATH | tr ":" "\n" | grep -v 'homebrew' | xargs | tr ' ' ':')
fi

# All of the job's recipes in one build-ci run (tools/robostack.py), which builds
# independent ones in parallel and adds the variant config and the distro's channels.
recipe_args=()
for recipe in ${CURRENT_RECIPES[@]}; do
# build-ci (tools/robostack.py) adds the variant config and the distro's channels.
pixi run -v rs "${ROBOSTACK_DISTRO}" build-ci \
--recipe ${FEEDSTOCK_ROOT}/recipes/${recipe} \
--output-dir $CONDA_BLD_PATH

recipe_args+=(--recipe "${FEEDSTOCK_ROOT}/recipes/${recipe}")
done
pixi run -v rs "${ROBOSTACK_DISTRO}" build-ci "${recipe_args[@]}" --output-dir $CONDA_BLD_PATH

# Check if it build something, this is a hotfix for the skips inside additional_recipes
shopt -s nullglob
Expand Down
30 changes: 19 additions & 11 deletions .scripts/build_win.bat
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@

setlocal EnableExtensions EnableDelayedExpansion

set CONDA_BLD_PATH=C:\bld
:: Defender's real-time scan slows down installing and deleting the environments'
:: files several times over; the runner is thrown away after the job
powershell -NoProfile -Command "Set-MpPreference -DisableRealtimeMonitoring $true"

:: The builds, rattler's package cache (on the same drive, for hardlinks) and the
:: temporary files on D:, about three times as fast as C: on GitHub's runners
set CONDA_BLD_PATH=D:\bld
set VINCA_CUSTOM_CMAKE_BUILD_DIR=D:\x\
set RATTLER_CACHE_DIR=D:\rattler
set TMP=D:\tmp
set TEMP=D:\tmp
mkdir D:\tmp
powershell -NoProfile -Command "Get-PSDrive C, D | Format-Table Name, @{n='free GB'; e={[math]::Round($_.Free / 1GB)}}"
echo "PATH is %PATH%"

rmdir /Q/S C:\Strawberry\
Expand All @@ -18,16 +30,12 @@ reg add HKLM\SYSTEM\CurrentControlSet\Control\FileSystem /v LongPathsEnabled /t
:: ... and in git, for sources that vendor packages clone during the build
git config --global core.longpaths true

for %%X in (%CURRENT_RECIPES%) do (
echo "BUILDING RECIPE %%X"
cd %FEEDSTOCK_ROOT%\recipes\%%X\
rem build-ci (tools/robostack.py) adds the variant config and the distro's channels.
pixi run -v rs %ROBOSTACK_DISTRO% build-ci --recipe %FEEDSTOCK_ROOT%\recipes\%%X\ ^
--output-dir %CONDA_BLD_PATH%

if errorlevel 1 exit 1
rem -m %FEEDSTOCK_ROOT%\.ci_support\conda_forge_pinnings.yaml
)
:: All of the job's recipes in one build-ci run (tools/robostack.py), which builds
:: independent ones in parallel and adds the variant config and the distro's channels.
set RECIPE_ARGS=
for %%X in (%CURRENT_RECIPES%) do set "RECIPE_ARGS=!RECIPE_ARGS! --recipe %FEEDSTOCK_ROOT%\recipes\%%X\"
pixi run -v rs %ROBOSTACK_DISTRO% build-ci !RECIPE_ARGS! --output-dir %CONDA_BLD_PATH%
if errorlevel 1 exit 1

:: Check if .conda files exist in the win-64 directory
if exist "%CONDA_BLD_PATH%\win-64\*.conda" (
Expand Down
68 changes: 34 additions & 34 deletions pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ PYTHONIOENCODING = "utf-8"

[dependencies]
python = ">=3.14.0,<3.15"
rattler-build = ">=0.76.1,<0.77"
rattler-build = ">=0.77.0,<0.78"
cmake = "<4.0"
setuptools = "<82.0"
rattler-index = ">=0.27.16"
Expand Down
20 changes: 14 additions & 6 deletions tools/build_timings.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,18 +87,26 @@ def dumps(recipes: dict) -> str:
return "{\n" + ",\n".join(lines) + "\n}\n"


def vinca_timings(distro: str, platform: str, path: Path) -> bool:
"""Write vinca-gha's --timings file for the platform: each recipe's average over the
distributions, and ALIAS_SECONDS for the distribution's compatibility recipes
(ros-<distro>-<name>, built right after ros2-<name>). False when there are no times yet."""
def timings(distro: str, platform: str) -> dict | None:
"""{"recipes": {recipe: seconds}, "default": seconds} for the platform: each recipe's
average over the distributions, and ALIAS_SECONDS for the distribution's compatibility
recipes (ros-<distro>-<name>, built right after ros2-<name>). None without times yet."""
source = TIMINGS / f"{platform}.json"
if not source.is_file():
return False
return None
recipes = {r: round(statistics.fmean(by.values()), 1) for r, by in json.loads(source.read_text()).items()}
# unmeasured recipes: the median of the packages (ros2-*)
default = statistics.median([s for r, s in recipes.items() if r.startswith("ros2-")] or list(recipes.values()))
recipes.update({f"ros-{distro}-{r[len('ros2-'):]}": ALIAS_SECONDS for r in list(recipes) if r.startswith("ros2-")})
path.write_text(json.dumps({"recipes": recipes, "default": default}) + "\n")
return {"recipes": recipes, "default": default}


def vinca_timings(distro: str, platform: str, path: Path) -> bool:
"""Write vinca-gha's --timings file for the platform (timings()); False when there are
no times yet."""
if (data := timings(distro, platform)) is None:
return False
path.write_text(json.dumps(data) + "\n")
return True


Expand Down
16 changes: 12 additions & 4 deletions tools/ci_estimate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
python tools/ci_estimate.py --recipes distros/<d>/work/recipes --cache-dir <dir> --platform <p>

Recipes whose package is in the restored cache are skipped by rattler-build; the rest
are built. The seconds per package below are rough averages from the jazzy full
rebuild in October 2026 (wall clock of the build step, including environment setup):
building one package, and skipping one that is already in the cache.
are built, each taking its measured time (shared/build_timings, see build_timings.py).
The seconds per package below are rough averages from the jazzy full rebuild in October
2026 (wall clock of the build step, including environment setup): building one package,
for platforms without measured times, and skipping one that is already in the cache.
"""

import argparse
Expand All @@ -14,6 +15,8 @@
import sys
from pathlib import Path

import build_timings

SECONDS = { # platform: (per built package, per skipped package)
"linux-64": (19, 2),
"linux-aarch64": (21, 3),
Expand Down Expand Up @@ -45,7 +48,12 @@ def main() -> int:
to_build = sorted(recipes - cached)
skipped = len(recipes & cached)
build, skip = SECONDS.get(args.platform, max(SECONDS.values()))
seconds = len(to_build) * build + skipped * skip
distro = args.recipes.resolve().parent.parent.name # distros/<distro>/work/recipes
measured = build_timings.timings(distro, args.platform)
if measured:
seconds = sum(measured["recipes"].get(r, measured["default"]) for r in to_build) + skipped * skip
else:
seconds = len(to_build) * build + skipped * skip
hours = seconds / 3600
rounds = int(hours // JOB_LIMIT_HOURS) + 1
done = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=seconds)
Expand Down
Loading
Loading