3 import jalview.analysis.SeqsetUtils;
4 import jalview.bin.Cache;
5 import jalview.datamodel.Alignment;
6 import jalview.datamodel.AlignmentAnnotation;
7 import jalview.datamodel.AlignmentI;
8 import jalview.datamodel.AnnotatedCollectionI;
9 import jalview.datamodel.Annotation;
10 import jalview.datamodel.HiddenMarkovModel;
11 import jalview.datamodel.SequenceI;
12 import jalview.gui.AlignFrame;
13 import jalview.gui.JvOptionPane;
14 import jalview.gui.Preferences;
15 import jalview.io.HMMFile;
16 import jalview.io.StockholmFile;
17 import jalview.util.FileUtils;
18 import jalview.util.MessageManager;
19 import jalview.util.Platform;
20 import jalview.ws.params.ArgumentI;
22 import java.io.BufferedReader;
24 import java.io.IOException;
25 import java.io.InputStreamReader;
26 import java.io.PrintWriter;
27 import java.nio.file.Paths;
28 import java.util.ArrayList;
29 import java.util.Hashtable;
30 import java.util.List;
33 * Base class for hmmbuild, hmmalign and hmmsearch
38 public abstract class HmmerCommand implements Runnable
40 public static final String HMMBUILD = "hmmbuild";
42 protected final AlignFrame af;
44 protected final AlignmentI alignment;
46 protected final List<ArgumentI> params;
54 public HmmerCommand(AlignFrame alignFrame, List<ArgumentI> args)
57 alignment = af.getViewport().getAlignment();
62 * Answers true if preference HMMER_PATH is set, and its value is the path to
63 * a directory that contains an executable <code>hmmbuild</code> or
64 * <code>hmmbuild.exe</code>, else false
68 public static boolean isHmmerAvailable()
70 File exec = FileUtils.getExecutable(HMMBUILD,
71 Cache.getProperty(Preferences.HMMER_PATH));
76 * Uniquifies the sequences when exporting and stores their details in a
81 protected Hashtable stashSequences(SequenceI[] seqs)
83 return SeqsetUtils.uniquify(seqs, true);
87 * Restores the sequence data lost by uniquifying
92 protected void recoverSequences(Hashtable hashtable, SequenceI[] seqs)
94 SeqsetUtils.deuniquify(hashtable, seqs);
98 * Runs a command as a separate process and waits for it to complete. Answers
99 * true if the process return status is zero, else false.
102 * the executable command and any arguments to it
103 * @throws IOException
105 public boolean runCommand(List<String> commands)
108 List<String> args = Platform.isWindows() ? wrapWithCygwin(commands)
113 ProcessBuilder pb = new ProcessBuilder(args);
114 pb.redirectErrorStream(true); // merge syserr to sysout
115 if (Platform.isWindows())
117 String path = pb.environment().get("Path");
118 path = jalview.bin.Cache.getProperty("CYGWIN_PATH") + ";" + path;
119 pb.environment().put("Path", path);
121 final Process p = pb.start();
122 new Thread(new Runnable()
127 BufferedReader input = new BufferedReader(
128 new InputStreamReader(p.getInputStream()));
131 String line = input.readLine();
134 System.out.println(line);
135 line = input.readLine();
137 } catch (IOException e)
145 int exitValue = p.exitValue();
148 Cache.log.error("Command failed, return code = " + exitValue);
149 Cache.log.error("Command/args were: " + args.toString());
151 return exitValue == 0; // 0 is success, by convention
152 } catch (Exception e)
160 * Converts the given command to a Cygwin "bash" command wrapper. The hmmer
161 * command and any arguments to it are converted into a single parameter to the
166 protected List<String> wrapWithCygwin(List<String> commands)
168 File bash = FileUtils.getExecutable("bash",
169 Cache.getProperty(Preferences.CYGWIN_PATH));
172 Cache.log.error("Cygwin shell not found");
176 List<String> wrapped = new ArrayList<>();
177 // wrapped.add("C:\Users\tva\run");
178 wrapped.add(bash.getAbsolutePath());
182 * combine hmmbuild/search/align and arguments to a single string
184 StringBuilder sb = new StringBuilder();
185 for (String cmd : commands)
187 sb.append(" ").append(cmd);
189 wrapped.add(sb.toString());
195 * Exports an alignment, and reference (RF) annotation if present, to the
196 * specified file, in Stockholm format
201 * @throws IOException
203 public void exportStockholm(SequenceI[] seqs, File toFile,
204 AnnotatedCollectionI annotated) throws IOException
210 AlignmentI newAl = new Alignment(seqs);
211 if (!newAl.isAligned())
216 if (toFile != null && annotated != null)
218 AlignmentAnnotation[] annots = annotated.getAlignmentAnnotation();
221 for (AlignmentAnnotation annot : annots)
223 if (annot.label.contains("Reference") || "RF".equals(annot.label))
225 AlignmentAnnotation newRF;
226 if (annot.annotations.length > newAl.getWidth())
228 Annotation[] rfAnnots = new Annotation[newAl.getWidth()];
229 System.arraycopy(annot.annotations, 0, rfAnnots, 0,
231 newRF = new AlignmentAnnotation("RF", "Reference Positions",
236 newRF = new AlignmentAnnotation(annot);
238 newAl.addAnnotation(newRF);
244 StockholmFile file = new StockholmFile(newAl);
245 String output = file.print(seqs, false);
246 PrintWriter writer = new PrintWriter(toFile);
247 writer.println(output);
252 * Answers the full path to the given hmmer executable, or null if file cannot
253 * be found or is not executable
256 * command short name e.g. hmmalign
258 * @throws IOException
260 protected String getCommandPath(String cmd)
263 String binariesFolder = Cache.getProperty(Preferences.HMMER_PATH);
264 // ensure any symlink to the directory is resolved:
265 binariesFolder = Paths.get(binariesFolder).toRealPath().toString();
266 File file = FileUtils.getExecutable(cmd, binariesFolder);
267 if (file == null && af != null)
269 JvOptionPane.showInternalMessageDialog(af, MessageManager
270 .formatMessage("label.executable_not_found", cmd));
273 return file == null ? null : getFilePath(file, true);
277 * Exports an HMM to the specified file
281 * @throws IOException
283 public void exportHmm(HiddenMarkovModel hmm, File hmmFile)
288 HMMFile file = new HMMFile(hmm);
289 PrintWriter writer = new PrintWriter(hmmFile);
290 writer.print(file.print());
296 * Answers the HMM profile for the profile sequence the user selected (default
297 * is just the first HMM sequence in the alignment)
301 protected HiddenMarkovModel getHmmProfile()
303 String alignToParamName = MessageManager.getString("label.use_hmm");
304 for (ArgumentI arg : params)
306 String name = arg.getName();
307 if (name.equals(alignToParamName))
309 String seqName = arg.getValue();
310 SequenceI hmmSeq = alignment.findName(seqName);
311 if (hmmSeq.hasHMMProfile())
313 return hmmSeq.getHMM();
321 * Answers an absolute path to the given file, in a format suitable for
322 * processing by a hmmer command. On a Windows platform, the native Windows file
323 * path is converted to Cygwin format, by replacing '\'with '/' and drive letter
324 * X with /cygdrive/x.
328 * True if file is to be read/written from within the Cygwin
329 * shell. Should be false for any imports.
332 protected String getFilePath(File resultFile, boolean isInCygwin)
334 String path = resultFile.getAbsolutePath();
335 if (Platform.isWindows() && isInCygwin)
337 // the first backslash escapes '\' for the regular expression argument
338 path = path.replaceAll("\\" + File.separator, "/");
339 int colon = path.indexOf(':');
342 String drive = path.substring(0, colon);
343 path = path.replaceAll(drive + ":", "/cygdrive/" + drive);