+
With `pixi global`, users can manage globally installed tools in a way that makes them available from any directory.
This means that the pixi environment will be placed in a global location, and the tools will be exposed to the system `PATH`, allowing you to run them from the command line.
+
+## Basic Usage
+
+Running the following command installs [`rattler-build`](https://prefix-dev.github.io/rattler-build/latest/) on your system.
+
+```bash
+pixi global install rattler-build
+```
+
+What's great about `pixi global` is that, by default, it isolates each package in its own environment, exposing only the necessary entry points.
+This means you don't have to worry about removing a package and accidentally breaking seemingly unrelated packages.
+This behavior is quite similar to that of [`pipx`](https://pipx.pypa.io/latest/installation/).
+
+However, there are times when you may want multiple dependencies in the same environment.
+For instance, while `ipython` is really useful on its own, it becomes much more useful when `numpy` and `matplotlib` are available when using it.
+
+Let's execute the following command:
+
+```bash
+pixi global install ipython --with numpy --with matplotlib
+```
+
+`numpy` exposes executables, but since it's added via `--with` it's executables are not being exposed.
+
+Importing `numpy` and `matplotlib` now works as expected.
+```bash
+ipython -c 'import numpy; import matplotlib'
+```
+
+At some point, you might want to install multiple versions of the same package on your system.
+Since they will be all available on the system `PATH`, they need to be exposed under different names.
+
+Let's check out the following command:
+```bash
+pixi global install --expose py3=python "python=3.12"
+```
+
+By specifying `--expose` we specified that we want to expose the executable `python` under the name `py3`.
+The package `python` has more executables, but since we specified `--exposed` they are not auto-exposed.
+
+You can run `py3` to start the python interpreter.
+```shell
+py3 -c "print('Hello World')"
+```
+
## The Global Manifest
+
Since `v0.33.0` pixi has a new manifest file that will be created in the global directory.
This file will contain the list of environments that are installed globally, their dependencies and exposed binaries.
The manifest can be edited, synced, checked in to a version control system, and shared with others.
-
-A simple version looks like this:
+Running the commands from the section before results in the following manifest:
```toml
-[envs.vim]
+version = 1
+
+[envs.rattler-build]
channels = ["conda-forge"]
-dependencies = { vim = "*" } # (1)!
-exposed = { vimdiff = "vimdiff", vim = "vim" } # (2)!
+dependencies = { rattler-build = "*" }
+exposed = { rattler-build = "rattler-build" }
-[envs.gh]
+[envs.ipython]
channels = ["conda-forge"]
-dependencies = { gh = "*" }
-exposed = { gh = "gh" }
+dependencies = { ipython = "*", numpy = "*", matplotlib = "*" }
+exposed = { ipython = "ipython", ipython3 = "ipython3" }
[envs.python]
channels = ["conda-forge"]
-dependencies = { python = ">=3.10,<3.11" }
-exposed = { python310 = "python" } # (3)!
+dependencies = { python = "3.12.*" } # (1)!
+exposed = { py3 = "python" } # (2)!
```
1. Dependencies are the packages that will be installed in the environment. You can specify the version or use a wildcard.
-2. The exposed binaries are the ones that will be available in the system path. `vim` has multiple and all of them are exposed.
-3. Here python is exposed as `python310` to avoid conflicts with other python installations. You can give it any name you want.
+2. The exposed binaries are the ones that will be available in the system path. In this case, `python` is exposed under the name `py3`.
### Manifest locations
-The manifest can be found at the following locations depending on your operation system.
+The manifest can be found at the following locations depending on your operating system.
=== "Linux"
@@ -77,25 +131,7 @@ exposed = { snakemake = "snakemake" }
More information on channels can be found [here](../advanced/channel_priority.md).
-### Exposed
-The exposed binaries are the ones that will be available in the system `PATH`.
-This is useful when the package has multiple binaries, but you want to get a select few, or you want to expose it with a different name.
-For example, the `python` package has multiple binaries, but you only want to expose the interpreter as `py3`.
-Running:
-```
-pixi global expose add --environment python py3=python3
-```
-will create the following entry in the manifest:
-```toml
-[envs.python]
-channels = ["conda-forge"]
-dependencies = { python = ">=3.10,<3.11" }
-exposed = { py3 = "python3" }
-```
-Now you can run `py3` to start the python interpreter.
-```shell
-py3 -c "print('Hello World')"
-```
+### Automatic Exposed
There is some added automatic behavior, if you install a package with the same name as the environment, it will be exposed with the same name.
Even if the binary name is only exposed through dependencies of the package
@@ -158,7 +194,7 @@ When you execute a global install binary, a trampoline performs the following se
* Each trampoline first reads a configuration file named after the binary being executed. This configuration file, in JSON format (e.g., `python.json`), contains key information about how the environment should be set up. The configuration file is stored in `.pixi/bin/trampoline_configuration`.
* Once the configuration is loaded and the environment is set, the trampoline executes the original binary with the correct environment settings.
-* When installing a new binary, a new trampoline is placed in the `.pixi/bin` directory and is hardlinked to the `.pixi/bin/trampoline_configuration/trampoline_bin`. This optimizes storage space and avoids duplication of the same trampoline.
+* When installing a new binary, a new trampoline is placed in the `.pixi/bin` directory and is hard-linked to the `.pixi/bin/trampoline_configuration/trampoline_bin`. This optimizes storage space and avoids duplication of the same trampoline.
### Example: Adding a series of tools at once
From f432f43768befe688357e02a8eb9a2d60ecb7181 Mon Sep 17 00:00:00 2001
From: Julian Hofer
Date: Sat, 9 Nov 2024 22:05:17 +0100
Subject: [PATCH 02/10] docs: fix video
---
docs/features/global_tools.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/features/global_tools.md b/docs/features/global_tools.md
index d89376639..0b211b391 100644
--- a/docs/features/global_tools.md
+++ b/docs/features/global_tools.md
@@ -2,7 +2,7 @@
From 0a069f718d527451aee40f6e545db307cdc246d8 Mon Sep 17 00:00:00 2001
From: Julian Hofer
Date: Sun, 10 Nov 2024 08:26:54 +0100
Subject: [PATCH 03/10] docs: fix url one more time
---
docs/features/global_tools.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/features/global_tools.md b/docs/features/global_tools.md
index 0b211b391..e3e33a278 100644
--- a/docs/features/global_tools.md
+++ b/docs/features/global_tools.md
@@ -2,7 +2,7 @@
From 12aa332b8fb3f396ef9b79616def48589f8569ac Mon Sep 17 00:00:00 2001
From: Jermiah Joseph <44614774+jjjermiah@users.noreply.github.com>
Date: Sun, 10 Nov 2024 03:51:36 -0500
Subject: [PATCH 04/10] fix: ensure tasks are fetched for the best platform
(#2446)
`task list` was not displaying when targets were specified
**manifest-path**
```toml
[project]
channels = ["https://fast.prefix.dev/conda-forge"]
name = "pixi"
platforms = ["linux-64", "win-64", "osx-64", "osx-arm64"]
[tasks]
make.cmd = "command_1"
generate_keymap.cmd = "command_2"
svg.cmd = "command_3"
[target.osx.tasks]
flash.cmd = "command_4"
port.cmd = "command_5"
port_right.cmd = "command_6"
```
### on `osx-arm64`
**before**
```console
> pixi task --manifest-path target/pixi.toml ls -s
Tasks per environment:
----------------------
default: generate_keymap, make, svg
```
**after**
```console
> pixi task --manifest-path target/pixi.toml ls -s
Tasks per environment:
----------------------
default: flash, generate_keymap, make, port, port_right, svg
```
---
src/cli/task.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/cli/task.rs b/src/cli/task.rs
index 261faf22e..ad6923553 100644
--- a/src/cli/task.rs
+++ b/src/cli/task.rs
@@ -423,7 +423,7 @@ pub fn execute(args: Args) -> miette::Result<()> {
let tasks: HashMap = task_names
.into_iter()
.filter_map(|task_name| {
- env.task(&task_name, None)
+ env.task(&task_name, Some(env.best_platform()))
.ok()
.map(|task| (task_name, task.clone()))
})
From ca3b195d10bd2d505cfefbedf11553643ecfea30 Mon Sep 17 00:00:00 2001
From: Hofer-Julian <30049909+Hofer-Julian@users.noreply.github.com>
Date: Sun, 10 Nov 2024 10:01:36 +0100
Subject: [PATCH 05/10] docs: remove badge (#2449)
It shows failing builds even if they are only skipped
---
README.md | 3 ---
1 file changed, 3 deletions(-)
diff --git a/README.md b/README.md
index b8b3d98e1..edfa420fd 100644
--- a/README.md
+++ b/README.md
@@ -11,14 +11,11 @@
![License][license-badge]
-[![Build Status][build-badge]][build]
[![Project Chat][chat-badge]][chat-url]
[![Pixi Badge][pixi-badge]][pixi-url]
[license-badge]: https://img.shields.io/badge/license-BSD--3--Clause-blue?style=flat-square
-[build-badge]: https://img.shields.io/github/actions/workflow/status/prefix-dev/pixi/rust.yml?style=flat-square&branch=main
-[build]: https://github.com/prefix-dev/pixi/actions/
[chat-badge]: https://img.shields.io/discord/1082332781146800168.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2&style=flat-square
[chat-url]: https://discord.gg/kKV8ZxyzY4
[pixi-badge]:https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/prefix-dev/pixi/main/assets/badge/v0.json&style=flat-square
From 1e777958da4611f9b2824e2b0be790195d8afb29 Mon Sep 17 00:00:00 2001
From: Liam Connors
Date: Mon, 11 Nov 2024 01:16:01 -0500
Subject: [PATCH 06/10] docs: update Python tutorial (#2452)
Update Python tutorial to accommodate change where `init` already adds
the python project.
See https://github.com/prefix-dev/pixi/issues/2451
---
docs/tutorials/python.md | 39 ++++++++++++---------------------------
1 file changed, 12 insertions(+), 27 deletions(-)
diff --git a/docs/tutorials/python.md b/docs/tutorials/python.md
index b03953a92..570b36085 100644
--- a/docs/tutorials/python.md
+++ b/docs/tutorials/python.md
@@ -18,13 +18,22 @@ In this tutorial, we will use the `pyproject.toml` format because it is the most
## Let's get started
-Let's start out by making a directory and creating a new `pyproject.toml` file.
+Let's start out by creating a new project that uses a `pyproject.toml` file.
```shell
pixi init pixi-py --format pyproject
```
-This gives you the following pyproject.toml:
+This creates a project with the following structure:
+
+```shell
+├── src
+│ └── pixi_py
+│ └── __init__.py
+└── pyproject.toml
+```
+
+The `pyproject.toml` for the project looks like this:
```toml
[project]
@@ -49,32 +58,8 @@ pixi-py = { path = ".", editable = true }
[tool.pixi.tasks]
```
-Let's add the Python project to the tree:
-
-=== "Linux & macOS"
- ```shell
- cd pixi-py # move into the project directory
- mkdir pixi_py
- touch pixi_py/__init__.py
- ```
-
-=== "Windows"
- ```shell
- cd pixi-py
- mkdir pixi_py
- type nul > pixi_py\__init__.py
- ```
-
-We now have the following directory structure:
-
-```shell
-.
-├── pixi_py
-│ └── __init__.py
-└── pyproject.toml
-```
+This project uses a src-layout, but pixi supports both [flat- and src-layouts](https://packaging.python.org/en/latest/discussions/src-layout-vs-flat-layout/#src-layout-vs-flat-layout).
-We've used a flat-layout here but pixi supports both [flat- and src-layouts](https://packaging.python.org/en/latest/discussions/src-layout-vs-flat-layout/#src-layout-vs-flat-layout).
### What's in the `pyproject.toml`?
From 5ab7fac2245ad5e8a716ba26a585990d164bdaa0 Mon Sep 17 00:00:00 2001
From: Hofer-Julian <30049909+Hofer-Julian@users.noreply.github.com>
Date: Mon, 11 Nov 2024 11:26:58 +0100
Subject: [PATCH 07/10] ci: lint github actions with actionlint (#2454)
Taken from https://github.com/freundTech/typst-forge
---
.github/workflows/rust.yml | 61 ++++-----
.github/workflows/test_common_wheels.yml | 26 ++--
.github/workflows/test_downstream.yml | 26 ++--
.github/workflows/test_exports.yml | 128 +++++++++----------
.github/workflows/trampoline.yaml | 60 +++++----
.pre-commit-config.yaml | 7 ++
pixi.lock | 154 +++++++++++++++++++++++
pixi.toml | 3 +
8 files changed, 315 insertions(+), 150 deletions(-)
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index d9cb77f8e..d9cb9a4ef 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -146,30 +146,24 @@ jobs:
fail-fast: false
matrix:
include:
- - {
- name: "Linux-x86_64",
- target: x86_64-unknown-linux-musl,
- os: "${{ contains(github.event.pull_request.labels.*.name, 'ci:free') && 'ubuntu-latest' || '8core_ubuntu_latest_runner' }}"
- }
- - {
- name: "Linux-aarch64",
- target: aarch64-unknown-linux-musl,
- os: ubuntu-latest,
- }
-
- - { name: "macOS-x86", target: x86_64-apple-darwin, os: macos-13 }
- - { name: "macOS-arm", target: aarch64-apple-darwin, os: macos-14 } # macOS-14 is the ARM chipset
-
- - {
- name: "Windows",
- target: x86_64-pc-windows-msvc,
- os: "${{ contains(github.event.pull_request.labels.*.name, 'ci:free') && 'windows-latest' || '16core_windows_latest_runner' }}"
- }
- - {
- name: "Windows-arm",
- target: aarch64-pc-windows-msvc,
- os: windows-latest,
- }
+ - name: "Linux-x86_64"
+ target: x86_64-unknown-linux-musl
+ os: "${{ contains(github.event.pull_request.labels.*.name, 'ci:free') && 'ubuntu-latest' || '8core_ubuntu_latest_runner' }}"
+ - name: "Linux-aarch64"
+ target: aarch64-unknown-linux-musl
+ os: ubuntu-latest
+ - name: "macOS-x86"
+ target: x86_64-apple-darwin
+ os: macos-13
+ - name: "macOS-arm"
+ target: aarch64-apple-darwin
+ os: macos-14
+ - name: "Windows"
+ target: x86_64-pc-windows-msvc
+ os: "${{ contains(github.event.pull_request.labels.*.name, 'ci:free') && 'windows-latest' || '16core_windows_latest_runner' }}"
+ - name: "Windows-arm"
+ target: aarch64-pc-windows-msvc
+ os: windows-latest
env:
#
# These are some environment variables that configure the build so that the binary size is reduced.
@@ -209,12 +203,6 @@ jobs:
# cargo-wix does not require static crt
RUSTFLAGS: ""
- - name: Ensure cache directory exists
- shell: bash
- if: matrix.os == 'ubuntu-20.04' && matrix.use-cross
- run: |
- mkdir -p ${XDG_CACHE_HOME}
-
- name: Show version information (Rust, cargo, GCC)
shell: bash
run: |
@@ -270,10 +258,11 @@ jobs:
BIN_PATH="target/${{ matrix.target }}/${CARGO_PROFILE}/${BIN_NAME}"
# Let subsequent steps know where to find the binary
- echo "BIN_PATH=${BIN_PATH}" >> $GITHUB_OUTPUT
- echo "BIN_NAME=${BIN_NAME}" >> $GITHUB_OUTPUT
- echo "EXE_SUFFIX=${EXE_SUFFIX}" >> $GITHUB_OUTPUT
-
+ {
+ echo "BIN_PATH=${BIN_PATH}"
+ echo "BIN_NAME=${BIN_NAME}"
+ echo "EXE_SUFFIX=${EXE_SUFFIX}"
+ } >> $GITHUB_OUTPUT
- name: Build msi Installer
if: startsWith(matrix.name, 'Windows') && matrix.target != 'aarch64-pc-windows-msvc'
run: >
@@ -309,7 +298,8 @@ jobs:
KEYCHAIN_PATH="$RUNNER_TEMP/$KEYCHAIN_FILENAME"
# create temporary keychain
- export KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
+ KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
+ export KEYCHAIN_PASSWORD
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
@@ -339,7 +329,6 @@ jobs:
# notarize binary
xcrun notarytool submit pixi.zip --keychain-profile "$KEYCHAIN_ENTRY" --wait
-
- name: Create tarball
id: package
shell: bash
diff --git a/.github/workflows/test_common_wheels.yml b/.github/workflows/test_common_wheels.yml
index 4d2be528f..1266e43d4 100644
--- a/.github/workflows/test_common_wheels.yml
+++ b/.github/workflows/test_common_wheels.yml
@@ -17,21 +17,21 @@ jobs:
matrix:
arch:
# Linux
- - {
- target: x86_64-unknown-linux-musl,
- os: 8core_ubuntu_latest_runner,
- name: "Linux",
- }
+ - target: x86_64-unknown-linux-musl
+ os: 8core_ubuntu_latest_runner
+ name: "Linux"
# MacOS
- - { target: x86_64-apple-darwin, os: macos-13, name: "MacOS-x86" }
- - { target: aarch64-apple-darwin, os: macos-14, name: "MacOS-Arm" } # macOS-14 is the ARM chipset
+ - target: x86_64-apple-darwin
+ os: macos-13
+ name: "MacOS-x86"
+ - target: aarch64-apple-darwin
+ os: macos-14
+ name: "MacOS-Arm" # macOS-14 is the ARM chipset
# Windows
- - {
- target: x86_64-pc-windows-msvc,
- os: windows-latest,
- extension: .exe,
- name: "Windows",
- }
+ - target: x86_64-pc-windows-msvc
+ os: windows-latest
+ extension: .exe
+ name: "Windows"
steps:
- name: Checkout repo
uses: actions/checkout@v4
diff --git a/.github/workflows/test_downstream.yml b/.github/workflows/test_downstream.yml
index 96bc10758..2e77ae246 100644
--- a/.github/workflows/test_downstream.yml
+++ b/.github/workflows/test_downstream.yml
@@ -13,21 +13,21 @@ jobs:
matrix:
arch:
# Linux
- - {
- target: x86_64-unknown-linux-musl,
- os: 8core_ubuntu_latest_runner,
- name: "Linux",
- }
+ - target: x86_64-unknown-linux-musl
+ os: 8core_ubuntu_latest_runner
+ name: "Linux"
# MacOS
- - { target: x86_64-apple-darwin, os: macos-13, name: "MacOS-x86" }
- - { target: aarch64-apple-darwin, os: macos-14, name: "MacOS-Arm" } # macOS-14 is the ARM chipset
+ - target: x86_64-apple-darwin
+ os: macos-13
+ name: "MacOS-x86"
+ - target: aarch64-apple-darwin
+ os: macos-14
+ name: "MacOS-Arm" # macOS-14 is the ARM chipset
# Windows
- - {
- target: x86_64-pc-windows-msvc,
- os: windows-latest,
- extension: .exe,
- name: "Windows",
- }
+ - target: x86_64-pc-windows-msvc
+ os: windows-latest
+ extension: .exe
+ name: "Windows"
repository:
- Deltares/Ribasim
- quantco/polarify
diff --git a/.github/workflows/test_exports.yml b/.github/workflows/test_exports.yml
index 66f11d544..fe82ca37e 100644
--- a/.github/workflows/test_exports.yml
+++ b/.github/workflows/test_exports.yml
@@ -3,72 +3,66 @@ name: "Test exports"
on:
workflow_call:
-
jobs:
- test-export:
- name: ${{ matrix.arch.name }} - Export Tests
- runs-on: ${{ matrix.arch.os }}
- strategy:
- fail-fast: false
- matrix:
- arch:
- # Linux
- - {
- target: x86_64-unknown-linux-musl,
- os: ubuntu-20.04,
- name: "Linux",
- }
- # MacOS
- - { target: x86_64-apple-darwin, os: macos-13, name: "MacOS-x86" }
- - { target: aarch64-apple-darwin, os: macos-14, name: "MacOS-arm" } # macOS-14 is the ARM chipset
- # # Windows
- # - {
- # target: x86_64-pc-windows-msvc,
- # os: windows-latest,
- # extension: .exe,
- # name: "Windows",
- # }
- steps:
- - name: checkout repo
- uses: actions/checkout@v4
- - name: setup micromamba
- uses: mamba-org/setup-micromamba@v2.0.0
- - name: Download binary from build
- uses: actions/download-artifact@v4
- with:
- name: pixi-${{ matrix.arch.target }}${{ matrix.arch.extension }}
- path: pixi_bin
- - name: Debug
- run: |
- pwd
- - name: Setup unix binary, add to github path
- if: matrix.arch.name != 'Windows'
- run: |
- mv pixi_bin/pixi-${{ matrix.arch.target }} pixi_bin/pixi
- chmod a+x pixi_bin/pixi
- echo "$(pwd)/pixi_bin" >> $GITHUB_PATH
- - name: Create Directory and Move Executable
- if: matrix.arch.name == 'Windows' && matrix.arch.target == 'x86_64-pc-windows-msvc'
- run: |
- New-Item -ItemType Directory -Force -Path "D:\.pixi"
- Move-Item -Path "pixi_bin/pixi-${{ matrix.arch.target }}${{ matrix.arch.extension }}" -Destination "D:\.pixi\pixi.exe"
- shell: pwsh
- - name: Add to PATH
- if: matrix.arch.name == 'Windows' && matrix.arch.target == 'x86_64-pc-windows-msvc'
- run: echo "D:\.pixi" | Out-File -Append -Encoding utf8 -FilePath $env:GITHUB_PATH
+ test-export:
+ name: ${{ matrix.arch.name }} - Export Tests
+ runs-on: ${{ matrix.arch.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ arch:
+ # Linux
+ - target: x86_64-unknown-linux-musl
+ os: ubuntu-20.04
+ name: "Linux"
+ # MacOS
+ - target: x86_64-apple-darwin
+ os: macos-13
+ name: "MacOS-x86"
+ - target: aarch64-apple-darwin
+ os: macos-14
+ name: "MacOS-arm" # macOS-14 is the ARM chipset
+ steps:
+ - name: checkout repo
+ uses: actions/checkout@v4
+ - name: setup micromamba
+ uses: mamba-org/setup-micromamba@v2.0.0
+ - name: Download binary from build
+ uses: actions/download-artifact@v4
+ with:
+ name: pixi-${{ matrix.arch.target }}
+ path: pixi_bin
+ - name: Debug
+ run: |
+ pwd
+ - name: Setup unix binary, add to github path
+ if: matrix.arch.name != 'Windows'
+ run: |
+ mv pixi_bin/pixi-${{ matrix.arch.target }} pixi_bin/pixi
+ chmod a+x pixi_bin/pixi
+ echo "$(pwd)/pixi_bin" >> $GITHUB_PATH
+ - name: Create Directory and Move Executable
+ if: matrix.arch.name == 'Windows' && matrix.arch.target == 'x86_64-pc-windows-msvc'
+ run: |
+ New-Item -ItemType Directory -Force -Path "D:\.pixi"
+ Move-Item -Path "pixi_bin/pixi-${{ matrix.arch.target }}" -Destination "D:\.pixi\pixi.exe"
+ shell: pwsh
+ - name: Add to PATH
+ if: matrix.arch.name == 'Windows' && matrix.arch.target == 'x86_64-pc-windows-msvc'
+ run: echo "D:\.pixi" | Out-File -Append -Encoding utf8 -FilePath $env:GITHUB_PATH
+ shell: pwsh
+ - name: Verify and Use Executable
+ if: matrix.arch.name == 'Windows' && matrix.arch.target == 'x86_64-pc-windows-msvc'
+ run: |
+ echo "Current PATH: $env:PATH"
+ pixi --version
shell: pwsh
- - name: Verify and Use Executable
- if: matrix.arch.name == 'Windows' && matrix.arch.target == 'x86_64-pc-windows-msvc'
- run: |
- echo "Current PATH: $env:PATH"
- pixi --version
- shell: pwsh
- - name: Help
- run: pixi --help
- - name: Info
- run: pixi info
- - name: Install pixi
- run: pixi install -v
- - name: Test export
- shell: bash
- run: pixi run test-export
+ - name: Help
+ run: pixi --help
+ - name: Info
+ run: pixi info
+ - name: Install pixi
+ run: pixi install -v
+ - name: Test export
+ shell: bash
+ run: pixi run test-export
diff --git a/.github/workflows/trampoline.yaml b/.github/workflows/trampoline.yaml
index d087e11c7..da8ca35c4 100644
--- a/.github/workflows/trampoline.yaml
+++ b/.github/workflows/trampoline.yaml
@@ -3,18 +3,18 @@ name: Update Trampoline Binary
on:
push:
paths:
- - 'crates/pixi_trampoline/**'
- - '.github/workflows/trampoline.yaml'
- - 'src/global/trampoline.rs'
+ - "crates/pixi_trampoline/**"
+ - ".github/workflows/trampoline.yaml"
+ - "src/global/trampoline.rs"
workflow_dispatch:
pull_request:
paths:
- - 'crates/pixi_trampoline/**'
- - '.github/workflows/trampoline.yaml'
- - 'src/global/trampoline.rs'
+ - "crates/pixi_trampoline/**"
+ - ".github/workflows/trampoline.yaml"
+ - "src/global/trampoline.rs"
permissions:
- contents: write # Allow write permissions for contents (like pushing to the repo)
+ contents: write # Allow write permissions for contents (like pushing to the repo)
pull-requests: write
jobs:
@@ -27,13 +27,33 @@ jobs:
fail-fast: true
matrix:
include:
- - { name: "Linux-x86_64", target: x86_64-unknown-linux-musl, os: ubuntu-latest }
- - { name: "Linux-aarch64", target: aarch64-unknown-linux-musl, os: ubuntu-latest }
- - { name: "Linux-powerpc64", target: powerpc64-unknown-linux-gnu, os: ubuntu-latest }
- - { name: "macOS-x86", target: x86_64-apple-darwin, os: macos-13 }
- - { name: "macOS-arm", target: aarch64-apple-darwin, os: macos-14 }
- - { name: "Windows", target: x86_64-pc-windows-msvc, os: windows-latest }
- - { name: "Windows-arm", target: aarch64-pc-windows-msvc, os: windows-latest }
+ - name: "Linux-x86_64"
+ target: x86_64-unknown-linux-musl
+ os: ubuntu-latest
+
+ - name: "Linux-aarch64"
+ target: aarch64-unknown-linux-musl
+ os: ubuntu-latest
+
+ - name: "Linux-powerpc64"
+ target: powerpc64-unknown-linux-gnu
+ os: ubuntu-latest
+
+ - name: "macOS-x86"
+ target: x86_64-apple-darwin
+ os: macos-13
+
+ - name: "macOS-arm"
+ target: aarch64-apple-darwin
+ os: macos-14
+
+ - name: "Windows"
+ target: x86_64-pc-windows-msvc
+ os: windows-latest
+
+ - name: "Windows-arm"
+ target: aarch64-pc-windows-msvc
+ os: windows-latest
steps:
- name: Checkout code
@@ -62,7 +82,7 @@ jobs:
mv target/${{ matrix.target }}/release/pixi_trampoline trampolines-binaries/pixi-trampoline-${{ matrix.target }}
- name: Upload binary artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: trampoline-${{ matrix.target }}
path: crates/pixi_trampoline/trampolines-binaries/
@@ -72,13 +92,13 @@ jobs:
defaults:
run:
working-directory: crates/pixi_trampoline
- needs: build # This ensures the aggregation job runs after the build jobs
+ needs: build # This ensures the aggregation job runs after the build jobs
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download all binaries
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
path: crates/pixi_trampoline/trampolines-binaries/
@@ -100,13 +120,11 @@ jobs:
ls -R trampolines/
- name: Upload binary artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: trampolines
path: crates/pixi_trampoline/trampolines/
-
-
- name: Commit and push updated binaries
# Don't run on forks
if: github.repository == 'prefix-dev/pixi' && startsWith(github.ref, 'reaf/heads')
@@ -117,5 +135,5 @@ jobs:
git add trampolines/
git commit -m "[CI]: Update trampoline binaries for all targets"
# Push changes to the branch that triggered the workflow
- BRANCH=$(echo "${GITHUB_REF#refs/heads/}")
+ BRANCH=${GITHUB_REF#refs/heads/}
git push origin HEAD:$BRANCH
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ade0edfe1..a945dccb2 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -32,6 +32,13 @@ repos:
language: system
types_or: [python, pyi]
require_serial: true
+ # GitHub Actions
+ - id: actionlint
+ name: Lint GitHub Actions workflow files
+ language: system
+ entry: pixi run -e lint actionlint
+ types: [yaml]
+ files: ^\.github/workflows/
# Typecheck python tests
- id: typecheck-python
name: typecheck-python
diff --git a/pixi.lock b/pixi.lock
index 5449c63c9..95d6b77d7 100644
--- a/pixi.lock
+++ b/pixi.lock
@@ -881,6 +881,7 @@ environments:
linux-64:
- conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/actionlint-1.7.4-hb9d3cd8_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.8.30-hbcca054_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.0-py312h06ac9bb_1.conda
@@ -933,6 +934,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.8-py312h98912ed_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.4.10-py312h5715c7c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-72.2.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/linux-64/shellcheck-0.10.0-ha770c72_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/taplo-0.9.3-h1de38c7_0.conda
- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2
@@ -946,6 +948,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.1-pyhd8ed1ab_0.conda
osx-64:
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/actionlint-1.7.4-hd79239c_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-hfdf4475_7.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2024.8.30-h8857fd0_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/cffi-1.17.0-py312hf857d28_1.conda
@@ -955,6 +958,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.16.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.4.0-pyha770c72_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda
@@ -990,6 +994,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml.clib-0.2.8-py312h41838bb_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/ruff-0.4.10-py312h8b25c6c_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-72.2.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-64/shellcheck-0.10.0-h7dd6a17_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/taplo-0.9.3-hd264b5c_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h1abcd95_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2
@@ -1003,6 +1008,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h0d85af4_2.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.1-pyhd8ed1ab_0.conda
osx-arm64:
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/actionlint-1.7.4-h5505292_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-h99b78c6_7.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ca-certificates-2024.8.30-hf0a4a13_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/cffi-1.17.0-py312h0fad829_1.conda
@@ -1012,6 +1018,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.2.2-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/execnet-2.1.1-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.16.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/gmp-6.3.0-h7bae524_2.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.0-pyhd8ed1ab_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-8.4.0-pyha770c72_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_0.conda
@@ -1047,6 +1054,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruamel.yaml.clib-0.2.8-py312he37b823_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.4.10-py312h3402d49_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-72.2.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/osx-arm64/shellcheck-0.10.0-hecfb573_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/taplo-0.9.3-h563f0a8_0.conda
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h5083fa2_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2
@@ -1060,6 +1068,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/osx-arm64/yaml-0.2.5-h3422bc3_2.tar.bz2
- conda: https://conda.anaconda.org/conda-forge/noarch/zipp-3.20.1-pyhd8ed1ab_0.conda
win-64:
+ - conda: https://conda.anaconda.org/conda-forge/win-64/actionlint-1.7.4-h2466b09_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h2466b09_7.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2024.8.30-h56e8100_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/cffi-1.17.0-py312h4389bb4_1.conda
@@ -1107,6 +1116,7 @@ environments:
- conda: https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml.clib-0.2.8-py312he70551f_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/ruff-0.4.10-py312h7a6832a_0.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-72.2.0-pyhd8ed1ab_0.conda
+ - conda: https://conda.anaconda.org/conda-forge/win-64/shellcheck-0.10.0-h57928b3_0.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/taplo-0.9.3-ha073cba_1.conda
- conda: https://conda.anaconda.org/conda-forge/win-64/tk-8.6.13-h5226925_1.conda
- conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2
@@ -1510,6 +1520,68 @@ packages:
license_family: GPL
size: 20798
timestamp: 1720621358501
+- kind: conda
+ name: actionlint
+ version: 1.7.4
+ build: h2466b09_0
+ subdir: win-64
+ url: https://conda.anaconda.org/conda-forge/win-64/actionlint-1.7.4-h2466b09_0.conda
+ sha256: 4bf1c9370415136610aa99603bc6cf2403ab8aebcec54427ba01e395410563c5
+ md5: c1b6b21fdaed39bc0ba0f8067db88a3e
+ depends:
+ - ucrt >=10.0.20348.0
+ - vc >=14.2,<15
+ - vc14_runtime >=14.29.30139
+ license: MIT
+ license_family: MIT
+ size: 1804586
+ timestamp: 1730743220374
+- kind: conda
+ name: actionlint
+ version: 1.7.4
+ build: h5505292_0
+ subdir: osx-arm64
+ url: https://conda.anaconda.org/conda-forge/osx-arm64/actionlint-1.7.4-h5505292_0.conda
+ sha256: 70cc5a33b7a73d638769a6f4721bff32cc8f38359f464b25bfccf56a839513a1
+ md5: cee2822980a166152536b435d45c6eb7
+ depends:
+ - __osx >=11.0
+ license: MIT
+ license_family: MIT
+ size: 1545787
+ timestamp: 1730742896293
+- kind: conda
+ name: actionlint
+ version: 1.7.4
+ build: hb9d3cd8_0
+ subdir: linux-64
+ url: https://conda.anaconda.org/conda-forge/linux-64/actionlint-1.7.4-hb9d3cd8_0.conda
+ sha256: ce74b8358f26e6e72ab07fd7d85554f00865dc02ea52ae806f037f0de69096cf
+ md5: a8ec6e2623fa4c5f0f43cacc9448ddd2
+ depends:
+ - __glibc >=2.17
+ - __glibc >=2.17,<3.0.a0
+ - libgcc >=13
+ license: MIT
+ license_family: MIT
+ size: 1753018
+ timestamp: 1730742808033
+- kind: conda
+ name: actionlint
+ version: 1.7.4
+ build: hd79239c_0
+ subdir: osx-64
+ url: https://conda.anaconda.org/conda-forge/osx-64/actionlint-1.7.4-hd79239c_0.conda
+ sha256: c3ba5ff5fabd584b6c29a18a436924cc76a688f58e3a9da103d7274e2f4bc013
+ md5: 16ce00fb139a02a3248e2da260d7cb2a
+ depends:
+ - __osx >=11.0
+ constrains:
+ - __osx>=10.12
+ license: MIT
+ license_family: MIT
+ size: 1684031
+ timestamp: 1730743027785
- kind: conda
name: annotated-types
version: 0.7.0
@@ -3039,6 +3111,36 @@ packages:
license: MIT OR Apache-2.0
size: 4849602
timestamp: 1719439458923
+- kind: conda
+ name: gmp
+ version: 6.3.0
+ build: h7bae524_2
+ build_number: 2
+ subdir: osx-arm64
+ url: https://conda.anaconda.org/conda-forge/osx-arm64/gmp-6.3.0-h7bae524_2.conda
+ sha256: 76e222e072d61c840f64a44e0580c2503562b009090f55aa45053bf1ccb385dd
+ md5: eed7278dfbab727b56f2c0b64330814b
+ depends:
+ - __osx >=11.0
+ - libcxx >=16
+ license: GPL-2.0-or-later OR LGPL-3.0-or-later
+ size: 365188
+ timestamp: 1718981343258
+- kind: conda
+ name: gmp
+ version: 6.3.0
+ build: hf036a51_2
+ build_number: 2
+ subdir: osx-64
+ url: https://conda.anaconda.org/conda-forge/osx-64/gmp-6.3.0-hf036a51_2.conda
+ sha256: 75aa5e7a875afdcf4903b7dc98577672a3dc17b528ac217b915f9528f93c85fc
+ md5: 427101d13f19c4974552a4e5b072eef1
+ depends:
+ - __osx >=10.13
+ - libcxx >=16
+ license: GPL-2.0-or-later OR LGPL-3.0-or-later
+ size: 428919
+ timestamp: 1718981041839
- kind: conda
name: gxx
version: 12.4.0
@@ -7910,6 +8012,58 @@ packages:
license_family: MIT
size: 1459799
timestamp: 1724163617860
+- kind: conda
+ name: shellcheck
+ version: 0.10.0
+ build: h57928b3_0
+ subdir: win-64
+ url: https://conda.anaconda.org/conda-forge/win-64/shellcheck-0.10.0-h57928b3_0.conda
+ sha256: a7a08960774abdf394791867fa5ec26752eaaf4beda70f7daefbb7076054ee9b
+ md5: c79f416ceb03e3add6e16381ecfdadd9
+ license: GPL-3.0-only
+ license_family: GPL
+ size: 2904381
+ timestamp: 1713721121438
+- kind: conda
+ name: shellcheck
+ version: 0.10.0
+ build: h7dd6a17_0
+ subdir: osx-64
+ url: https://conda.anaconda.org/conda-forge/osx-64/shellcheck-0.10.0-h7dd6a17_0.conda
+ sha256: 383901632d791e01f6799a8882c202c1fcf5ec2914f869b2bdd8ae6e139c20b7
+ md5: 6870813f912971e13d56360d2db55bde
+ depends:
+ - gmp >=6.3.0,<7.0a0
+ license: GPL-3.0-only
+ license_family: GPL
+ size: 1319826
+ timestamp: 1713720882839
+- kind: conda
+ name: shellcheck
+ version: 0.10.0
+ build: ha770c72_0
+ subdir: linux-64
+ url: https://conda.anaconda.org/conda-forge/linux-64/shellcheck-0.10.0-ha770c72_0.conda
+ sha256: 6809031184c07280dcbaed58e15020317226a3ed234b99cb1bd98384ea5be813
+ md5: 61b19e9e334ddcdf8bb2422ee576549e
+ license: GPL-3.0-only
+ license_family: GPL
+ size: 2606806
+ timestamp: 1713719553683
+- kind: conda
+ name: shellcheck
+ version: 0.10.0
+ build: hecfb573_0
+ subdir: osx-arm64
+ url: https://conda.anaconda.org/conda-forge/osx-arm64/shellcheck-0.10.0-hecfb573_0.conda
+ sha256: d175f46af454d3f2ba97f0a4be8a4fdf962aaec996db54dfcf8044d38da3769c
+ md5: 6b2856ca39fa39c438dcd46140cd894e
+ depends:
+ - gmp >=6.3.0,<7.0a0
+ license: GPL-3.0-only
+ license_family: GPL
+ size: 1320371
+ timestamp: 1713720918209
- kind: conda
name: six
version: 1.16.0
diff --git a/pixi.toml b/pixi.toml
index fc1a178ef..36dc88961 100644
--- a/pixi.toml
+++ b/pixi.toml
@@ -70,13 +70,16 @@ cffconvert = ">=2.0.0,<2.1"
tbump = ">=6.9.0,<6.10"
[feature.lint.dependencies]
+actionlint = ">=1.7.4,<2"
pre-commit = ">=3.7.1,<4"
pre-commit-hooks = ">=4.6.0,<5"
ruff = ">=0.4.8,<0.5"
+shellcheck = ">=0.10.0,<0.11"
taplo = ">=0.9.1,<0.10"
typos = ">=1.23.1,<2"
[feature.lint.tasks]
+actionlint = { cmd = "actionlint", env = { SHELLCHECK_OPTS = "-e SC2086" } }
check-openssl = "python tests/scripts/check-openssl.py"
lint = "pre-commit run --all-files --hook-stage=manual"
pre-commit-install = "pre-commit install --install-hooks -t=pre-commit -t=pre-push"
From 689cf9dd70371562d936af62e87b500e0d08e6aa Mon Sep 17 00:00:00 2001
From: Swastik Patel
Date: Mon, 11 Nov 2024 21:10:43 +0530
Subject: [PATCH 08/10] feat: add `--prepend` option for `pixi project channel
add` (#2447)
trying to fix #2349
### Example:
If the current `pixi.toml` has:
```
[project]
channels = ["conda-forge"]
```
After running `pixi project channel add pytorch --prepend` , the
channels list will become:
```
[project]
channels = ["pytorch", "conda-forge"]
```
unit test regarding the above functionality is passing:
![Screenshot from 2024-11-10
02-46-18](https://github.com/user-attachments/assets/30973f40-6a2e-471b-abea-6e13195f99d0)
this is my first time trying to contribute to pixi, and I am not that
good in Rust too, so any kind of help will be very much appreciated. I
will be happy to make requested code changes for this PR.
---
.../pixi_manifest/src/manifests/manifest.rs | 99 +++++++++++++++----
docs/reference/cli.md | 2 +
src/cli/project/channel/add.rs | 8 +-
src/cli/project/channel/mod.rs | 4 +
tests/integration_rust/common/mod.rs | 2 +
5 files changed, 95 insertions(+), 20 deletions(-)
diff --git a/crates/pixi_manifest/src/manifests/manifest.rs b/crates/pixi_manifest/src/manifests/manifest.rs
index ab28348df..134d5daf7 100644
--- a/crates/pixi_manifest/src/manifests/manifest.rs
+++ b/crates/pixi_manifest/src/manifests/manifest.rs
@@ -523,13 +523,17 @@ impl Manifest {
&mut self,
channels: impl IntoIterator,
feature_name: &FeatureName,
+ prepend: bool,
) -> miette::Result<()> {
- // Get current and new platforms for the feature
+ // First collect all the new channels
+ let to_add: IndexSet<_> = channels.into_iter().collect();
+
+ // Get the current channels and update them
let current = match feature_name {
FeatureName::Default => &mut self.parsed.project.channels,
FeatureName::Named(_) => self.get_or_insert_feature_mut(feature_name).channels_mut(),
};
- let to_add: IndexSet<_> = channels.into_iter().collect();
+
let new: IndexSet<_> = to_add.difference(current).cloned().collect();
let new_channels: IndexSet<_> = new
.clone()
@@ -540,16 +544,25 @@ impl Manifest {
// clear channels with modified priority
current.retain(|c| !new_channels.contains(&c.channel));
- // Add the updated channels to the manifest
- current.extend(new.clone());
- let current_clone = current.clone();
+ // Create the final channel list in the desired order
+ let final_channels = if prepend {
+ let mut new_set = new.clone();
+ new_set.extend(current.iter().cloned());
+ new_set
+ } else {
+ let mut new_set = current.clone();
+ new_set.extend(new.clone());
+ new_set
+ };
- // Then to the TOML document
+ // Update both the parsed channels and the TOML document
+ *current = final_channels.clone();
+
+ // Update the TOML document
let channels = self.document.get_array_mut("channels", feature_name)?;
- // clear and recreate from current list
channels.clear();
- for channel in current_clone.iter() {
- channels.push(Value::from(channel.clone()));
+ for channel in final_channels {
+ channels.push(Value::from(channel));
}
Ok(())
@@ -1424,7 +1437,7 @@ platforms = ["linux-64", "win-64"]
[dependencies]
[feature.test.dependencies]
- "#;
+ "#;
let mut manifest = Manifest::from_str(Path::new("pixi.toml"), file_contents).unwrap();
@@ -1433,13 +1446,13 @@ platforms = ["linux-64", "win-64"]
let conda_forge =
PrioritizedChannel::from(NamedChannelOrUrl::Name(String::from("conda-forge")));
manifest
- .add_channels([conda_forge.clone()], &FeatureName::Default)
+ .add_channels([conda_forge.clone()], &FeatureName::Default, false)
.unwrap();
let cuda_feature = FeatureName::Named("cuda".to_string());
let nvidia = PrioritizedChannel::from(NamedChannelOrUrl::Name(String::from("nvidia")));
manifest
- .add_channels([nvidia.clone()], &cuda_feature)
+ .add_channels([nvidia.clone()], &cuda_feature, false)
.unwrap();
let test_feature = FeatureName::Named("test".to_string());
@@ -1450,6 +1463,7 @@ platforms = ["linux-64", "win-64"]
PrioritizedChannel::from(NamedChannelOrUrl::Name(String::from("test2"))),
],
&test_feature,
+ false,
)
.unwrap();
@@ -1465,7 +1479,7 @@ platforms = ["linux-64", "win-64"]
// Try to add again, should not add more channels
manifest
- .add_channels([conda_forge.clone()], &FeatureName::Default)
+ .add_channels([conda_forge.clone()], &FeatureName::Default, false)
.unwrap();
assert_eq!(
@@ -1494,10 +1508,12 @@ platforms = ["linux-64", "win-64"]
.into_iter()
.collect::>()
);
+
// Try to add again, should not add more channels
manifest
- .add_channels([nvidia.clone()], &cuda_feature)
+ .add_channels([nvidia.clone()], &cuda_feature, false)
.unwrap();
+
assert_eq!(
manifest
.parsed
@@ -1544,8 +1560,9 @@ platforms = ["linux-64", "win-64"]
priority: None,
};
manifest
- .add_channels([custom_channel.clone()], &FeatureName::Default)
+ .add_channels([custom_channel.clone()], &FeatureName::Default, false)
.unwrap();
+
assert!(manifest
.parsed
.project
@@ -1559,8 +1576,9 @@ platforms = ["linux-64", "win-64"]
priority: Some(12i32),
};
manifest
- .add_channels([prioritized_channel1.clone()], &FeatureName::Default)
+ .add_channels([prioritized_channel1.clone()], &FeatureName::Default, false)
.unwrap();
+
assert!(manifest
.parsed
.project
@@ -1573,8 +1591,9 @@ platforms = ["linux-64", "win-64"]
priority: Some(-12i32),
};
manifest
- .add_channels([prioritized_channel2.clone()], &FeatureName::Default)
+ .add_channels([prioritized_channel2.clone()], &FeatureName::Default, false)
.unwrap();
+
assert!(manifest
.parsed
.project
@@ -2257,4 +2276,50 @@ bar = "*"
}
}
}
+
+ #[test]
+ fn test_prepend_channels() {
+ let contents = r#"
+ [project]
+ name = "foo"
+ channels = ["conda-forge"]
+ platforms = []
+ "#;
+ let mut manifest = Manifest::from_str(Path::new("pixi.toml"), contents).unwrap();
+
+ // Add pytorch channel with prepend=true
+ let pytorch = PrioritizedChannel::from(NamedChannelOrUrl::Name(String::from("pytorch")));
+ manifest
+ .add_channels([pytorch.clone()], &FeatureName::Default, true)
+ .unwrap();
+
+ // Verify pytorch is first in the list
+ assert_eq!(
+ manifest
+ .parsed
+ .project
+ .channels
+ .iter()
+ .next()
+ .unwrap()
+ .channel,
+ pytorch.channel
+ );
+
+ // Add another channel without prepend
+ let bioconda = PrioritizedChannel::from(NamedChannelOrUrl::Name(String::from("bioconda")));
+ manifest
+ .add_channels([bioconda.clone()], &FeatureName::Default, false)
+ .unwrap();
+
+ // Verify order is still pytorch, conda-forge, bioconda
+ let channels: Vec<_> = manifest
+ .parsed
+ .project
+ .channels
+ .iter()
+ .map(|c| c.channel.to_string())
+ .collect();
+ assert_eq!(channels, vec!["pytorch", "conda-forge", "bioconda"]);
+ }
}
diff --git a/docs/reference/cli.md b/docs/reference/cli.md
index 3bd9242a9..13b6d9958 100644
--- a/docs/reference/cli.md
+++ b/docs/reference/cli.md
@@ -1210,6 +1210,7 @@ When you add channels, the channels are tested for existence, added to the lock
- `--no-install`: do not update the environment, only add changed packages to the lock-file.
- `--feature (-f)`: The feature for which the channel is added.
+- `--prepend`: Prepend the channel to the list of channels.
```
pixi project channel add robostack
@@ -1218,6 +1219,7 @@ pixi project channel add file:///home/user/local_channel
pixi project channel add https://repo.prefix.dev/conda-forge
pixi project channel add --no-install robostack
pixi project channel add --feature cuda nvidia
+pixi project channel add --prepend pytorch
```
### `project channel list`
diff --git a/src/cli/project/channel/add.rs b/src/cli/project/channel/add.rs
index e4137df81..ceb18fbaf 100644
--- a/src/cli/project/channel/add.rs
+++ b/src/cli/project/channel/add.rs
@@ -8,9 +8,11 @@ use super::AddRemoveArgs;
pub async fn execute(mut project: Project, args: AddRemoveArgs) -> miette::Result<()> {
// Add the channels to the manifest
- project
- .manifest
- .add_channels(args.prioritized_channels(), &args.feature_name())?;
+ project.manifest.add_channels(
+ args.prioritized_channels(),
+ &args.feature_name(),
+ args.prepend,
+ )?;
// TODO: Update all environments touched by the features defined.
update_prefix(
diff --git a/src/cli/project/channel/mod.rs b/src/cli/project/channel/mod.rs
index 86dcd8ecd..8f9baecf5 100644
--- a/src/cli/project/channel/mod.rs
+++ b/src/cli/project/channel/mod.rs
@@ -31,6 +31,10 @@ pub struct AddRemoveArgs {
#[clap(long, num_args = 1)]
pub priority: Option,
+ /// Add the channel(s) to the beginning of the channels list, making them highest priority
+ #[clap(long)]
+ pub prepend: bool,
+
/// Don't update the environment, only modify the manifest and the
/// lock-file.
#[clap(long)]
diff --git a/tests/integration_rust/common/mod.rs b/tests/integration_rust/common/mod.rs
index 302ab98fe..464f78a02 100644
--- a/tests/integration_rust/common/mod.rs
+++ b/tests/integration_rust/common/mod.rs
@@ -360,6 +360,7 @@ impl PixiControl {
no_install: true,
feature: None,
priority: None,
+ prepend: false,
},
}
}
@@ -373,6 +374,7 @@ impl PixiControl {
no_install: true,
feature: None,
priority: None,
+ prepend: false,
},
}
}
From 5d37dcfeb897f450136163ef905abe081cba97e2 Mon Sep 17 00:00:00 2001
From: Johan Venant
Date: Tue, 12 Nov 2024 10:38:09 +0100
Subject: [PATCH 09/10] feat: tolerate pixi file error (#2457)
---
src/environment.rs | 30 +++++++++++++++++++++---------
1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/src/environment.rs b/src/environment.rs
index 77e2ecd9a..4f5e35240 100644
--- a/src/environment.rs
+++ b/src/environment.rs
@@ -233,15 +233,27 @@ pub(crate) fn write_environment_file(
.parent()
.expect("There should already be a conda-meta folder");
- std::fs::create_dir_all(parent).into_diagnostic()?;
-
- // Using json as it's easier to machine read it.
- let contents = serde_json::to_string_pretty(&env_file).into_diagnostic()?;
- std::fs::write(&path, contents).into_diagnostic()?;
-
- tracing::debug!("Wrote environment file to: {:?}", path);
-
- Ok(path)
+ match std::fs::create_dir_all(parent).into_diagnostic() {
+ Ok(_) => {
+ // Using json as it's easier to machine read it.
+ let contents = serde_json::to_string_pretty(&env_file).into_diagnostic()?;
+ match std::fs::write(&path, contents).into_diagnostic() {
+ Ok(_) => {
+ tracing::debug!("Wrote environment file to: {:?}", path);
+ }
+ Err(e) => tracing::debug!(
+ "Unable to write environment file to: {:?} => {:?}",
+ path,
+ e.root_cause().to_string()
+ ),
+ };
+ Ok(path)
+ }
+ Err(e) => {
+ tracing::debug!("Unable to create conda-meta folder to: {:?}", path);
+ Err(e)
+ }
+ }
}
/// Reading the environment file of the environment.
From 5ad93127b6337e3ffbccdb38240def225a96aa0e Mon Sep 17 00:00:00 2001
From: Hofer-Julian <30049909+Hofer-Julian@users.noreply.github.com>
Date: Tue, 12 Nov 2024 11:02:29 +0100
Subject: [PATCH 10/10] fix: attempt copying trampoline when hard-linking fails
(#2464)
Fixes #2462
---
src/global/trampoline.rs | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/global/trampoline.rs b/src/global/trampoline.rs
index d9ea13ab6..9055f324c 100644
--- a/src/global/trampoline.rs
+++ b/src/global/trampoline.rs
@@ -354,9 +354,15 @@ impl Trampoline {
.into_diagnostic()?;
}
- // Create a hard link to the shared trampoline binary
- if !self.path().exists() {
- tokio::fs::hard_link(self.trampoline_path(), self.path())
+ // If the path doesn't exist yet, create a hard link to the shared trampoline binary
+ // If creating a hard link doesn't succeed, try copying
+ // Hard-linking might for example fail because the file-system enforces a maximum number of hard-links per file
+ if !self.path().exists()
+ && tokio_fs::hard_link(self.trampoline_path(), self.path())
+ .await
+ .is_err()
+ {
+ tokio_fs::copy(self.trampoline_path(), self.path())
.await
.into_diagnostic()?;
}