diff --git a/.azure-pipelines/azure-pipelines-osx.yml b/.azure-pipelines/azure-pipelines-osx.yml
index 91fc823..d10ee3e 100755
--- a/.azure-pipelines/azure-pipelines-osx.yml
+++ b/.azure-pipelines/azure-pipelines-osx.yml
@@ -12,7 +12,14 @@ jobs:
CONFIG: osx_64_
UPLOAD_PACKAGES: 'True'
VMIMAGE: macOS-15
- store_build_artifacts: false
+ store_build_artifacts: true
+ SHORT_CONFIG: osx_64_
+ osx_arm64_:
+ CONFIG: osx_arm64_
+ UPLOAD_PACKAGES: 'True'
+ VMIMAGE: macOS-15-arm64
+ store_build_artifacts: true
+ SHORT_CONFIG: osx_arm64_
timeoutInMinutes: 360
variables: {}
@@ -37,3 +44,33 @@ jobs:
BINSTAR_TOKEN: $(BINSTAR_TOKEN)
FEEDSTOCK_TOKEN: $(FEEDSTOCK_TOKEN)
STAGING_BINSTAR_TOKEN: $(STAGING_BINSTAR_TOKEN)
+
+ - script: |
+ export CI=azure
+ export CI_RUN_ID=$(build.BuildNumber).$(system.JobAttempt)
+ export FEEDSTOCK_NAME=$(basename ${BUILD_REPOSITORY_NAME})
+ export CONDA_BLD_PATH=/Users/runner/miniforge3/conda-bld
+ export ARTIFACT_STAGING_DIR="$(Build.ArtifactStagingDirectory)"
+ # Archive everything in CONDA_BLD_PATH except environments
+ export BLD_ARTIFACT_PREFIX=conda_artifacts
+ if [[ "$AGENT_JOBSTATUS" == "Failed" ]]; then
+ # Archive the CONDA_BLD_PATH environments only when the job fails
+ export ENV_ARTIFACT_PREFIX=conda_envs
+ fi
+ ./.scripts/create_conda_build_artifacts.sh
+ displayName: Prepare conda build artifacts
+ condition: and(succeededOrFailed(), eq(variables.store_build_artifacts, true))
+
+ - task: PublishPipelineArtifact@1
+ displayName: Store conda build artifacts
+ condition: not(eq(variables.BLD_ARTIFACT_PATH, ''))
+ inputs:
+ targetPath: $(BLD_ARTIFACT_PATH)
+ artifactName: $(BLD_ARTIFACT_NAME)
+
+ - task: PublishPipelineArtifact@1
+ displayName: Store conda build environment artifacts
+ condition: not(eq(variables.ENV_ARTIFACT_PATH, ''))
+ inputs:
+ targetPath: $(ENV_ARTIFACT_PATH)
+ artifactName: $(ENV_ARTIFACT_NAME)
diff --git a/.ci_support/linux_aarch64_.yaml b/.ci_support/linux_aarch64_.yaml
new file mode 100644
index 0000000..dafa219
--- /dev/null
+++ b/.ci_support/linux_aarch64_.yaml
@@ -0,0 +1,33 @@
+c_compiler:
+- gcc
+c_compiler_version:
+- '14'
+c_stdlib:
+- sysroot
+c_stdlib_version:
+- '2.17'
+channel_sources:
+- conda-forge
+channel_targets:
+- conda-forge main
+cxx_compiler:
+- gxx
+cxx_compiler_version:
+- '14'
+docker_image:
+- quay.io/condaforge/linux-anvil-aarch64:alma9
+pin_run_as_build:
+ python:
+ min_pin: x.x
+ max_pin: x.x
+python:
+- 3.10.* *_cpython
+- 3.11.* *_cpython
+- 3.12.* *_cpython
+- 3.13.* *_cp313
+- 3.14.* *_cp314
+target_platform:
+- linux-aarch64
+zip_keys:
+- - c_compiler_version
+ - cxx_compiler_version
diff --git a/.ci_support/osx_arm64_.yaml b/.ci_support/osx_arm64_.yaml
new file mode 100644
index 0000000..1c4e1f1
--- /dev/null
+++ b/.ci_support/osx_arm64_.yaml
@@ -0,0 +1,39 @@
+MACOSX_DEPLOYMENT_TARGET:
+- '11.0'
+MACOSX_SDK_VERSION:
+- '11.0'
+c_compiler:
+- clang
+c_compiler_version:
+- '19'
+c_stdlib:
+- macosx_deployment_target
+c_stdlib_version:
+- '11.0'
+channel_sources:
+- conda-forge
+channel_targets:
+- conda-forge main
+cxx_compiler:
+- clangxx
+cxx_compiler_version:
+- '19'
+llvm_openmp:
+- '19'
+macos_machine:
+- arm64-apple-darwin20.0.0
+pin_run_as_build:
+ python:
+ min_pin: x.x
+ max_pin: x.x
+python:
+- 3.10.* *_cpython
+- 3.11.* *_cpython
+- 3.12.* *_cpython
+- 3.13.* *_cp313
+- 3.14.* *_cp314
+target_platform:
+- osx-arm64
+zip_keys:
+- - c_compiler_version
+ - cxx_compiler_version
diff --git a/.github/workflows/conda-build.yml b/.github/workflows/conda-build.yml
index 4b12dcf..c175e84 100644
--- a/.github/workflows/conda-build.yml
+++ b/.github/workflows/conda-build.yml
@@ -23,11 +23,19 @@ jobs:
matrix:
include:
- CONFIG: linux_64_
- STORE_BUILD_ARTIFACTS: False
+ STORE_BUILD_ARTIFACTS: True
+ SHORT_CONFIG: linux_64_
UPLOAD_PACKAGES: True
os: ubuntu
runs_on: ['ubuntu-latest']
DOCKER_IMAGE: quay.io/condaforge/linux-anvil-x86_64:alma9
+ - CONFIG: linux_aarch64_
+ STORE_BUILD_ARTIFACTS: True
+ SHORT_CONFIG: linux_aarch64_
+ UPLOAD_PACKAGES: True
+ os: ubuntu
+ runs_on: ['ubuntu-24.04-arm']
+ DOCKER_IMAGE: quay.io/condaforge/linux-anvil-aarch64:alma9
steps:
- name: Checkout code
@@ -108,4 +116,85 @@ jobs:
UPLOAD_PACKAGES: ${{ matrix.UPLOAD_PACKAGES }}
BINSTAR_TOKEN: ${{ secrets.BINSTAR_TOKEN }}
FEEDSTOCK_TOKEN: ${{ secrets.FEEDSTOCK_TOKEN }}
- STAGING_BINSTAR_TOKEN: ${{ secrets.STAGING_BINSTAR_TOKEN }}
\ No newline at end of file
+ STAGING_BINSTAR_TOKEN: ${{ secrets.STAGING_BINSTAR_TOKEN }}
+
+ - name: Determine build outcome
+ # this is to merge the status of the linux/osx/win builds into
+ # something we can easily reuse during artefact generation
+ id: determine-status
+ if: ${{ always() }}
+ shell: bash
+ env:
+ OS: ${{ matrix.os }}
+ run: |
+ if [[ "$OS" == "ubuntu" ]]; then
+ STATUS=${{ steps.build-linux.outcome }}
+ elif [[ "$OS" == "macos" ]]; then
+ STATUS=${{ steps.build-macos.outcome }}
+ elif [[ "$OS" == "windows" ]]; then
+ STATUS=${{ steps.build-windows.outcome }}
+ fi
+ if [ -z "$STATUS" ]; then
+ # steps that never ran will have empty status
+ STATUS="cancelled"
+ fi
+ echo "status=$STATUS" >> $GITHUB_OUTPUT
+
+ - name: Prepare conda build artifacts
+ continue-on-error: true
+ id: prepare-artifacts
+ shell: bash
+ # we do not want to trigger artefact creation if the build was cancelled
+ if: ${{ always() && steps.determine-status.outputs.status != 'cancelled' && matrix.STORE_BUILD_ARTIFACTS }}
+ env:
+ CI: github_actions
+ CONFIG: ${{ matrix.CONFIG }}
+ SHORT_CONFIG: ${{ matrix.SHORT_CONFIG }}
+ JOB_STATUS: ${{ steps.determine-status.outputs.status }}
+ OS: ${{ matrix.os }}
+ run: |
+ export CI_RUN_ID=$GITHUB_RUN_ID
+ export FEEDSTOCK_NAME="$(basename $GITHUB_REPOSITORY)"
+ export ARTIFACT_STAGING_DIR="$GITHUB_WORKSPACE"
+ if [ $OS == "macos" ]; then
+ export CONDA_BLD_PATH="${MINIFORGE_HOME:-${HOME}/miniforge3}/conda-bld"
+ elif [ $OS == "windows" ]; then
+ # this needs to be consistent with build step, see above
+ export CONDA_BLD_PATH="C:\\bld"
+ else
+ export CONDA_BLD_PATH="build_artifacts"
+ fi
+ # Archive everything in CONDA_BLD_PATH except environments
+ # Archive the CONDA_BLD_PATH environments only when the job fails
+ # Use different prefix for successful and failed build artifacts
+ # so random failures don't prevent rebuilds from creating artifacts.
+ if [ $JOB_STATUS == "failure" ]; then
+ export BLD_ARTIFACT_PREFIX="conda_artifacts"
+ export ENV_ARTIFACT_PREFIX="conda_envs"
+ else
+ export BLD_ARTIFACT_PREFIX="conda_pkgs"
+ fi
+ if [ $OS == "windows" ]; then
+ pwsh -Command ". '.scripts/create_conda_build_artifacts.bat'"
+ else
+ ./.scripts/create_conda_build_artifacts.sh
+ fi
+
+ - name: Store conda build artifacts
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ if: ${{ always() && steps.prepare-artifacts.outcome == 'success' }}
+ with:
+ name: ${{ steps.prepare-artifacts.outputs.BLD_ARTIFACT_NAME }}
+ path: ${{ steps.prepare-artifacts.outputs.BLD_ARTIFACT_PATH }}
+ retention-days: 14
+ continue-on-error: true
+
+ - name: Store conda build environment artifacts
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
+ # only relevant if build failed, see above
+ if: ${{ always() && steps.determine-status.outputs.status == 'failure' && steps.prepare-artifacts.outcome == 'success' }}
+ with:
+ name: ${{ steps.prepare-artifacts.outputs.ENV_ARTIFACT_NAME }}
+ path: ${{ steps.prepare-artifacts.outputs.ENV_ARTIFACT_PATH }}
+ retention-days: 14
+ continue-on-error: true
\ No newline at end of file
diff --git a/.scripts/build_steps.sh b/.scripts/build_steps.sh
index 80306f8..ce848e2 100755
--- a/.scripts/build_steps.sh
+++ b/.scripts/build_steps.sh
@@ -32,11 +32,19 @@ pkgs_dirs:
solver: libmamba
CONDARC
-mv /opt/conda/conda-meta/history /opt/conda/conda-meta/history.$(date +%Y-%m-%d-%H-%M-%S)
-echo > /opt/conda/conda-meta/history
-micromamba install --root-prefix ~/.conda --prefix /opt/conda \
- --yes --override-channels --channel conda-forge --strict-channel-priority \
- pip rattler-build conda-forge-ci-setup=4 "conda-build>=24.1"
+pushd "${FEEDSTOCK_ROOT}"
+arch=$(uname -m)
+if [[ "$arch" == "x86_64" ]]; then
+ arch="64"
+fi
+sed -i.bak -e "s/platforms = .*/platforms = [\"linux-${arch}\"]/" -e "s/# __PLATFORM_SPECIFIC_ENV__ =/docker-build-linux-$arch =/" pixi.toml
+echo "Creating environment"
+PIXI_CACHE_DIR=/opt/conda pixi install --environment docker-build-linux-$arch
+pixi list
+echo "Activating environment"
+eval "$(pixi shell-hook --environment docker-build-linux-$arch)"
+mv pixi.toml.bak pixi.toml
+popd
export CONDA_LIBMAMBA_SOLVER_NO_CHANNELS_FROM_INSTALLED=1
# set up the condarc
diff --git a/.scripts/create_conda_build_artifacts.sh b/.scripts/create_conda_build_artifacts.sh
new file mode 100755
index 0000000..1e3acc7
--- /dev/null
+++ b/.scripts/create_conda_build_artifacts.sh
@@ -0,0 +1,113 @@
+#!/usr/bin/env bash
+
+# INPUTS (environment variables that need to be set before calling this script):
+#
+# CI (azure/github_actions/UNSET)
+# CI_RUN_ID (unique identifier for the CI job run)
+# FEEDSTOCK_NAME
+# CONFIG (build matrix configuration string)
+# SHORT_CONFIG (uniquely-shortened configuration string)
+# CONDA_BLD_PATH (path to the conda-bld directory)
+# ARTIFACT_STAGING_DIR (use working directory if unset)
+# BLD_ARTIFACT_PREFIX (prefix for the conda build artifact name, skip if unset)
+# ENV_ARTIFACT_PREFIX (prefix for the conda build environments artifact name, skip if unset)
+
+# OUTPUTS
+#
+# BLD_ARTIFACT_NAME
+# BLD_ARTIFACT_PATH
+# ENV_ARTIFACT_NAME
+# ENV_ARTIFACT_PATH
+
+source .scripts/logging_utils.sh
+
+# DON'T do set -x, because it results in double echo-ing pipeline commands
+# and that might end up inserting extraneous quotation marks in output variables
+set -e
+
+# Check that the conda-build directory exists
+if [ ! -d "$CONDA_BLD_PATH" ]; then
+ echo "conda-build directory does not exist"
+ exit 1
+fi
+
+# Set staging dir to the working dir, in Windows style if applicable
+if [[ -z "${ARTIFACT_STAGING_DIR}" ]]; then
+ if pwd -W; then
+ ARTIFACT_STAGING_DIR=$(pwd -W)
+ else
+ ARTIFACT_STAGING_DIR=$PWD
+ fi
+fi
+echo "ARTIFACT_STAGING_DIR: $ARTIFACT_STAGING_DIR"
+
+FEEDSTOCK_ROOT=$(cd "$(dirname "$0")/.."; pwd;)
+if [ -z ${FEEDSTOCK_NAME} ]; then
+ export FEEDSTOCK_NAME=$(basename ${FEEDSTOCK_ROOT})
+fi
+
+# Set a unique ID for the artifact(s), specialized for this particular job run
+ARTIFACT_UNIQUE_ID="${CI_RUN_ID}_${CONFIG}"
+if [[ ${#ARTIFACT_UNIQUE_ID} -gt 80 ]]; then
+ ARTIFACT_UNIQUE_ID="${CI_RUN_ID}_${SHORT_CONFIG}"
+fi
+echo "ARTIFACT_UNIQUE_ID: $ARTIFACT_UNIQUE_ID"
+
+# Set a descriptive ID for the archive(s), specialized for this particular job run
+ARCHIVE_UNIQUE_ID="${CI_RUN_ID}_${CONFIG}"
+
+# Make the build artifact zip
+if [[ ! -z "$BLD_ARTIFACT_PREFIX" ]]; then
+ export BLD_ARTIFACT_NAME="${BLD_ARTIFACT_PREFIX}_${ARTIFACT_UNIQUE_ID}"
+ export BLD_ARTIFACT_PATH="${ARTIFACT_STAGING_DIR}/${FEEDSTOCK_NAME}_${BLD_ARTIFACT_PREFIX}_${ARCHIVE_UNIQUE_ID}.zip"
+
+ ( startgroup "Archive conda build directory" ) 2> /dev/null
+
+ # Try 7z and fall back to zip if it fails (for cross-platform use)
+ if ! 7z a "$BLD_ARTIFACT_PATH" "$CONDA_BLD_PATH" '-xr!.git/' '-xr!_*_env*/' '-xr!*_cache/' -bb; then
+ pushd "$CONDA_BLD_PATH"
+ zip -r -y -T "$BLD_ARTIFACT_PATH" . -x '*.git/*' '*_*_env*/*' '*_cache/*'
+ popd
+ fi
+
+ ( endgroup "Archive conda build directory" ) 2> /dev/null
+
+ echo "BLD_ARTIFACT_NAME: $BLD_ARTIFACT_NAME"
+ echo "BLD_ARTIFACT_PATH: $BLD_ARTIFACT_PATH"
+
+ if [[ "$CI" == "azure" ]]; then
+ echo "##vso[task.setVariable variable=BLD_ARTIFACT_NAME]$BLD_ARTIFACT_NAME"
+ echo "##vso[task.setVariable variable=BLD_ARTIFACT_PATH]$BLD_ARTIFACT_PATH"
+ elif [[ "$CI" == "github_actions" ]]; then
+ echo "BLD_ARTIFACT_NAME=$BLD_ARTIFACT_NAME" >> $GITHUB_OUTPUT
+ echo "BLD_ARTIFACT_PATH=$BLD_ARTIFACT_PATH" >> $GITHUB_OUTPUT
+ fi
+fi
+
+# Make the environments artifact zip
+if [[ ! -z "$ENV_ARTIFACT_PREFIX" ]]; then
+ export ENV_ARTIFACT_NAME="${ENV_ARTIFACT_PREFIX}_${ARTIFACT_UNIQUE_ID}"
+ export ENV_ARTIFACT_PATH="${ARTIFACT_STAGING_DIR}/${FEEDSTOCK_NAME}_${ENV_ARTIFACT_PREFIX}_${ARCHIVE_UNIQUE_ID}.zip"
+
+ ( startgroup "Archive conda build environments" ) 2> /dev/null
+
+ # Try 7z and fall back to zip if it fails (for cross-platform use)
+ if ! 7z a "$ENV_ARTIFACT_PATH" -r "$CONDA_BLD_PATH"/'_*_env*/' -bb; then
+ pushd "$CONDA_BLD_PATH"
+ zip -r -y -T "$ENV_ARTIFACT_PATH" . -i '*_*_env*/*'
+ popd
+ fi
+
+ ( endgroup "Archive conda build environments" ) 2> /dev/null
+
+ echo "ENV_ARTIFACT_NAME: $ENV_ARTIFACT_NAME"
+ echo "ENV_ARTIFACT_PATH: $ENV_ARTIFACT_PATH"
+
+ if [[ "$CI" == "azure" ]]; then
+ echo "##vso[task.setVariable variable=ENV_ARTIFACT_NAME]$ENV_ARTIFACT_NAME"
+ echo "##vso[task.setVariable variable=ENV_ARTIFACT_PATH]$ENV_ARTIFACT_PATH"
+ elif [[ "$CI" == "github_actions" ]]; then
+ echo "ENV_ARTIFACT_NAME=$ENV_ARTIFACT_NAME" >> $GITHUB_OUTPUT
+ echo "ENV_ARTIFACT_PATH=$ENV_ARTIFACT_PATH" >> $GITHUB_OUTPUT
+ fi
+fi
diff --git a/.scripts/run_osx_build.sh b/.scripts/run_osx_build.sh
index 3369f62..709bb00 100755
--- a/.scripts/run_osx_build.sh
+++ b/.scripts/run_osx_build.sh
@@ -9,34 +9,24 @@ set -xe
MINIFORGE_HOME="${MINIFORGE_HOME:-${HOME}/miniforge3}"
MINIFORGE_HOME="${MINIFORGE_HOME%/}" # remove trailing slash
export CONDA_BLD_PATH="${CONDA_BLD_PATH:-${MINIFORGE_HOME}/conda-bld}"
-
-( startgroup "Provisioning base env with micromamba" ) 2> /dev/null
-MICROMAMBA_VERSION="1.5.10-0"
-if [[ "$(uname -m)" == "arm64" ]]; then
- osx_arch="osx-arm64"
-else
- osx_arch="osx-64"
+( startgroup "Provisioning base env with pixi" ) 2> /dev/null
+mkdir -p "${MINIFORGE_HOME}"
+curl -fsSL https://pixi.sh/install.sh | bash
+export PATH="~/.pixi/bin:$PATH"
+arch=$(uname -m)
+if [[ "$arch" == "x86_64" ]]; then
+ arch="64"
fi
-MICROMAMBA_URL="https://github.com/mamba-org/micromamba-releases/releases/download/${MICROMAMBA_VERSION}/micromamba-${osx_arch}"
-MAMBA_ROOT_PREFIX="${MINIFORGE_HOME}-micromamba-$(date +%s)"
-echo "Downloading micromamba ${MICROMAMBA_VERSION}"
-micromamba_exe="$(mktemp -d)/micromamba"
-curl -L -o "${micromamba_exe}" "${MICROMAMBA_URL}"
-chmod +x "${micromamba_exe}"
+sed -i.bak "s/platforms = .*/platforms = [\"osx-${arch}\"]/" pixi.toml
echo "Creating environment"
-"${micromamba_exe}" create --yes --root-prefix "${MAMBA_ROOT_PREFIX}" --prefix "${MINIFORGE_HOME}" \
- --channel conda-forge \
- pip rattler-build conda-forge-ci-setup=4 "conda-build>=24.1"
-echo "Moving pkgs cache from ${MAMBA_ROOT_PREFIX} to ${MINIFORGE_HOME}"
-mv "${MAMBA_ROOT_PREFIX}/pkgs" "${MINIFORGE_HOME}"
-echo "Cleaning up micromamba"
-rm -rf "${MAMBA_ROOT_PREFIX}" "${micromamba_exe}" || true
-( endgroup "Provisioning base env with micromamba" ) 2> /dev/null
+pixi install
+pixi list
+echo "Activating environment"
+eval "$(pixi shell-hook)"
+mv pixi.toml.bak pixi.toml
+( endgroup "Provisioning base env with pixi" ) 2> /dev/null
( startgroup "Configuring conda" ) 2> /dev/null
-echo "Activating environment"
-source "${MINIFORGE_HOME}/etc/profile.d/conda.sh"
-conda activate base
export CONDA_SOLVER="libmamba"
export CONDA_LIBMAMBA_SOLVER_NO_CHANNELS_FROM_INSTALLED=1
diff --git a/README.md b/README.md
index 2bccba9..3635baa 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,13 @@ Current build status
+