import java.io.File;
import java.io.IOException;
-import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
* typical Windows installation path is
* C:\Program Files\Chimera 1.12\bin\chimera.exe
*/
- for (String root : new String[] { "\\Program Files",
- "C:\\Program Files", "\\Program Files (x86)",
- "C:\\Program Files (x86)" })
- {
- /*
- * match a path ending in \bin\chimera or \bin\chimera.exe
- * back-slashes are double escaped - for Java String, and for regex
- */
- for (String version : FileUtils
- .findMatchingPaths(".*\\\\Chimera.*$", Paths.get(root)))
- {
- pathList.addAll(FileUtils.findMatchingPaths(
- ".*\\\\bin\\\\chimera(\\\\.exe)?$",
- Paths.get(version)));
- }
- }
+ // current drive:
+ pathList.addAll(FileUtils.findMatches("\\",
+ "Program Files*/Chimera*/bin/{chimera,chimera.exe}"));
+ // C: drive (note may add as duplicates)
+ pathList.addAll(FileUtils.findMatches("C:\\",
+ "Program Files*/Chimera*/bin/{chimera,chimera.exe}"));
}
else if (os.startsWith("Mac"))
{
import java.io.File;
import java.io.IOException;
+import java.nio.file.DirectoryStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
+import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
* Answers a (possibly empty) list of file paths found by searching below
* <code>from</code> that match the supplied regular expression
* <code>pattern</code>. Results may include <code>from</code> itself if it
- * matches. If an exception occurs it is written to syserr and any results up
- * to that point are returned. Note that the regular expression match applies
- * to the whole path of any matched file.
+ * matches. If an exception occurs it is written to syserr and any results up to
+ * that point are returned. Note that the regular expression match applies to
+ * the whole path of any matched file.
* <p>
- * Because the whole directory tree below <code>from</code> is searched, this
- * method may be slow if used for a high level directory.
+ * WARNING: because the whole directory tree below <code>from</code> is
+ * searched, this method may be slow if used for a high level directory, or may
+ * exit prematurely if security or other exceptions occur.
*
* <pre>
* Example:
- * findMatchingPaths(".*/chimera.exe$", Paths.get("C:/Program Files"))
+ * findMatchingPaths(Paths.get("C:/Program Files"), ".*/chimera.exe$")
* </pre>
*
- * @param pattern
* @param from
+ * @param pattern
+ *
* @return
* @see https://stackoverflow.com/questions/794381/how-to-find-files-that-match-a-wildcard-string-in-java/31685610#comment62441832_31685610
*/
- public static List<String> findMatchingPaths(String pattern, Path from)
+ public static List<String> findMatchingPaths(Path from, String pattern)
{
List<String> matches = new ArrayList<>();
PathMatcher pathMatcher = FileSystems.getDefault()
return matches;
}
+
+ /**
+ * Answers a (possibly empty) list of paths to files below the given root path,
+ * that match the given pattern. The pattern should be a '/' delimited set of
+ * glob patterns, each of which is used to match child file names (not full
+ * paths). Note that 'directory spanning' glob patterns (**) are <em>not</em>
+ * supported by this method.
+ * <p>
+ * For example
+ *
+ * <pre>
+ * findMatches("C:\\", "Program Files*/Chimera*/bin/{chimera,chimera.exe}"
+ * </pre>
+ *
+ * would match "C:\Program Files\Chimera 1.11\bin\chimera.exe" and "C:\Program
+ * Files (x86)\Chimera 1.10.1\bin\chimera"
+ *
+ * @param root
+ * @param pattern
+ * @return
+ * @see https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob
+ */
+ public static List<String> findMatches(String root, String pattern)
+ {
+ List<String> results = new ArrayList<>();
+ try
+ {
+ Path from = Paths.get(root);
+ findMatches(results, from, Arrays.asList(pattern.split("/")));
+ } catch (Throwable e)
+ {
+ // Paths.get can throw IllegalArgumentException
+ System.err.println(String.format("Error searching %s for %s: %s",
+ root, pattern, e.toString()));
+ }
+
+ return results;
+ }
+
+ /**
+ * A helper method that performs recursive search of file patterns and adds any
+ * 'leaf node' matches to the results list
+ *
+ * @param results
+ * @param from
+ * @param patterns
+ */
+ protected static void findMatches(List<String> results, Path from,
+ List<String> patterns)
+ {
+ if (patterns.isEmpty())
+ {
+ /*
+ * reached end of recursion with all components matched
+ */
+ results.add(from.toString());
+ return;
+ }
+
+ String pattern = patterns.get(0);
+ try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(from,
+ pattern))
+ {
+ dirStream.forEach(p -> {
+
+ /*
+ * matched a next level file - search below it
+ * (ignore non-directory non-leaf matches)
+ */
+ List<String> subList = patterns.subList(1, patterns.size());
+ if (subList.isEmpty() || p.toFile().isDirectory())
+ {
+ findMatches(results, p, subList);
+ }
+ });
+ } catch (IOException e)
+ {
+ System.err.println(String.format("Error searching %s: %s", pattern,
+ e.toString()));
+ }
+ }
}
package jalview.util;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
@Test(groups = "Functional")
public void testFindMatchingPaths() throws IOException
{
- String expect1 = Paths.get("../jalview/examples/plantfdx.fa")
+ String expect1 = Paths.get("..", "jalview", "examples", "plantfdx.fa")
.toString();
String expect2 = Paths.get("../jalview/examples/plantfdx.features")
.toString();
.get("../jalview/examples/testdata/plantfdx.features")
.toString();
- List<String> matches = FileUtils.findMatchingPaths(".*/plant.*\\.f.*",
- Paths.get(".."));
+ List<String> matches = FileUtils
+ .findMatchingPaths(Paths.get(".."),
+ ".*[/\\\\]plant.*\\.f.*");
+ System.out.println(matches);
assertTrue(matches.contains(expect1));
assertTrue(matches.contains(expect2));
assertTrue(matches.contains(expect3));
}
+
+ @Test(groups = "External")
+ public void testWindowsPath() throws IOException
+ {
+ if (System.getProperty("os.name").startsWith("Windows"))
+ {
+ /*
+ * should pass provided Eclipse is installed
+ */
+ List<String> matches = FileUtils.findMatches("C:\\",
+ "Program Files*/eclips*/eclips?.exe");
+ assertFalse(matches.isEmpty());
+
+ /*
+ * should pass provided Chimera is installed
+ */
+ matches = FileUtils.findMatches("C:\\",
+ "Program Files*/Chimera*/bin/{chimera,chimera.exe}");
+ assertFalse(matches.isEmpty());
+ }
+ }
+
+ @Test(groups = "Functional")
+ public void testFindMatches() throws IOException
+ {
+ String expect1 = Paths.get("..", "jalview", "examples", "plantfdx.fa")
+ .toString();
+ String expect2 = Paths.get("../jalview/examples/plantfdx.features")
+ .toString();
+ String expect3 = Paths
+ .get("../jalview/examples/testdata/plantfdx.features")
+ .toString();
+
+ List<String> matches = FileUtils
+ .findMatches("..", "jalview/ex*/plant*.f*");
+ System.out.println(matches);
+ assertTrue(matches.contains(expect1));
+ assertTrue(matches.contains(expect2));
+ assertFalse(matches.contains(expect3));
+ }
}