@@ -36,6 +36,30 @@ fn get_conda_executable(path: &Path) -> Option<PathBuf> {
3636 None
3737}
3838
39+ fn get_mamba_executable ( path : & Path ) -> Option < PathBuf > {
40+ #[ cfg( windows) ]
41+ let relative_paths = vec ! [
42+ PathBuf :: from( "Scripts" ) . join( "mamba.exe" ) ,
43+ PathBuf :: from( "Scripts" ) . join( "micromamba.exe" ) ,
44+ PathBuf :: from( "bin" ) . join( "mamba.exe" ) ,
45+ PathBuf :: from( "bin" ) . join( "micromamba.exe" ) ,
46+ ] ;
47+ #[ cfg( unix) ]
48+ let relative_paths = vec ! [
49+ PathBuf :: from( "bin" ) . join( "mamba" ) ,
50+ PathBuf :: from( "bin" ) . join( "micromamba" ) ,
51+ ] ;
52+
53+ for relative_path in relative_paths {
54+ let exe = path. join ( & relative_path) ;
55+ if exe. exists ( ) {
56+ return Some ( exe) ;
57+ }
58+ }
59+
60+ None
61+ }
62+
3963/// Specifically returns the file names that are valid for 'conda' on windows
4064#[ cfg( windows) ]
4165fn get_conda_bin_names ( ) -> Vec < & ' static str > {
@@ -48,6 +72,18 @@ fn get_conda_bin_names() -> Vec<&'static str> {
4872 vec ! [ "conda" ]
4973}
5074
75+ /// Specifically returns the file names that are valid for 'mamba'/'micromamba' on windows
76+ #[ cfg( windows) ]
77+ fn get_mamba_bin_names ( ) -> Vec < & ' static str > {
78+ vec ! [ "mamba.exe" , "micromamba.exe" ]
79+ }
80+
81+ /// Specifically returns the file names that are valid for 'mamba'/'micromamba' on linux/Mac
82+ #[ cfg( unix) ]
83+ fn get_mamba_bin_names ( ) -> Vec < & ' static str > {
84+ vec ! [ "mamba" , "micromamba" ]
85+ }
86+
5187/// Find the conda binary on the PATH environment variable
5288pub fn find_conda_binary ( env_vars : & EnvVariables ) -> Option < PathBuf > {
5389 let paths = env_vars. path . clone ( ) ?;
@@ -62,17 +98,32 @@ pub fn find_conda_binary(env_vars: &EnvVariables) -> Option<PathBuf> {
6298 None
6399}
64100
101+ /// Find a mamba or micromamba binary on the PATH environment variable
102+ pub fn find_mamba_binary ( env_vars : & EnvVariables ) -> Option < PathBuf > {
103+ let paths = env_vars. path . clone ( ) ?;
104+ for path in env:: split_paths ( & paths) {
105+ for bin in get_mamba_bin_names ( ) {
106+ let mamba_path = path. join ( bin) ;
107+ if mamba_path. is_file ( ) || mamba_path. is_symlink ( ) {
108+ return Some ( mamba_path) ;
109+ }
110+ }
111+ }
112+ None
113+ }
114+
65115#[ derive( Debug , Clone ) ]
66116pub struct CondaManager {
67117 pub executable : PathBuf ,
68118 pub version : Option < String > ,
69119 pub conda_dir : Option < PathBuf > ,
120+ pub manager_type : EnvManagerType ,
70121}
71122
72123impl CondaManager {
73124 pub fn to_manager ( & self ) -> EnvManager {
74125 EnvManager {
75- tool : EnvManagerType :: Conda ,
126+ tool : self . manager_type ,
76127 executable : self . executable . clone ( ) ,
77128 version : self . version . clone ( ) ,
78129 }
@@ -85,7 +136,9 @@ impl CondaManager {
85136 // If this environment is in a folder named `envs`, then the parent directory of `envs` is the root conda install folder.
86137 if let Some ( parent) = path. ancestors ( ) . nth ( 2 ) {
87138 if is_conda_install ( parent) {
88- if let Some ( manager) = get_conda_manager ( parent) {
139+ if let Some ( manager) =
140+ get_conda_manager ( parent) . or_else ( || get_mamba_manager ( parent) )
141+ {
89142 return Some ( manager) ;
90143 }
91144 }
@@ -98,6 +151,7 @@ impl CondaManager {
98151 // Or its in a location such as `~/.conda/envs` or `~/miniconda3/envs` where the conda install folder is not a parent of this path.
99152 if let Some ( conda_install_folder) = get_conda_installation_used_to_create_conda_env ( path) {
100153 get_conda_manager ( & conda_install_folder)
154+ . or_else ( || get_mamba_manager ( & conda_install_folder) )
101155 } else {
102156 // If this is a conda env and the parent is `.conda/envs`, then this is definitely NOT a root conda install folder.
103157 // Hence never use conda installs from these env paths.
@@ -111,19 +165,24 @@ impl CondaManager {
111165 }
112166 }
113167
114- if let Some ( manager) = get_conda_manager ( path) {
168+ if let Some ( manager) = get_conda_manager ( path) . or_else ( || get_mamba_manager ( path ) ) {
115169 Some ( manager)
116170 } else {
117- trace ! ( "No conda manager found for path: {:?}" , path) ;
171+ trace ! ( "No conda or mamba manager found for path: {:?}" , path) ;
118172 None
119173 }
120174 }
121175 }
122- pub fn from_info ( executable : & Path , info : & CondaInfo ) -> Option < CondaManager > {
176+ pub fn from_info (
177+ executable : & Path ,
178+ info : & CondaInfo ,
179+ manager_type : EnvManagerType ,
180+ ) -> Option < CondaManager > {
123181 Some ( CondaManager {
124182 executable : executable. to_path_buf ( ) ,
125183 version : Some ( info. conda_version . clone ( ) ) ,
126184 conda_dir : info. conda_prefix . clone ( ) ,
185+ manager_type,
127186 } )
128187 }
129188}
@@ -135,8 +194,32 @@ fn get_conda_manager(path: &Path) -> Option<CondaManager> {
135194 executable : conda_exe,
136195 version : Some ( conda_pkg. version ) ,
137196 conda_dir : Some ( path. to_path_buf ( ) ) ,
197+ manager_type : EnvManagerType :: Conda ,
138198 } )
139199 } else {
140200 None
141201 }
142202}
203+
204+ /// Checks whether a given executable path refers to a mamba or micromamba binary.
205+ pub fn is_mamba_executable ( exe : & Path ) -> bool {
206+ if let Some ( name) = exe. file_name ( ) . and_then ( |n| n. to_str ( ) ) {
207+ let name = name. to_lowercase ( ) ;
208+ name. starts_with ( "mamba" ) || name. starts_with ( "micromamba" )
209+ } else {
210+ false
211+ }
212+ }
213+
214+ pub ( crate ) fn get_mamba_manager ( path : & Path ) -> Option < CondaManager > {
215+ let mamba_exe = get_mamba_executable ( path) ?;
216+ // We cannot reliably determine the mamba/micromamba version from package metadata alone.
217+ // The conda package version in conda-meta is the conda version, not the mamba version.
218+ // Determining the mamba version would require spawning the mamba process.
219+ Some ( CondaManager {
220+ executable : mamba_exe,
221+ version : None ,
222+ conda_dir : Some ( path. to_path_buf ( ) ) ,
223+ manager_type : EnvManagerType :: Mamba ,
224+ } )
225+ }
0 commit comments