Skip to content

Commit

Permalink
Make setting and determining the conda env list more robust.
Browse files Browse the repository at this point in the history
  • Loading branch information
tinevez committed Jan 22, 2025
1 parent fdf59bc commit 10b6cd1
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 11 deletions.
90 changes: 81 additions & 9 deletions src/main/java/fiji/plugin/trackmate/util/cli/CLIUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.io.InputStreamReader;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
Expand All @@ -48,30 +49,51 @@
import ij.IJ;

public class CLIUtils

{

public static final String CONDA_PATH_PREF_KEY = "trackmate.conda.path";

public static Map< String, String > getEnvMap() throws IOException
public static final String CONDA_ROOT_PREFIX_KEY = "trackmate.conda.root.prefix";

public static Map< String, String > getEnvMap() throws Exception
{
// Create a map to store the environment names and paths
final Map< String, String > envMap = new HashMap<>();

// Prepare the command and environment variables.
// Command
final ProcessBuilder pb;
if ( IJ.isWindows() )
pb = new ProcessBuilder( Arrays.asList( "cmd.exe", "/c", "conda", "env", "list" ) );
else
pb = new ProcessBuilder( Arrays.asList( getCondaPath(), "env", "list" ) );
// Env variables.
final Map< String, String > env = new HashMap<>();
final String condaRootPrefix = getCondaRootPrefix();
env.put( "MAMBA_ROOT_PREFIX", condaRootPrefix );
env.put( "CONDA_ROOT_PREFIX", condaRootPrefix );
pb.environment().putAll( env );
// Run and collect output.
final Process process = pb.start();
final BufferedReader reader = new BufferedReader( new InputStreamReader( process.getInputStream() ) );
final BufferedReader stdOutput = new BufferedReader( new InputStreamReader( process.getInputStream() ) );
final BufferedReader stdError = new BufferedReader( new InputStreamReader( process.getErrorStream() ) );

/*
* Did we have an error? Read the error from the command
*/
String s;
String errorOutput = "";
while ( ( s = stdError.readLine() ) != null )
errorOutput += ( s + '\n' );
if ( !errorOutput.isEmpty() )
throw new Exception( "Could not retrieve environment map properly:\n" + errorOutput );

// Read each line of output and extract the environment name and
// path
String line;
while ( ( line = reader.readLine() ) != null )
while ( ( line = stdOutput.readLine() ) != null )
{
line = line.trim();
if ( line.isEmpty() || line.startsWith( "#" ) || line.startsWith( "Name" ) )
line = line.replaceAll( "\\*", "" );
if ( line.isEmpty() || line.startsWith( "#" ) || line.startsWith( "Name" ) || line.startsWith( "──────" ) )
continue;

final String[] parts = line.split( "\\s+" );
Expand All @@ -81,6 +103,22 @@ public static Map< String, String > getEnvMap() throws IOException
final String envPath = parts[ 1 ] + "/bin/python";
envMap.put( envName, envPath );
}
else if ( parts.length == 1 )
{
/*
* When we don't have the right configuration, sometimes the
* list returns the path to the envs but not the name. We try
* then to extract the name from the path.
*/

final String envRoot = parts[ 0 ];
if ( !isValidPath( envRoot ) )
continue;
final Path path = Paths.get( envRoot );
final String envName = path.getFileName().toString();
final String envPath = envRoot + "/bin/python";
envMap.put( envName, envPath );
}
}
return envMap;
}
Expand All @@ -93,7 +131,7 @@ public static List< String > getEnvList()
l.sort( null );
return l;
}
catch ( final IOException e )
catch ( final Exception e )
{
e.printStackTrace();
}
Expand All @@ -118,6 +156,13 @@ public static String getCondaPath()
return prefs.get( CLIUtils.class, CLIUtils.CONDA_PATH_PREF_KEY, findPath );
}

public static String getCondaRootPrefix()
{
final PrefService prefs = TMUtils.getContext().getService( PrefService.class );
final String findPath = "/usr/local/opt/micromamba";
return prefs.get( CLIUtils.class, CLIUtils.CONDA_ROOT_PREFIX_KEY, findPath );
}

public static String findDefaultCondaPath() throws IllegalArgumentException
{
final String username = System.getProperty( "user.name" );
Expand Down Expand Up @@ -246,7 +291,34 @@ else if ( !line.trim().isEmpty() )
}
}

public static void main( final String[] args ) throws IOException
public static boolean isValidPath( final String pathString )
{
try
{
// Convert the string to a Path object
final Path path = Paths.get( pathString );

// Check for basic path characteristics
if ( !pathString.contains( "/" ) && !pathString.contains( "\\" ) )
return false;

// Check for illegal characters (Windows-specific example)
if ( System.getProperty( "os.name" ).toLowerCase().contains( "win" ) )
{
final Pattern illegalCharsPattern = Pattern.compile( "[<>:*?\"|]" );
if ( illegalCharsPattern.matcher( pathString ).find() )
return false;
}

return Files.exists( path );
}
catch ( final InvalidPathException e )
{
return false;
}
}

public static void main( final String[] args ) throws Exception
{
System.out.println( "Conda path: " + findDefaultCondaPath() );
System.out.println( "Known environments: " + getEnvList() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ protected CondaCLIConfigurator()
+ "Please configure the path to your conda executable in Edit > Options > Configure TrackMate Conda path..." );
e.printStackTrace();
}

catch ( final Exception e )
{
System.err.println( "Error running the conda executable:\n" );
e.printStackTrace();
}
}
// Split by spaces
final String executableCommand = getCommand();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ public CondaExecutableCLIConfigurator()
+ "Please configure the path to your conda executable in Edit > Options > Configure TrackMate Conda path..." );
e.printStackTrace();
}
catch ( final Exception e )
{
System.err.println( "Error running the conda executable:\n" );
e.printStackTrace();
}
}
return null;
} );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
package fiji.plugin.trackmate.util.cli;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;

import javax.swing.JLabel;
Expand Down Expand Up @@ -61,22 +63,40 @@ public void run()

String condaPath = prefs.get( CLIUtils.class, CLIUtils.CONDA_PATH_PREF_KEY, findPath );

final Path path = Paths.get( condaPath );
final Path parent = path.getParent();
final Path parentOfParent = ( parent != null ) ? parent.getParent() : null;
final String defaultValue = "/usr/local/opt/micromamba/";

String condaRootPrefix = ( parentOfParent != null ) ? parentOfParent.toString() : defaultValue;
condaRootPrefix = prefs.get( CLIUtils.class, CLIUtils.CONDA_ROOT_PREFIX_KEY, condaRootPrefix );

final GenericDialogPlus dialog = new GenericDialogPlus( "TrackMate Conda path" );
final JLabel lbl = dialog.addImage( GuiUtils.scaleImage( Icons.TRACKMATE_ICON, 64, 64 ) );
lbl.setText( "TrackMate Conda path" );
lbl.setFont( Fonts.BIG_FONT );
dialog.addMessage(
"Browse to the conda (or mamba, micromaba, ...) executable \n"
+ "to use in the TrackMate modules that rely on Conda." );
+ "to use in the TrackMate modules that rely on Conda." );
dialog.addMessage( "Conda executable path:" );
dialog.addFileField( "", condaPath, 40 );
dialog.addMessage( ""
+ "Browse to the conda root prefix. This is the content of \n"
+ "'MAMBA_ROOT_PREFIX' or 'CONDA_ROOT_PREFIX' environment \n"
+ "variable, and points to the root directory of the conda, \n"
+ "mamba or micromamba installation." );
dialog.addMessage( "Conda executable path:" );
dialog.addFileField( "", condaRootPrefix, 40 );

dialog.showDialog();

if ( dialog.wasCanceled() )
return;

condaPath = dialog.getNextString();
condaRootPrefix = dialog.getNextString();
prefs.put( CLIUtils.class, CLIUtils.CONDA_PATH_PREF_KEY, condaPath );
prefs.put( CLIUtils.class, CLIUtils.CONDA_ROOT_PREFIX_KEY, condaRootPrefix );
test();
}

Expand All @@ -96,10 +116,17 @@ public void test()
+ "Error message:\n "
+ e.getMessage() );
}
catch ( final Exception e )
{
IJ.error( "Error when running Conda.\n"
+ "Error message:\n "
+ e.getMessage() );
}
}

public static void main( final String[] args )
{
TMUtils.getContext().getService( CommandService.class ).run( CondaPathConfigCommand.class, false );
// new CondaPathConfigCommand().test();
}
}

0 comments on commit 10b6cd1

Please sign in to comment.