2009-06-01 8 views
13

Estoy escribiendo un programa en el que llaman Scala:.Cómo comprobar la existencia de un programa en el camino

Runtime.getRuntime().exec("svn ...") 

Quiero comprobar si "SVN" está disponible desde la línea de comandos (es decir, es alcanzable en el camino). ¿Cómo puedo hacer esto?

PS: Mi programa está diseñado para ejecutarse en Windows

Respuesta

13

No soy un programador Scala, pero lo que haría en cualquier idioma, es ejecutar algo así como 'svn help' sólo para comprobar el código de retorno (0 o 1) del método exec ... si falla el sVN no está en el camino: P

Runtime rt = Runtime.getRuntime(); 
Process proc = rt.exec("svn help"); 
int exitVal = proc.exitValue(); 

Por convención, el valor 0 indica la terminación normal.

+0

Creo que sería mejor que hacer "que svn" en lugar de "ayuda SVN". Todavía dará el código de retorno adecuado para determinar si svn existe o no en la ruta, pero en caso de éxito también obtendrá la ruta completa al ejecutable svn. – Apreche

+5

"which" no es un comando de Windows. – EMMERICH

+0

"donde" es el equivalente de Windows de "que" –

2

cuanto a la pregunta original que también haría el ingreso por la existencia como lo sugiere la FMF.

También me gustaría señalar que vas a tener que manejar al menos la salida del proceso, la lectura de los datos disponibles hasta las corrientes no se llenaron hasta arriba. Esto causaría que el proceso se bloquee, de lo contrario.

Para ello, recuperar los InputStreams del proceso utilizando proc.getInputStream() (por System.out) y proc.getErrorStream() (para System.err) y leer los datos disponibles en diferentes hilos.

te acabo de decir, porque esto es un error común y SVN potencialmente crear un poco de salida por lo que no Downvote para offtopicness;)

0

Si ha instalado cygwin se podría llamar primero ", que SVN ", que devolverá la ruta absoluta al svn si está en la ruta ejecutable, o de lo contrario 'que: no sVN (...)'. La llamada a "que" devolverá un exitValue de 1 si no lo encuentra, o 0 si se encuentra. Puede verificar este código de error de la manera en que FMF detalla.

13

Tal vez alguien estaría interesado en la solución de Java 8:

String exec = <executable name>; 
boolean existsInPath = Stream.of(System.getenv("PATH").split(Pattern.quote(File.pathSeparator))) 
     .map(Paths::get) 
     .anyMatch(path -> Files.exists(path.resolve(exec))); 

Por cierto, se puede reemplazar con anyMatch(...)filter(...).findFirst() - de manera que obtendrá la ruta ejecutable exacta.

+0

Estará mejor con 'Pattern.splitAsStream' ... –

+0

Cuando pruebo esto y lo ejecuto dentro de mi IDE (estoy usando Eclipse), no puede encontrar un archivo cuya ruta se haya agregado a mi entorno PATH variable. Sin embargo, cuando creo un JRE ejecutable desde allí y lo ejecuto desde mi terminal, funciona. Así que sospecho que mi PATH desde mi IDE no es lo mismo que mi PATH cuando abro un terminal. ¿Cómo puedo evitar esto? Prefiero no hacer un Jar ejecutable cada vez que quiero probar el código. ¡Gracias! – skrilmps

+0

Tampoco estoy haciendo que esto funcione en Windows. Si configuro 'exec = java' obtengo un resultado falso. Pero si ejecuto 'where java' desde cmd obtengo un hit. – skrilmps

4

selenio tiene lo que parece ser una aplicación bastante completa para Windows/Linux/Mac en la clase org.openqa.selenium.os.ExecutableFinder, con acceso desde public Selenio 3.1 (anteriormente sólo se puede acceder a través del método en desuso org.openqa.selenium.os.CommandLine#find). Sin embargo, es ASL 2.0.

Tenga en cuenta que ExecutableFinder no entiende PATHEXT en Windows - sólo tiene un conjunto codificado de extensiones de archivos ejecutables (.exe, .com, .bat).

+1

Es público ahora: https://github.com/SeleniumHQ/selenium/blob/master/java/client/src/org/openqa/selenium/os/ExecutableFinder.java#L48 – gouessej

+0

Gracias @gouessej. Parece que todavía no forma parte de un lanzamiento: https://github.com/SeleniumHQ/selenium/blob/selenium-3.0.1/java/client/src/org/openqa/selenium/os/ExecutableFinder.java#L35 – seanf

3

este código usa el comando "where" en Windows, y el comando "which" en otros sistemas, para verificar si el sistema conoce el programa deseado en PATH. Si se encuentra, la función devuelve un java.nio.file.Path para el programa, y ​​null de lo contrario.

Lo probé con Java 8 en Windows 7 y Linux Mint 17.3.

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import java.util.logging.Logger; 


public class SimulationUtils 
{ 
    private final static Logger LOGGER = Logger.getLogger(SimulationUtils.class.getName()); 

    public static Path lookForProgramInPath(String desiredProgram) { 
     ProcessBuilder pb = new ProcessBuilder(isWindows() ? "where" : "which", desiredProgram); 
     Path foundProgram = null; 
     try { 
      Process proc = pb.start(); 
      int errCode = proc.waitFor(); 
      if (errCode == 0) { 
       try (BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()))) { 
        foundProgram = Paths.get(reader.readLine()); 
       } 
       LOGGER.info(desiredProgram + " has been found at : " + foundProgram); 
      } else { 
       LOGGER.warning(desiredProgram + " not in PATH"); 
      } 
     } catch (IOException | InterruptedException ex) { 
      LOGGER.warning("Something went wrong while searching for " + desiredProgram); 
     } 
     return foundProgram; 
    } 

    private static boolean isWindows() { 
     return System.getProperty("os.name").toLowerCase().contains("windows"); 
    } 
} 

Para usarlo:

System.out.println(SimulationUtils.lookForProgramInPath("notepad")); 

En mi sistema Windows 7, se muestra:

C: \ Windows \ System32 \ notepad.exe

Y en linux:

System.out.println(SimulationUtils.lookForProgramInPath("psql")); 

/usr/bin/psql

La ventaja de este método es que debería funcionar en cualquier plataforma y no hay necesidad de analizar la variable de entorno PATH o mirar en el registro. El programa deseado nunca se llama, incluso si se encuentra. Finalmente, no hay necesidad de saber la extensión del programa. gnuplot.exe bajo Windows y en Linux sería gnuplot tanto ser encontrado por el mismo código:

SimulationUtils.lookForProgramInPath("gnuplot") 

Las sugerencias para mejorar son bienvenidos!

+0

Esto realmente tiene un rendimiento terrible. Llamar a procesos externos debe evitarse tanto como sea posible. – BullyWiiPlaza

+1

@BullyWiiPlaza: Bueno, lograr un buen rendimiento tampoco era mi objetivo. Si tiene alguna idea de cómo podría ser más rápido mientras todavía trabaja en Windows/Linux/MacOS, siéntase libre de sugerir cualquier cosa. Por cierto, el resultado podría ser almacenado en caché. Finalmente, el objetivo es llamar a un proceso externo. Cualquier llamada 'svn' será probablemente mucho más lenta que' where' o 'which'. –

+0

Sí, la respuesta anterior de 'Dmitry Ginzburg' es realmente buena. 'where' tiene una sobrecarga relativamente grande (puede ser más de 100 - 200ms) y si lo llamas varias veces se te va de las manos. Me di cuenta de esto en mi código de por qué era notablemente más lento. – BullyWiiPlaza

0

En mi experiencia, es imposible saber sobre los distintos sistemas a través de simplemente llamar a un comando con el ProcessBuilder si sale o no (ni Exceptions ni devolver valores parecen coherentes)

Así que aquí es una solución Java7 que atraviesa la variable de entorno PATH y busca una herramienta de coincidencia. Verificará todos los archivos si el directorio. El matchesExecutable debe ser el nombre de la herramienta que ignora la extensión y el estuche.

public static File checkAndGetFromPATHEnvVar(final String matchesExecutable) { 
    String[] pathParts = System.getenv("PATH").split(File.pathSeparator); 
    for (String pathPart : pathParts) { 
     File pathFile = new File(pathPart); 

     if (pathFile.isFile() && pathFile.getName().toLowerCase().contains(matchesExecutable)) { 
      return pathFile; 
     } else if (pathFile.isDirectory()) { 
      File[] matchedFiles = pathFile.listFiles(new FileFilter() { 
       @Override 
       public boolean accept(File pathname) { 
        return FileUtil.getFileNameWithoutExtension(pathname).toLowerCase().equals(matchesExecutable); 
       } 
      }); 

      if (matchedFiles != null) { 
       for (File matchedFile : matchedFiles) { 
        if (FileUtil.canRunCmd(new String[]{matchedFile.getAbsolutePath()})) { 
         return matchedFile; 
        } 
       } 
      } 
     } 
    } 
    return null; 
} 

Éstos son el ayudante:

public static String getFileNameWithoutExtension(File file) { 
     String fileName = file.getName(); 
     int pos = fileName.lastIndexOf("."); 
     if (pos > 0) { 
      fileName = fileName.substring(0, pos); 
     } 
     return fileName; 
} 

public static boolean canRunCmd(String[] cmd) { 
     try { 
      ProcessBuilder pb = new ProcessBuilder(cmd); 
      pb.redirectErrorStream(true); 
      Process process = pb.start(); 
      try (BufferedReader inStreamReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { 
       while ((inStreamReader.readLine()) != null) { 
       } 
      } 
      process.waitFor(); 
     } catch (Exception e) { 
      return false; 
     } 
     return true; 
} 
Cuestiones relacionadas