11import shutil
2+ import sys
3+ from pathlib import Path
4+ from typing import Any
25
36from returns .result import Failure , Result , Success
47
58from .async_subprocess import subprocess_exec
69
7- MINIMUM_PIXI_VERSION = (0 , 30 , 0 )
10+ if sys .version_info >= (3 , 11 ):
11+ import tomllib
12+ else :
13+ import tomli as tomllib
14+
15+
16+ MINIMUM_PIXI_VERSION = (0 , 39 , 0 )
817
918
1019PIXI_NOT_FOUND = """Pixi was not detected in your system.
3443"""
3544
3645
46+ def get_config_file () -> Path :
47+ return Path .home () / ".config" / "pixi-kernel" / "config.toml"
48+
49+
50+ def get_default_pixi_path () -> Path :
51+ if sys .platform == "win32" :
52+ return Path .home () / ".pixi" / "bin" / "pixi.exe"
53+ else :
54+ return Path .home () / ".pixi" / "bin" / "pixi"
55+
56+
57+ def find_pixi_binary () -> Result [str , None ]:
58+ # 1. Check if the Pixi binary is available in the system PATH
59+ pixi_path = shutil .which ("pixi" )
60+ if pixi_path is not None :
61+ return Success (pixi_path )
62+
63+ # 2. Check if a config file exists and read the Pixi path from it
64+ config_file = get_config_file ()
65+ if config_file .is_file ():
66+ try :
67+ content = Path (config_file ).read_text ()
68+ config = tomllib .loads (content )
69+ pixi_path = config .get ("pixi-path" )
70+ if pixi_path is not None and Path (pixi_path ).is_file ():
71+ return Success (pixi_path )
72+ except (OSError , tomllib .TOMLDecodeError ):
73+ pass
74+
75+ # 3. Check if the default installation path exists
76+ # https://pixi.sh/latest/installation/#installer-script-options
77+ default_pixi_path = get_default_pixi_path ()
78+ if default_pixi_path .is_file ():
79+ return Success (str (default_pixi_path ))
80+
81+ return Failure (None )
82+
83+
3784async def has_compatible_pixi () -> Result [None , str ]:
38- if shutil .which ("pixi" ) is None :
85+ result = find_pixi_binary ()
86+
87+ if isinstance (result , Failure ):
3988 return Failure (PIXI_NOT_FOUND )
89+ else :
90+ pixi_path = result .unwrap ()
4091
41- returncode , stdout , stderr = await subprocess_exec ("pixi" , "--version" )
92+ returncode , stdout , stderr = await subprocess_exec (pixi_path , "--version" )
4293 if returncode != 0 or not stdout .startswith ("pixi " ):
4394 return Failure (PIXI_VERSION_ERROR )
4495
@@ -50,3 +101,11 @@ async def has_compatible_pixi() -> Result[None, str]:
50101 return Failure (PIXI_OUTDATED .format (minimum_version = minimum_version ))
51102
52103 return Success (None )
104+
105+
106+ async def run_pixi (* args : str , ** kwargs : Any ) -> tuple [int , str , str ]:
107+ # It is safe to unwrap as `has_compatible_pixi()` would already have checked for a compatible
108+ # Pixi binary.
109+ pixi = find_pixi_binary ().unwrap ()
110+
111+ return await subprocess_exec (pixi , * args , ** kwargs )
0 commit comments