Skip to content

Commit f06a0ec

Browse files
committed
Add more edge cases in conda autodetect
1/ Sometimes (W11, cmd.exe) 'where conda' returns and error: " INFO: Could not find files for the given pattern(s)." We must not treat this as a path. '2/ where conda' is only available in conda-specific prompts, we should help users by checking if Java inherited any conda environment variables (Method 1)
1 parent 58f8248 commit f06a0ec

1 file changed

Lines changed: 112 additions & 12 deletions

File tree

src/main/java/fiji/plugin/trackmate/util/cli/condapath/CondaDetector.java

Lines changed: 112 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ private static CondaInfo detectCondaInfo()
184184
return info;
185185

186186
// Method 2: Parse shell config files (critical for macOS/Linux GUI apps)
187+
IJ.log( "" );
187188
if ( isMac() || isLinux() )
188189
{
189190
info = detectFromShellConfig();
@@ -194,19 +195,21 @@ private static CondaInfo detectCondaInfo()
194195
{
195196
IJ.log( "Method 2: Parsing shell configuration files..." );
196197
IJ.log( " Skipped (only applicable on macOS/Linux)" );
197-
IJ.log( "" );
198198
}
199199

200200
// Method 3: Search in PATH
201+
IJ.log( "" );
201202
info = detectFromPath();
202203
if ( info != null )
203204
return info;
204205

205206
// Method 4: Check common installation locations (fallback)
207+
IJ.log( "" );
206208
info = detectFromCommonLocations();
207209
if ( info != null )
208210
return info;
209211

212+
IJ.log( "" );
210213
IJ.log( "Failed to detect conda installation" );
211214
return null;
212215
}
@@ -217,21 +220,32 @@ private static CondaInfo detectCondaInfo()
217220
private static CondaInfo detectFromEnvironment()
218221
{
219222
IJ.log( "Method 1: Checking CONDA_EXE environment variable..." );
223+
224+
// Check CONDA_EXE first
220225
String condaExe = System.getenv( "CONDA_EXE" );
226+
227+
// Also check for _CONDA_EXE (sometimes set by conda)
228+
if ( condaExe == null || condaExe.isEmpty() )
229+
condaExe = System.getenv( "_CONDA_EXE" );
230+
221231
if ( condaExe != null && new File( condaExe ).exists() )
222232
{
223233
// Resolve symlinks/aliases
224234
condaExe = resolveRealExecutable( condaExe );
225235

226-
final String rootPrefix = deriveRootPrefix( condaExe );
227-
final String version = getCondaVersion( condaExe );
228-
229-
if ( rootPrefix != null && version != null )
236+
if ( condaExe != null )
230237
{
231-
IJ.log( " Found conda via CONDA_EXE: " + condaExe );
232-
return new CondaInfo( condaExe, rootPrefix, version );
238+
final String rootPrefix = deriveRootPrefix( condaExe );
239+
final String version = getCondaVersion( condaExe );
240+
241+
if ( rootPrefix != null && version != null )
242+
{
243+
IJ.log( " Found conda via CONDA_EXE: " + condaExe );
244+
return new CondaInfo( condaExe, rootPrefix, version );
245+
}
233246
}
234247
}
248+
235249
IJ.log( " CONDA_EXE not set or invalid" );
236250
return null;
237251
}
@@ -794,12 +808,25 @@ private static String findInPath( final String executable )
794808

795809
try
796810
{
797-
final Process process = new ProcessBuilder( command )
798-
.redirectErrorStream( true )
799-
.start();
811+
final ProcessBuilder pb = new ProcessBuilder( command );
812+
pb.redirectErrorStream( true );
813+
final Process process = pb.start();
800814

801815
final String output = readProcessOutput( process );
802-
process.waitFor( 5, TimeUnit.SECONDS );
816+
final boolean completed = process.waitFor( 5, TimeUnit.SECONDS );
817+
818+
// Check exit code - 'where' returns non-zero when not found
819+
if ( !completed )
820+
{
821+
IJ.log( " Command timed out searching for '" + executable + "'" );
822+
return null;
823+
}
824+
825+
if ( process.exitValue() != 0 )
826+
{
827+
IJ.log( " '" + executable + "' not found in PATH" );
828+
return null;
829+
}
803830

804831
if ( output != null && !output.isEmpty() )
805832
{
@@ -814,6 +841,23 @@ private static String findInPath( final String executable )
814841
if ( path.isEmpty() )
815842
continue;
816843

844+
// Skip error messages from Windows 'where' command
845+
if ( path.startsWith( "INFO:" ) ||
846+
path.startsWith( "ERROR:" ) ||
847+
path.startsWith( "WARNING:" ) ||
848+
path.contains( "Could not find" ) )
849+
{
850+
IJ.log( " Skipping error message: " + path );
851+
continue;
852+
}
853+
854+
// Validate that this looks like a real path
855+
if ( !isValidPath( path ) )
856+
{
857+
IJ.log( " Skipping invalid path format: " + path );
858+
continue;
859+
}
860+
817861
// On Windows, skip conda in Library\bin (it's a helper
818862
// script)
819863
if ( isWindows() && path.contains( "\\Library\\bin\\conda" ) )
@@ -822,6 +866,13 @@ private static String findInPath( final String executable )
822866
continue;
823867
}
824868

869+
// Verify the file actually exists
870+
if ( !new File( path ).exists() )
871+
{
872+
IJ.log( " Skipping non-existent path: " + path );
873+
continue;
874+
}
875+
825876
// Resolve symlinks on Unix
826877
if ( !isWindows() )
827878
{
@@ -841,12 +892,61 @@ private static String findInPath( final String executable )
841892
}
842893
catch ( final Exception e )
843894
{
844-
// Command failed
895+
IJ.log( " Error searching PATH: " + e.getMessage() );
845896
}
846897

847898
return null;
848899
}
849900

901+
/**
902+
* Validate that a string looks like a valid file path
903+
*/
904+
private static boolean isValidPath( final String path )
905+
{
906+
if ( path == null || path.isEmpty() )
907+
return false;
908+
909+
// Check for obvious non-path patterns (error messages)
910+
if ( path.startsWith( "INFO:" ) ||
911+
path.startsWith( "ERROR:" ) ||
912+
path.startsWith( "WARNING:" ) ||
913+
path.toLowerCase().contains( "could not find" ) ||
914+
path.toLowerCase().contains( "not recognized" ) )
915+
return false;
916+
917+
if ( isWindows() )
918+
{
919+
// Windows paths should contain : (drive letter) or start with \\
920+
// (UNC)
921+
// or at least contain \ (subdirectory)
922+
if ( !path.contains( ":" ) && !path.startsWith( "\\\\" ) && !path.contains( "\\" ) )
923+
{
924+
// Might be a relative path - check if file exists
925+
if ( !new File( path ).exists() )
926+
return false;
927+
}
928+
929+
// Check for invalid Windows path characters that indicate error
930+
// messages
931+
final String invalidChars = "<>|\u0000";
932+
for ( int i = 0; i < invalidChars.length(); i++ )
933+
{
934+
if ( path.indexOf( invalidChars.charAt( i ) ) >= 0 )
935+
return false;
936+
}
937+
}
938+
else
939+
{
940+
// Unix paths should start with / (absolute) or contain / (relative)
941+
// Simple heuristic: if it's long, has spaces, but no /, probably an
942+
// error message
943+
if ( !path.contains( "/" ) && path.contains( " " ) && path.length() > 30 )
944+
return false;
945+
}
946+
947+
return true;
948+
}
949+
850950
/**
851951
* Build path to conda/mamba/micromamba executable from installation
852952
* directory

0 commit comments

Comments
 (0)