From 1ed4ac38ab7e097a051afaa25853434f1cfb6d4c Mon Sep 17 00:00:00 2001 From: Mungo Carstairs Date: Mon, 9 Apr 2018 17:09:32 +0100 Subject: [PATCH] JAL-2937 Cygwin path preference, method refactoring --- resources/lang/Messages.properties | 17 +++--- src/jalview/gui/Preferences.java | 63 +++++++++++++++---- src/jalview/hmmer/HMMAlign.java | 7 ++- src/jalview/hmmer/HMMSearch.java | 11 ++-- src/jalview/hmmer/HmmerCommand.java | 100 +++++++++++++++--------------- src/jalview/jbgui/GPreferences.java | 114 +++++++++++++++++++++++++---------- src/jalview/util/Platform.java | 2 +- 7 files changed, 203 insertions(+), 111 deletions(-) diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 06c8b6b..bcd0bbd 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -1379,7 +1379,8 @@ label.hmmbuild_group = Build HMM from Selected Group label.group_hmmbuild = Build HMM from Group label.hmmsearch = hmmsearch label.hmmer_location = HMMER Binaries Installation Location -warn.null_hmm = Please ensure the alignment contains a hidden Markov model. +label.cygwin_location = Cygwin Binaries Installation Location (Windows) +warn.null_hmm = Please ensure the alignment contains a hidden Markov model label.ignore_below_background_frequency = Ignore Below Background Frequency label.information_description = Information content, measured in bits warn.no_selected_hmm = Please select a hidden Markov model sequence. @@ -1390,14 +1391,12 @@ label.no_sequences_found = No matching sequences, or an error occurred. label.hmmer = HMMER label.trim_termini = Trim Non-Matching Termini label.trim_termini_desc = If true, non-matching regions on either end of the resulting alignment are removed. -label.no_of_sequences = Sequences Returned -label.freq_alignment = Use Alignment Background Frequencies -label.freq_uniprot = Use Uniprot Background Frequencies -label.hmmalign_label = hmmalign Options -label.hmmsearch_label = hmmsearch Options -label.hmmbuild_not_found = The hmmbuild binary was not found -label.hmmalign_not_found = The hmmalign binary was not found -label.hmmsearch_not_found = The hmmsearch binary was not found +label.no_of_sequences = Number of sequences returned +label.freq_alignment = Use alignment background frequencies +label.freq_uniprot = Use Uniprot background frequencies +label.hmmalign_label = hmmalign options +label.hmmsearch_label = hmmsearch options +label.executable_not_found = The ''{0}'' executable file was not found warn.hmm_command_failed = hmm command not found label.invalid_folder = Invalid Folder label.folder_not_exists = HMMER binaries not found. \n Please enter the path to the HMMER binaries (if installed). diff --git a/src/jalview/gui/Preferences.java b/src/jalview/gui/Preferences.java index df35b5e..9f9d6f8 100755 --- a/src/jalview/gui/Preferences.java +++ b/src/jalview/gui/Preferences.java @@ -37,6 +37,7 @@ import jalview.urls.UrlLinkTableModel; import jalview.urls.api.UrlProviderFactoryI; import jalview.urls.api.UrlProviderI; import jalview.urls.desktop.DesktopUrlProviderFactory; +import jalview.util.FileUtils; import jalview.util.MessageManager; import jalview.util.Platform; import jalview.util.UrlConstants; @@ -61,6 +62,7 @@ import javax.swing.JColorChooser; import javax.swing.JFileChooser; import javax.swing.JInternalFrame; import javax.swing.JPanel; +import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.RowFilter; import javax.swing.RowSorter; @@ -108,6 +110,8 @@ public class Preferences extends GPreferences public static final String HMMER_PATH = "HMMER_PATH"; + public static final String CYGWIN_PATH = "CYGWIN_PATH"; + public static final String HMMSEARCH_DB_PATHS = "HMMSEARCH_DB_PATHS"; public static final String HMMSEARCH_DBS = "HMMSEARCH_DBS"; @@ -235,7 +239,7 @@ public class Preferences extends GPreferences @Override public void actionPerformed(ActionEvent e) { - validateHMMERPath(true); + validateHmmerPath(); } }); hmmerPath.addFocusListener(new FocusAdapter() @@ -243,7 +247,24 @@ public class Preferences extends GPreferences @Override public void focusLost(FocusEvent e) { - validateHMMERPath(true); + validateHmmerPath(); + } + }); + cygwinPath.setText(Cache.getProperty(CYGWIN_PATH)); + cygwinPath.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + validateCygwinPath(); + } + }); + cygwinPath.addFocusListener(new FocusAdapter() + { + @Override + public void focusLost(FocusEvent e) + { + validateCygwinPath(); } }); @@ -712,8 +733,8 @@ public class Preferences extends GPreferences Boolean.toString(hmmerBackgroundUniprot.isSelected())); Cache.applicationProperties.setProperty("SEQUENCES_TO_KEEP", hmmerSequenceCount.getText()); - Cache.applicationProperties.setProperty(HMMER_PATH, - hmmerPath.getText()); + Cache.setOrRemove(HMMER_PATH, hmmerPath.getText()); + Cache.setOrRemove(CYGWIN_PATH, cygwinPath.getText()); AlignFrame[] frames = Desktop.getAlignFrames(); if (frames != null && frames.length > 0) { @@ -1264,23 +1285,27 @@ public class Preferences extends GPreferences } /** - * Returns true if hmmer path is to a folder that contains an executable - * hmmbuild or hmmbuild.exe, else false (optionally after showing a warning - * dialog) + * Returns true if the given text field contains a path to a folder that + * contains an executable with the given name, else false (after showing a + * warning dialog). The executable name will be tried with .exe appended if not + * found. + * + * @param textField + * @param executable */ - @Override - protected boolean validateHMMERPath(boolean showWarning) + protected boolean validateExecutablePath(JTextField textField, String executable) { - String folder = hmmerPath.getText().trim(); + String folder = textField.getText().trim(); - if (HmmerCommand.getExecutable(HmmerCommand.HMMBUILD, folder) != null) + if (FileUtils.getExecutable(executable, folder) != null) { return true; } - if (showWarning && folder.length() > 0) + if (folder.length() > 0) { JvOptionPane.showInternalMessageDialog(Desktop.desktop, - MessageManager.getString("label.hmmbuild_not_found"), + MessageManager.formatMessage("label.executable_not_found", + executable), MessageManager.getString("label.invalid_folder"), JvOptionPane.ERROR_MESSAGE); } @@ -1357,6 +1382,18 @@ public class Preferences extends GPreferences } } + @Override + protected void validateHmmerPath() + { + validateExecutablePath(hmmerPath, HmmerCommand.HMMBUILD); + } + + @Override + protected void validateCygwinPath() + { + validateExecutablePath(cygwinPath, "run"); + } + public class OptionsParam { private String name; diff --git a/src/jalview/hmmer/HMMAlign.java b/src/jalview/hmmer/HMMAlign.java index 44828aa..befdc55 100644 --- a/src/jalview/hmmer/HMMAlign.java +++ b/src/jalview/hmmer/HMMAlign.java @@ -14,6 +14,7 @@ import jalview.gui.JvOptionPane; import jalview.gui.SplitFrame; import jalview.io.DataSourceType; import jalview.io.StockholmFile; +import jalview.util.FileUtils; import jalview.util.MessageManager; import jalview.viewmodel.seqfeatures.FeatureRendererSettings; import jalview.ws.params.ArgumentI; @@ -86,9 +87,9 @@ public class HMMAlign extends HmmerCommand Hashtable sequencesHash = stashSequences(seqs); try { - File modelFile = createTempFile("hmm", ".hmm"); - File alignmentFile = createTempFile("output", ".sto"); - File resultFile = createTempFile("input", ".sto"); + File modelFile = FileUtils.createTempFile("hmm", ".hmm"); + File alignmentFile = FileUtils.createTempFile("output", ".sto"); + File resultFile = FileUtils.createTempFile("input", ".sto"); exportStockholm(seqs, alignmentFile.getAbsoluteFile(), null); exportHmm(hmm, modelFile.getAbsoluteFile()); diff --git a/src/jalview/hmmer/HMMSearch.java b/src/jalview/hmmer/HMMSearch.java index 30299e9..6f73f2f 100644 --- a/src/jalview/hmmer/HMMSearch.java +++ b/src/jalview/hmmer/HMMSearch.java @@ -11,6 +11,7 @@ import jalview.gui.JvOptionPane; import jalview.io.DataSourceType; import jalview.io.FileParse; import jalview.io.StockholmFile; +import jalview.util.FileUtils; import jalview.util.MessageManager; import jalview.ws.params.ArgumentI; import jalview.ws.params.simple.BooleanOption; @@ -71,9 +72,11 @@ public class HMMSearch extends HmmerCommand try { - File hmmFile = createTempFile("hmm", ".hmm"); - File hitsAlignmentFile = createTempFile("hitAlignment", ".sto"); - File searchOutputFile = createTempFile("searchOutput", ".sto"); + File hmmFile = FileUtils.createTempFile("hmm", ".hmm"); + File hitsAlignmentFile = FileUtils.createTempFile("hitAlignment", + ".sto"); + File searchOutputFile = FileUtils.createTempFile("searchOutput", + ".sto"); exportHmm(hmm, hmmFile.getAbsoluteFile()); @@ -196,7 +199,7 @@ public class HMMSearch extends HmmerCommand * no external database specified for search, so * export current alignment as 'database' to search */ - databaseFile = createTempFile("database", ".sto"); + databaseFile = FileUtils.createTempFile("database", ".sto"); AlignmentI al = af.getViewport().getAlignment(); AlignmentI copy = new Alignment(al); SequenceI hmms = copy.getHmmConsensus(); diff --git a/src/jalview/hmmer/HmmerCommand.java b/src/jalview/hmmer/HmmerCommand.java index fe6c0f9..9bec181 100644 --- a/src/jalview/hmmer/HmmerCommand.java +++ b/src/jalview/hmmer/HmmerCommand.java @@ -14,7 +14,9 @@ import jalview.gui.JvOptionPane; import jalview.gui.Preferences; import jalview.io.HMMFile; import jalview.io.StockholmFile; +import jalview.util.FileUtils; import jalview.util.MessageManager; +import jalview.util.Platform; import jalview.ws.params.ArgumentI; import java.io.BufferedReader; @@ -22,6 +24,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Hashtable; import java.util.List; @@ -63,7 +66,8 @@ public abstract class HmmerCommand implements Runnable */ public static boolean isHmmerAvailable() { - File exec = getExecutable(HMMBUILD, Cache.getProperty(Preferences.HMMER_PATH)); + File exec = FileUtils.getExecutable(HMMBUILD, + Cache.getProperty(Preferences.HMMER_PATH)); return exec != null; } @@ -100,9 +104,12 @@ public abstract class HmmerCommand implements Runnable public boolean runCommand(List command) throws IOException { + List commands = Platform.isWindows() ? wrapWithCygwin(command) + : command; + try { - ProcessBuilder pb = new ProcessBuilder(command); + ProcessBuilder pb = new ProcessBuilder(commands); pb.redirectErrorStream(true); // merge syserr to sysout final Process p = pb.start(); new Thread(new Runnable() @@ -128,7 +135,13 @@ public abstract class HmmerCommand implements Runnable }).start(); p.waitFor(); - return p.exitValue() == 0; // 0 is success, by convention + int exitValue = p.exitValue(); + if (exitValue != 0) + { + Cache.log.error("Command failed, return code = " + exitValue); + Cache.log.error("Command/args were: " + commands.toString()); + } + return exitValue == 0; // 0 is success, by convention } catch (Exception e) { e.printStackTrace(); @@ -137,6 +150,40 @@ public abstract class HmmerCommand implements Runnable } /** + * Converts the given command to a Cygwin "run" command wrapper + * + * @param command + * @return + */ + protected List wrapWithCygwin(List command) + { + File runCygwin = FileUtils.getExecutable("run", + Cache.getProperty(Preferences.CYGWIN_PATH)); + if (runCygwin == null) + { + Cache.log.error("Cygwin shell not found"); + return command; + } + + List wrapped = new ArrayList<>(); + wrapped.add(runCygwin.getAbsolutePath()); + if (!command.isEmpty()) + { + wrapped.add(command.get(0)); + // wrapped.add("--quote"); + StringBuilder args = new StringBuilder(); + for (String arg : command.subList(1, command.size())) + { + args.append(" ").append(arg); + } + wrapped.add(args.toString()); + } + // TODO this doesn't yet pass parameters successfully + + return wrapped; + } + + /** * Exports an alignment, and reference (RF) annotation if present, to the * specified file, in Stockholm format * @@ -204,7 +251,7 @@ public abstract class HmmerCommand implements Runnable protected String getCommandPath(String cmd) { String binariesFolder = Cache.getProperty(Preferences.HMMER_PATH); - File file = getExecutable(cmd, binariesFolder); + File file = FileUtils.getExecutable(cmd, binariesFolder); if (file == null && af != null) { JvOptionPane.showInternalMessageDialog(af, @@ -215,51 +262,6 @@ public abstract class HmmerCommand implements Runnable } /** - * Answers the executable file for the given hmmer command, or null if not - * found or not executable. The path to the executable is the command name - * prefixed by the hmmer binaries folder path, optionally with .exe appended. - * - * @param cmd - * hmmer command short name, for example hmmbuild - * @param binaryPath - * parent folder containing hmmer executables - * @return - */ - public static File getExecutable(String cmd, String binaryPath) - { - File file = new File(binaryPath, cmd); - if (!file.canExecute()) - { - file = new File(binaryPath, cmd + ".exe"); - { - if (!file.canExecute()) - { - file = null; - } - } - } - return file; - } - - /** - * A convenience method to create a temporary file that is deleted on exit of - * the JVM - * - * @param prefix - * @param suffix - * @return - * @throws IOException - */ - protected File createTempFile(String prefix, String suffix) - throws IOException - { - File f = File.createTempFile(prefix, suffix); - f.deleteOnExit(); - return f; - - } - - /** * Exports an HMM to the specified file * * @param hmm diff --git a/src/jalview/jbgui/GPreferences.java b/src/jalview/jbgui/GPreferences.java index 358298d..6ff335e 100755 --- a/src/jalview/jbgui/GPreferences.java +++ b/src/jalview/jbgui/GPreferences.java @@ -26,6 +26,7 @@ import jalview.fts.service.pdb.PDBFTSRestClient; import jalview.gui.JvSwingUtils; import jalview.gui.StructureViewer.ViewerType; import jalview.util.MessageManager; +import jalview.util.Platform; import java.awt.BorderLayout; import java.awt.Color; @@ -284,6 +285,8 @@ public class GPreferences extends JPanel protected JTextField hmmerPath = new JTextField(); + protected JTextField cygwinPath = new JTextField(); + /* * DAS Settings tab */ @@ -424,12 +427,19 @@ public class GPreferences extends JPanel private JPanel initHMMERTab() { hmmerTab.setLayout(null); + final int lineSpacing = 20; - JLabel installationLocation = new JLabel( + /* + * path to hmmer binaries folder + */ + JLabel hmmerLocation = new JLabel( MessageManager.getString("label.hmmer_location")); - installationLocation.setFont(LABEL_FONT); - installationLocation.setBounds(new Rectangle(22, 10, 250, 23)); - hmmerPath.setBounds(new Rectangle(22, 30, 300, 23)); + hmmerLocation.setFont(LABEL_FONT); + int xPos = 22; + int yPos = 10; + hmmerLocation.setBounds(new Rectangle(xPos, yPos, 250, 23)); + yPos += lineSpacing; + hmmerPath.setBounds(new Rectangle(xPos, yPos, 300, 23)); hmmerPath.addMouseListener(new MouseAdapter() { @Override @@ -441,54 +451,96 @@ public class GPreferences extends JPanel if (chosen != null) { hmmerPath.setText(chosen); + validateHmmerPath(); } } } }); + hmmerTab.add(hmmerLocation); + hmmerTab.add(hmmerPath); - JLabel hmmalign = new JLabel( - MessageManager.getString("label.hmmalign_label")); - hmmalign.setFont(LABEL_FONT); - hmmalign.setBounds(new Rectangle(22, 50, 200, 23)); + /* + * path to Cygwin binaries folder (for Windows) + */ + if (Platform.isWindows()) + { + JLabel cygwinLocation = new JLabel( + MessageManager.getString("label.cygwin_location")); + cygwinLocation.setFont(LABEL_FONT); + yPos += lineSpacing * 2; + cygwinLocation.setBounds(new Rectangle(xPos, yPos, 250, 23)); + yPos += lineSpacing; + cygwinPath.setBounds(new Rectangle(xPos, yPos, 300, 23)); + cygwinPath.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent e) + { + if (e.getClickCount() == 2) + { + String chosen = openFileChooser(true); + if (chosen != null) + { + cygwinPath.setText(chosen); + validateCygwinPath(); + } + } + } + }); + hmmerTab.add(cygwinLocation); + hmmerTab.add(cygwinPath); + } + /* + * preferences for hmmalign + */ + yPos += lineSpacing * 2; + JPanel alignOptions = new JPanel(new FlowLayout(FlowLayout.LEFT)); + JvSwingUtils.createTitledBorder(alignOptions, + MessageManager.getString("label.hmmalign_label"), true); + yPos += lineSpacing; hmmrTrimTermini.setFont(LABEL_FONT); hmmrTrimTermini.setText(MessageManager.getString("label.trim_termini")); - hmmrTrimTermini.setBounds(new Rectangle(22, 70, 200, 23)); - - JLabel hmmsearch = new JLabel( - MessageManager.getString("label.hmmsearch_label")); - hmmsearch.setFont(LABEL_FONT); - hmmsearch.setBounds(new Rectangle(22, 90, 200, 23)); + alignOptions.add(hmmrTrimTermini); + hmmerTab.add(alignOptions); + alignOptions.setBounds(new Rectangle(xPos, yPos, 300, 43)); + /* + * preferences for hmmsearch + */ + yPos += lineSpacing * 3; + JPanel searchOptions = new JPanel(new FlowLayout(FlowLayout.LEFT)); + JvSwingUtils.createTitledBorder(searchOptions, + MessageManager.getString("label.hmmsearch_label"), true); + searchOptions.setBounds(new Rectangle(xPos, yPos, 300, 43)); JLabel sequencesToKeep = new JLabel( MessageManager.getString("label.no_of_sequences")); sequencesToKeep.setFont(LABEL_FONT); - sequencesToKeep.setBounds(new Rectangle(22, 110, 125, 23)); - hmmerSequenceCount.setBounds(new Rectangle(150, 110, 40, 23)); + // hmmerSequenceCount.setBounds(new Rectangle(xPos + 250, yPos, 60, 23)); + searchOptions.add(sequencesToKeep); + searchOptions.add(hmmerSequenceCount); + hmmerTab.add(searchOptions); ButtonGroup backgroundFreqSource = new ButtonGroup(); backgroundFreqSource.add(hmmerBackgroundUniprot); backgroundFreqSource.add(hmmerBackgroundAlignment); backgroundFreqSource.setSelected(hmmerBackgroundUniprot.getModel(), true); + /* + * preferences for Information Content annotation + */ + yPos += lineSpacing * 3; hmmerBackgroundUniprot.setText(MessageManager.getString("label.freq_uniprot")); hmmerBackgroundUniprot.setFont(LABEL_FONT); - hmmerBackgroundUniprot.setBounds(new Rectangle(22, 130, 255, 23)); + hmmerBackgroundUniprot.setBounds(new Rectangle(xPos, yPos, 255, 23)); + yPos += lineSpacing; hmmerBackgroundAlignment.setText(MessageManager.getString("label.freq_alignment")); hmmerBackgroundAlignment.setFont(LABEL_FONT); - hmmerBackgroundAlignment.setBounds(new Rectangle(22, 150, 300, 23)); + hmmerBackgroundAlignment.setBounds(new Rectangle(xPos, yPos, 300, 23)); hmmerTab.add(hmmerBackgroundUniprot); hmmerTab.add(hmmerBackgroundAlignment); - hmmerTab.add(hmmalign); - hmmerTab.add(hmmsearch); - hmmerTab.add(installationLocation); - hmmerTab.add(hmmerPath); - hmmerTab.add(hmmrTrimTermini); - hmmerTab.add(sequencesToKeep); - hmmerTab.add(sequencesToKeep); - hmmerTab.add(hmmerSequenceCount); return hmmerTab; } @@ -1406,11 +1458,6 @@ public class GPreferences extends JPanel return false; } - protected boolean validateHMMERPath(boolean showWarning) - { - return false; - } - /** * Initialises the Visual tabbed panel. * @@ -1915,8 +1962,11 @@ public class GPreferences extends JPanel } - public void hmmerPath_actionPerformed(ActionEvent e) + protected void validateHmmerPath() { + } + protected void validateCygwinPath() + { } } diff --git a/src/jalview/util/Platform.java b/src/jalview/util/Platform.java index 2c74609..7c0e15d 100644 --- a/src/jalview/util/Platform.java +++ b/src/jalview/util/Platform.java @@ -51,7 +51,7 @@ public class Platform } /** - * Check if we are on a Microsoft plaform... + * Check if we are on a Microsoft platform... * * @return true if we have to cope with another platform variation */ -- 1.7.10.2