Skip to content

Commit

Permalink
Merge branch 'main' into prefix-devgh-1375-constructor-example
Browse files Browse the repository at this point in the history
  • Loading branch information
ruben-arts authored Sep 23, 2024
2 parents 6a73647 + fd903bf commit 56eca5d
Show file tree
Hide file tree
Showing 18 changed files with 285 additions and 54 deletions.
9 changes: 4 additions & 5 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,7 @@ jobs:
with:
tool: cargo-nextest

- if: ${{ matrix.os != 'windows-latest' }}
uses: rui314/setup-mold@v1
- uses: rui314/setup-mold@v1

- name: "Cargo nextest"
run: >-
Expand Down Expand Up @@ -214,7 +213,7 @@ jobs:

- name: Setup | Install cargo-wix [Windows]
# aarch64 is only supported in wix 4.0 development builds
if: startsWith(matrix.os, 'windows') && matrix.target != 'aarch64-pc-windows-msvc'
if: startsWith(matrix.name, 'Windows') && matrix.target != 'aarch64-pc-windows-msvc'
run: cargo install --version 0.3.8 cargo-wix
env:
# cargo-wix does not require static crt
Expand Down Expand Up @@ -284,7 +283,7 @@ jobs:
echo "EXE_SUFFIX=${EXE_SUFFIX}" >> $GITHUB_OUTPUT
- name: Build msi Installer
if: matrix.os == 'windows-latest' && matrix.target != 'aarch64-pc-windows-msvc'
if: startsWith(matrix.name, 'Windows') && matrix.target != 'aarch64-pc-windows-msvc'
run: >
cargo wix -v --no-build --nocapture -I install/windows/main.wxs
--profile $env:CARGO_PROFILE
Expand Down Expand Up @@ -394,7 +393,7 @@ jobs:
path: ${{ steps.package.outputs.BIN_PATH }}

- name: "Artifact upload: windows installer"
if: matrix.os == 'windows-latest' && matrix.target != 'aarch64-pc-windows-msvc'
if: startsWith(matrix.name, 'Windows') && matrix.target != 'aarch64-pc-windows-msvc'
uses: actions/upload-artifact@v4
with:
name: pixi-${{ matrix.target }}.msi
Expand Down
24 changes: 24 additions & 0 deletions crates/pixi_manifest/src/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::str::FromStr;
use rattler_conda_types::NamedChannelOrUrl;
use serde::{de::Error, Deserialize, Deserializer};
use serde_with::serde_as;
use toml_edit::{Table, Value};

/// A channel with an optional priority.
/// If the priority is not specified, it is assumed to be 0.
Expand All @@ -23,6 +24,29 @@ impl From<NamedChannelOrUrl> for PrioritizedChannel {
}
}

impl From<(NamedChannelOrUrl, Option<i32>)> for PrioritizedChannel {
fn from((value, prio): (NamedChannelOrUrl, Option<i32>)) -> Self {
Self {
channel: value,
priority: prio,
}
}
}

impl From<PrioritizedChannel> for Value {
fn from(channel: PrioritizedChannel) -> Self {
match channel.priority {
Some(priority) => {
let mut table = Table::new().into_inline_table();
table.insert("channel", channel.channel.to_string().into());
table.insert("priority", i64::from(priority).into());
Value::InlineTable(table)
}
None => Value::String(toml_edit::Formatted::new(channel.channel.to_string())),
}
}
}

pub enum TomlPrioritizedChannelStrOrMap {
Map(PrioritizedChannel),
Str(NamedChannelOrUrl),
Expand Down
67 changes: 57 additions & 10 deletions crates/pixi_manifest/src/manifests/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use itertools::Itertools;
use miette::{miette, IntoDiagnostic, NamedSource, WrapErr};
use pixi_spec::PixiSpec;
use rattler_conda_types::{ChannelConfig, MatchSpec, PackageName, Platform, Version};
use toml_edit::DocumentMut;
use toml_edit::{DocumentMut, Value};

use crate::{
consts,
Expand Down Expand Up @@ -531,14 +531,25 @@ impl Manifest {
};
let to_add: IndexSet<_> = channels.into_iter().collect();
let new: IndexSet<_> = to_add.difference(current).cloned().collect();
let new_channels: IndexSet<_> = new
.clone()
.into_iter()
.map(|channel| channel.channel)
.collect();

// Add the channels to the 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();

// Then to the TOML document
let channels = self.document.get_array_mut("channels", feature_name)?;
for channel in new.iter() {
channels.push(channel.channel.to_string())
// clear and recreate from current list
channels.clear();
for channel in current_clone.iter() {
channels.push(Value::from(channel.clone()));
}

Ok(())
Expand All @@ -555,28 +566,35 @@ impl Manifest {
FeatureName::Default => &mut self.parsed.project.channels,
FeatureName::Named(_) => self.feature_mut(feature_name)?.channels_mut(),
};

// Get the channels to remove, while checking if they exist
let to_remove: IndexSet<_> = channels
.into_iter()
.map(|c| {
current
.iter()
.position(|x| x.channel == c.channel)
.position(|x| x.channel.to_string() == c.channel.to_string())
.ok_or_else(|| miette::miette!("channel {} does not exist", c.channel.as_str()))
.map(|_| c)
.map(|_| c.channel.to_string())
})
.collect::<Result<_, _>>()?;

let retained: IndexSet<_> = current.difference(&to_remove).cloned().collect();
let retained: IndexSet<_> = current
.iter()
.filter(|channel| !to_remove.contains(&channel.channel.to_string()))
.cloned()
.collect();

// Remove channels from the manifest
current.retain(|c| retained.contains(c));
let current_clone = current.clone();

// And from the TOML document
let retained = retained.iter().map(|c| c.channel.as_str()).collect_vec();
let channels = self.document.get_array_mut("channels", feature_name)?;
channels.retain(|x| retained.contains(&x.as_str().unwrap()));
// clear and recreate from current list
channels.clear();
for channel in current_clone.iter() {
channels.push(Value::from(channel.clone()));
}

Ok(())
}
Expand Down Expand Up @@ -1534,6 +1552,35 @@ platforms = ["linux-64", "win-64"]
.iter()
.any(|c| c.channel == custom_channel.channel));

// Test adding priority
let prioritized_channel1 = PrioritizedChannel {
channel: NamedChannelOrUrl::Name(String::from("prioritized")),
priority: Some(12i32),
};
manifest
.add_channels([prioritized_channel1.clone()], &FeatureName::Default)
.unwrap();
assert!(manifest
.parsed
.project
.channels
.iter()
.any(|c| c.channel == prioritized_channel1.channel && c.priority == Some(12i32)));

let prioritized_channel2 = PrioritizedChannel {
channel: NamedChannelOrUrl::Name(String::from("prioritized2")),
priority: Some(-12i32),
};
manifest
.add_channels([prioritized_channel2.clone()], &FeatureName::Default)
.unwrap();
assert!(manifest
.parsed
.project
.channels
.iter()
.any(|c| c.channel == prioritized_channel2.channel && c.priority == Some(-12i32)));

assert_snapshot!(manifest.document.to_string());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expression: manifest.document.to_string()
---
[project]
name = "foo"
channels = ["conda-forge", "https://custom.com/channel"]
channels = ["conda-forge", "https://custom.com/channel", { channel = "prioritized", priority = 12 }, { channel = "prioritized2", priority = -12 }]
platforms = ["linux-64", "win-64"]

[dependencies]
Expand Down
1 change: 1 addition & 0 deletions docs/Community.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ When you want to show your users and contributors that they can use pixi in your
- [Rerun](https://www.rerun.io/): Rerun is an SDK for building time aware visualizations of multimodal data.
- [conda-auth](https://github.com/conda-incubator/conda-auth): a conda plugin providing more secure authentication support to conda.
- [py-rattler](https://github.com/mamba-org/rattler/tree/main/py-rattler): Build your own conda environment manager using the python wrapper of our Rattler backend.
- [array-api-extra](https://github.com/data-apis/array-api-extra): Extra array functions built on top of the Python array API standard.
13 changes: 13 additions & 0 deletions docs/basic_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,19 @@ pixi global install rattler-build
pixi global install ruff
```

### Using the --no-activation option

When installing packages globally, you can use the `--no-activation` option to prevent the insertion of environment activation code into the installed executable scripts. This means that when you run the installed executable, it won't modify the `PATH` or `CONDA_PREFIX` environment variables beforehand.

Example:

```shell
# Install a package without inserting activation code
pixi global install ruff --no-activation
```

This option can be useful in scenarios where you want more control over the environment activation or if you're using the installed executables in contexts where automatic activation might interfere with other processes.

## Use pixi in GitHub Actions

You can use pixi in GitHub Actions to install dependencies and run commands.
Expand Down
16 changes: 15 additions & 1 deletion docs/design_proposals/pixi_global_manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Multiple channels can be specified by using `--channel` multiple times.
By default, if no channel is provided, the `default-channels` key in the pixi configuration is used, which again defaults to "conda-forge".

```
pixi global install [--expose MAPPING] [--environment ENV] [--platform PLATFORM] [--channel CHANNEL]... PACKAGE...
pixi global install [--expose MAPPING] [--environment ENV] [--platform PLATFORM] [--no-activation] [--channel CHANNEL]... PACKAGE...
```

Remove environments `ENV`.
Expand Down Expand Up @@ -294,3 +294,17 @@ In order to make it easier to manage manifests in version control, we could allo
``` title="config.toml"
global_manifests = "/path/to/your/manifests"
```


### No activation

The current `pixi global install` features `--no-activation`.
When this flag is set, `CONDA_PREFIX` and `PATH` will not be set when running the exposed executable.
This is useful when installing Python package managers or shells.

Assuming that this needs to be set per mapping, one way to expose this functionality would be to allow the following:

```toml
[envs.pip.exposed]
pip = { executable="pip", activation=false }
```
4 changes: 4 additions & 0 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,7 @@ This command installs package(s) into its own environment and adds the binary to

- `--channel <CHANNEL> (-c)`: specify a channel that the project uses. Defaults to `conda-forge`. (Allowed to be used more than once)
- `--platform <PLATFORM> (-p)`: specify a platform that you want to install the package for. (default: current platform)
- `--no-activation`: Do not insert conda_prefix, path modifications, and activation script into the installed executable script.

```shell
pixi global install ruff
Expand All @@ -952,6 +953,9 @@ pixi global install python=3.11.0=h10a6764_1_cpython

# Install for a specific platform, only useful on osx-arm64
pixi global install --platform osx-64 ruff

# Install without inserting activation code into the executable script
pixi global install ruff --no-activation
```

!!! tip
Expand Down
7 changes: 3 additions & 4 deletions scripts/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,9 @@ def main():
)
status.append("Checked main branch and CI status")

if start_step <= 3:
release_version = get_release_version()
os.environ["RELEASE_VERSION"] = release_version
status.append(f"Release version set to {release_version}")
release_version = get_release_version()
os.environ["RELEASE_VERSION"] = release_version
status.append(f"Release version set to {release_version}")

if start_step <= 4:
colored_print("\nCreating a new branch for the release...", "yellow")
Expand Down
27 changes: 25 additions & 2 deletions src/cli/global/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ pub struct Args {

#[clap(flatten)]
config: ConfigCli,

/// Do not insert `CONDA_PREFIX`, `PATH` modifications into the installed executable script.
#[clap(long)]
no_activation: bool,
}

impl HasSpecs for Args {
Expand Down Expand Up @@ -212,13 +216,23 @@ pub(super) async fn create_executable_scripts(
prefix: &Prefix,
shell: &ShellEnum,
activation_script: String,
no_activation: bool,
) -> miette::Result<()> {
for BinScriptMapping {
original_executable: exec,
global_binary_path: executable_script_path,
} in mapped_executables
{
let mut script = activation_script.clone();
let mut script = if no_activation {
if cfg!(unix) {
"#!/bin/sh\n".to_string()
} else {
String::new()
}
} else {
activation_script.clone()
};

shell
.run_command(
&mut script,
Expand Down Expand Up @@ -342,6 +356,7 @@ pub async fn execute(args: Args) -> miette::Result<()> {
solved_records.clone(),
auth_client.clone(),
args.platform,
args.no_activation,
)
.await?;
let channel_name =
Expand Down Expand Up @@ -410,6 +425,7 @@ pub(super) async fn globally_install_package(
records: Vec<RepoDataRecord>,
authenticated_client: ClientWithMiddleware,
platform: Platform,
no_activation: bool,
) -> miette::Result<(PrefixRecord, Vec<PathBuf>, bool)> {
try_increase_rlimit_to_sensible();

Expand Down Expand Up @@ -460,7 +476,14 @@ pub(super) async fn globally_install_package(
let bin_dir = BinDir::create().await?;
let script_mapping =
find_and_map_executable_scripts(&prefix, &prefix_package, &bin_dir).await?;
create_executable_scripts(&script_mapping, &prefix, &shell, activation_script).await?;
create_executable_scripts(
&script_mapping,
&prefix,
&shell,
activation_script,
no_activation,
)
.await?;

let scripts: Vec<_> = script_mapping
.into_iter()
Expand Down
1 change: 1 addition & 0 deletions src/cli/global/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ pub(super) async fn upgrade_packages(
records,
authenticated_client.clone(),
platform,
false,
)
.await?;
pb.finish_with_message(format!("{} {}", console::style("Updated").green(), message));
Expand Down
Loading

0 comments on commit 56eca5d

Please sign in to comment.