2009-06-01 2 views
13

Я пишу программу в Скале, которые называют:.Как проверить существование программы на пути

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

Я хочу, чтобы проверить, если «СВН» доступен из командной строки (т.е. доступен в PATH). Как я могу это сделать?

PS: Моя программа предназначена для запуска на окнах

ответ

13

Я не Scala программист, но то, что я хотел бы сделать на любом языке, чтобы выполнить что-то вроде «svn help» просто проверить код возврата (0 или 1) с выполняемым методом ... если он не в SVN не в пути: P

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

по соглашению, значение 0 указывает на нормальное завершение.

+0

Я думаю, что было бы лучше сделать «который СВН» вместо «СВН помощи». Он по-прежнему будет давать правильный код возврата относительно того, существует или нет svn в пути, но с успехом вы также получите полный путь к исполняемому файлу svn. – Apreche

+5

"который" не является командой Windows. – EMMERICH

+0

«где» - эквивалент Windows, «который» –

2

Что касается первоначального вопроса, я бы также проверял наличие в качестве FMF.

Я также хотел бы указать, что вам придется обрабатывать хотя бы выходные данные процесса, читая доступные данные, чтобы потоки не были заполнены до краев. В противном случае процесс блокируется.

Для этого необходимо получить InputStreams процесса с помощью proc.getInputStream() (для System.out) и proc.getErrorStream() (для System.err) и прочитать доступные данные в разных потоках.

Я просто говорю вам, потому что это общая ловушкой и СВН потенциально создать совсем немного выходной поэтому, пожалуйста, не downvote для offtopicness;)

0

Если Cygwin установлена, вы могли бы назвать первым «, который СВН », который вернет абсолютный путь к svn, если он находится в исполняемом пути, или« который: no svn in (...) ». Вызов «which» вернет exitValue из 1, если не найден, или 0, если он найден. Вы можете проверить этот код ошибки в виде данных FMF.

13

Может кто-то будет заинтересован в 8 решении Java:

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))); 

Кстати, вы можете заменить anyMatch(...) с filter(...).findFirst() - так что вы получите точный путь к исполняемому файлу.

+0

Вам будет лучше с 'Pattern.splitAsStream' ... –

+0

Когда я пытаюсь это сделать и запускаю его внутри своей IDE (я использую Eclipse), он не может найти файл, у которого был добавлен путь к моей среде PATH переменная. Однако, когда я создаю из него исполняемый JRE и запускаю его с моего терминала, он работает. Поэтому я подозреваю, что мой PATH изнутри моей IDE не такой же, как мой PATH, когда я открываю терминал. Как я могу обойти это? Я бы предпочел не делать runnable Jar каждый раз, когда я хочу проверить код. Благодаря! – skrilmps

+0

Я тоже не получаю, чтобы это работало в Windows. Если я устанавливаю 'exec = java', я получаю ложный результат. Но если я запускаю 'where java' из cmd, я получаю удар. – skrilmps

4

Селена имеет то, что выглядит разумно полная реализация для Windows/Linux/Mac в классе org.openqa.selenium.os.ExecutableFinder с public доступом, так как Selenium 3.1 (ранее доступный только через устаревший метод org.openqa.selenium.os.CommandLine#find). Это ASL 2.0.

Отметьте, что ExecutableFinder не понимает PATHEXT на Windows - он имеет только жестко запрограммированный набор расширений исполняемого файла (.exe, .com, .bat).

+1

Публично сейчас: https://github.com/SeleniumHQ/selenium/blob/master/java/client/src/org/openqa/selenium/os/ExecutableFinder.java#L48 – gouessej

+0

Спасибо @gouessej. Похоже, что это еще не часть релиза: https://github.com/SeleniumHQ/selenium/blob/selenium-3.0.1/java/client/src/org/openqa/selenium/os/ExecutableFinder.java#L35 – seanf

3

Этот код использует команду «где» в Windows и команду «which» в других системах, чтобы проверить, знает ли система о желаемой программе в PATH. Если найдено, функция возвращает java.nio.file.Path программе, а null - в противном случае.

Я тестировал его с помощью Java 8 на Windows 7 и 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"); 
    } 
} 

Чтобы использовать его:

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

В моей системе Windows 7, он отображает:

C: \ Windows \ System32 \ notepad.exe

И по линуксу:

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

/USR/бен/PSQL

Преимущество этого метода заключается в том, что он должен работать на любой платформе, и нет никакой необходимости разобрать переменную окружения PATH или посмотреть на реестр. Желаемая программа никогда не вызывается, даже если она найдена. Наконец, нет необходимости знать расширение программы. gnuplot.exe под Windows, и под Linux Gnuplot бы как можно найти одним и тем же кодом:

SimulationUtils.lookForProgramInPath("gnuplot") 

Предложения по улучшению приветствуются!

+0

У этого действительно ужасная производительность. Вызовы внешних процессов следует избегать как можно больше. – BullyWiiPlaza

+1

@BullyWiiPlaza: Ну, достижение хорошей производительности тоже не было моей целью. Если у вас есть представление о том, как оно может быть быстрее при работе в Windows/Linux/MacOS, не стесняйтесь предлагать что-либо. BTW, результат может быть кэширован. Наконец, целью является вызов внешнего процесса. Любой вызов 'svn', вероятно, будет намного медленнее, чем' where' или 'which' call. –

+0

Да, ответ выше «Дмитрий Гинзбург» действительно хорош. 'где' имеет относительно большие накладные расходы (может быть более 100-200 мс), и если вы его назовете несколько раз, он выходит из рук. Я просто понял это в своем коде, почему он заметно медленнее. – BullyWiiPlaza

0

В моем опыте это невозможно сказать по различным системам через просто вызывая команду с ProcessBuilder, если он выходит или нет (ни Exceptions, ни возвращать значения, кажется последовательным)

Так вот решение Java7 что пересекает переменную окружения PATH и ищет соответствующий инструмент. Будет проверять все файлы, если каталог. matchesExecutable должно быть именем инструмента, игнорирующего расширение и регистр.

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; 
} 

Вот помощник:

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; 
} 
Смежные вопросы