Skip to content

Commit 15124b5

Browse files
Add Pixi locator (#172)
Fixes #46 I'd like to reopen the discussion about adding support for Pixi given the community interest after the above issue was closed and to bring feature parity with the `js` locator. Because Pixi environments have a unique directory layout, the proposed solution is simple enough that it doesn't need any process spawning. Sister PR: - microsoft/vscode-python#24442
1 parent 3708544 commit 15124b5

File tree

14 files changed

+193
-27
lines changed

14 files changed

+193
-27
lines changed

.devcontainer/linux-homebrew/Dockerfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ RUN curl https://raw.githubusercontent.com/DonJayamanne/vscode-jupyter/container
1010
RUN echo "# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh." >> ~/.zshrc
1111
RUN echo "[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh" >> ~/.zshrc
1212

13-
# Install Pythone
13+
# Install Python
14+
# homebrew/brew:4.4.6 broke running `brew install` as root.
15+
# As a workaround, running `brew update` and ignoring errors coming from it fixes `brew install`.
16+
RUN brew update || true
1417
1518

1619
# Install Rust

.github/workflows/pr-check.yml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,23 @@ jobs:
167167

168168
# endregion venv
169169

170+
# region Pixi
171+
- name: Install Pixi
172+
uses: prefix-dev/[email protected]
173+
with:
174+
run-install: false
175+
176+
- name: Create Pixi environments
177+
run: |
178+
pixi init
179+
pixi add python
180+
pixi add --feature dev python
181+
pixi project environment add --feature dev dev
182+
pixi install --environment dev
183+
shell: bash
184+
185+
# endregion Pixi
186+
170187
# Rust
171188
- name: Rust Tool Chain setup
172189
uses: dtolnay/rust-toolchain@stable
@@ -395,7 +412,11 @@ jobs:
395412
# Homebrew
396413
- name: Homebrew Python
397414
if: startsWith( matrix.image, 'homebrew')
398-
415+
run: |
416+
# homebrew/brew:4.4.6 broke running `brew install` as root.
417+
# As a workaround, running `brew update` and ignoring errors coming from it fixes `brew install`.
418+
brew update || true
419+
399420
shell: bash
400421

401422
# Rust

Cargo.lock

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/pet-conda/README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@
3636
- Thus using the `history` file we can find the conda installation folder.
3737
This is useful in cases where conda environments are created using `-p` option.
3838

39-
## Known issues
40-
41-
- Note: pixi seems to use conda envs internall, hence its possible to falsely identify a pixi env as a conda env.
42-
- However pixi is not supported by this tool, hence thats not a concern.
43-
4439
## Miscellanous
4540

4641
- What if conda is installed in some custom locations that we have no idea about?

crates/pet-core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub enum LocatorKind {
4747
MacPythonOrg,
4848
MacXCode,
4949
PipEnv,
50+
Pixi,
5051
Poetry,
5152
PyEnv,
5253
Venv,

crates/pet-core/src/python_environment.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::{arch::Architecture, manager::EnvManager};
1212
#[derive(Parser, ValueEnum, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug, Hash)]
1313
pub enum PythonEnvironmentKind {
1414
Conda,
15+
Pixi,
1516
Homebrew,
1617
Pyenv,
1718
GlobalPaths, // Python found in global locations like PATH, /usr/bin etc.

crates/pet-pixi/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "pet-pixi"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[target.'cfg(target_os = "windows")'.dependencies]
7+
msvc_spectre_libs = { version = "0.1.1", features = ["error"] }
8+
9+
[dependencies]
10+
pet-conda = { path = "../pet-conda" }
11+
pet-core = { path = "../pet-core" }
12+
pet-python-utils = { path = "../pet-python-utils" }
13+
log = "0.4.21"

crates/pet-pixi/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Pixi
2+
3+
## Notes
4+
5+
- Pixi environments are detected by:
6+
- Searching for Python interpreters in `.pixi/envs` subdirectories within workspace folders
7+
- Checking for a `conda-meta/pixi` file in potential Pixi environment directories (`.pixi/envs/{env_name}`)
8+
- Determining the version of the Python interpreter from the `conda-meta/python-{version}.json` file
9+
10+
This process ensures fast detection without spawning processes.
11+
Note that the Pixi locator should run before Conda since Conda could incorrectly identify Pixi environments as Conda environments.

crates/pet-pixi/src/lib.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
use std::path::{Path, PathBuf};
5+
6+
use pet_conda::package::{CondaPackageInfo, Package};
7+
use pet_core::{
8+
env::PythonEnv,
9+
python_environment::{PythonEnvironment, PythonEnvironmentBuilder, PythonEnvironmentKind},
10+
reporter::Reporter,
11+
Locator, LocatorKind,
12+
};
13+
use pet_python_utils::executable::find_executables;
14+
15+
pub fn is_pixi_env(path: &Path) -> bool {
16+
path.join("conda-meta").join("pixi").is_file()
17+
}
18+
19+
fn get_pixi_prefix(env: &PythonEnv) -> Option<PathBuf> {
20+
env.prefix.clone().or_else(|| {
21+
env.executable.parent().and_then(|parent_dir| {
22+
if is_pixi_env(parent_dir) {
23+
Some(parent_dir.to_path_buf())
24+
} else if parent_dir.ends_with("bin") || parent_dir.ends_with("Scripts") {
25+
parent_dir
26+
.parent()
27+
.filter(|parent| is_pixi_env(parent))
28+
.map(|parent| parent.to_path_buf())
29+
} else {
30+
None
31+
}
32+
})
33+
})
34+
}
35+
36+
pub struct Pixi {}
37+
38+
impl Pixi {
39+
pub fn new() -> Pixi {
40+
Pixi {}
41+
}
42+
}
43+
impl Default for Pixi {
44+
fn default() -> Self {
45+
Self::new()
46+
}
47+
}
48+
49+
impl Locator for Pixi {
50+
fn get_kind(&self) -> LocatorKind {
51+
LocatorKind::Pixi
52+
}
53+
fn supported_categories(&self) -> Vec<PythonEnvironmentKind> {
54+
vec![PythonEnvironmentKind::Pixi]
55+
}
56+
57+
fn try_from(&self, env: &PythonEnv) -> Option<PythonEnvironment> {
58+
get_pixi_prefix(env).and_then(|prefix| {
59+
if !is_pixi_env(&prefix) {
60+
return None;
61+
}
62+
63+
let name = prefix
64+
.file_name()
65+
.and_then(|name| name.to_str())
66+
.unwrap_or_default()
67+
.to_string();
68+
69+
let symlinks = find_executables(&prefix);
70+
71+
let version = CondaPackageInfo::from(&prefix, &Package::Python)
72+
.map(|package_info| package_info.version);
73+
74+
Some(
75+
PythonEnvironmentBuilder::new(Some(PythonEnvironmentKind::Pixi))
76+
.executable(Some(env.executable.clone()))
77+
.name(Some(name))
78+
.prefix(Some(prefix))
79+
.symlinks(Some(symlinks))
80+
.version(version)
81+
.build(),
82+
)
83+
})
84+
}
85+
86+
fn find(&self, _reporter: &dyn Reporter) {}
87+
}

crates/pet/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pet-homebrew = { path = "../pet-homebrew" }
1616
[dependencies]
1717
pet-core = { path = "../pet-core" }
1818
pet-conda = { path = "../pet-conda" }
19+
pet-pixi = { path = "../pet-pixi" }
1920
pet-jsonrpc = { path = "../pet-jsonrpc" }
2021
pet-fs = { path = "../pet-fs" }
2122
pet-pyenv = { path = "../pet-pyenv" }

0 commit comments

Comments
 (0)