426920 - jetty-start / BaseHome.listFilesRegex() and .recurseDir() do not detect filesystem loops
+ Using java.nio.files to walk directory tree and detect filesystem loops + All standard PathMatching patterns now work. ("glob:" and "regex:")
This commit is contained in:
parent
1444ffadb8
commit
dfbe5c92c6
|
@ -1,9 +1,9 @@
|
|||
#
|
||||
# Module to add all lib/ext/*.jar files to classpath
|
||||
# Module to add all lib/ext/**.jar files to classpath
|
||||
#
|
||||
|
||||
[lib]
|
||||
regex:lib/ext/.*\.jar$
|
||||
lib/ext/**.jar
|
||||
|
||||
[files]
|
||||
lib/
|
||||
|
|
|
@ -19,21 +19,21 @@
|
|||
package org.eclipse.jetty.start;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jetty.start.FS.RelativeRegexFilter;
|
||||
|
||||
/**
|
||||
* File access for <code>${jetty.home}</code>, <code>${jetty.base}</code>, directories.
|
||||
* <p>
|
||||
|
@ -45,6 +45,9 @@ import org.eclipse.jetty.start.FS.RelativeRegexFilter;
|
|||
*/
|
||||
public class BaseHome
|
||||
{
|
||||
private final static EnumSet<FileVisitOption> SEARCH_VISIT_OPTIONS = EnumSet.of(FileVisitOption.FOLLOW_LINKS);;
|
||||
private final static int MAX_SEARCH_DEPTH = 30;
|
||||
|
||||
private File homeDir;
|
||||
private File baseDir;
|
||||
|
||||
|
@ -119,7 +122,7 @@ public class BaseHome
|
|||
* <ol>
|
||||
* <li>If exists relative to <code>${jetty.base}</code>, return that reference</li>
|
||||
* <li>If exists relative to <code>${jetty.home}</code>, return that reference</li>
|
||||
* <li>Otherwise return absolute path reference</li>
|
||||
* <li>Otherwise return absolute path reference (standard java logic)</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param path
|
||||
|
@ -151,6 +154,140 @@ public class BaseHome
|
|||
return new File(rpath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a List of {@link Path}s from a provided pattern.
|
||||
* <p>
|
||||
* Resolution Steps:
|
||||
* <ol>
|
||||
* <li>If the pattern starts with "regex:" or "glob:" then a standard {@link PathMatcher} is built using
|
||||
* {@link java.nio.file.FileSystem#getPathMatcher(String)} as a file search.</li>
|
||||
* <li>If pattern starts with a known filesystem root (using information from {@link java.nio.file.FileSystem#getRootDirectories()}) then this is assumed to
|
||||
* be a absolute file system pattern.</li>
|
||||
* <li>All other patterns are treated as relative to BaseHome information:
|
||||
* <ol>
|
||||
* <li>Search ${jetty.home} first</li>
|
||||
* <li>Search ${jetty.base} for overrides</li>
|
||||
* </ol>
|
||||
* </li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* Pattern examples:
|
||||
* <dl>
|
||||
* <dt><code>lib/logging/*.jar</code></dt>
|
||||
* <dd>Relative pattern, not recursive, search <code>${jetty.home}</code> then <code>${jetty.base}</code> for lib/logging/*.jar content</dd>
|
||||
*
|
||||
* <dt><code>lib/**/*-dev.jar</code></dt>
|
||||
* <dd>Relative pattern, recursive search <code>${jetty.home}</code> then <code>${jetty.base}</code> for files under <code>lib</code> ending in
|
||||
* <code>-dev.jar</code></dd>
|
||||
* </dl>
|
||||
*
|
||||
* <dt><code>etc/jetty.xml</code></dt>
|
||||
* <dd>Relative pattern, no glob, search for <code>${jetty.home}/etc/jetty.xml</code> then <code>${jetty.base}/etc/jetty.xml</code></dd>
|
||||
*
|
||||
* <dt><code>glob:/opt/app/common/*-corp.jar</code></dt>
|
||||
* <dd>PathMapper pattern, glob, search <code>/opt/app/common/</code> for <code>*-corp.jar</code></code></dd>
|
||||
*
|
||||
* </dl>
|
||||
*
|
||||
* <p>
|
||||
* Notes:
|
||||
* <ul>
|
||||
* <li>FileSystem case sensitivity is implementation specific (eg: linux is case-sensitive, windows is case-insensitive).<br/>
|
||||
* See {@link java.nio.file.FileSystem#getPathMatcher(String)} for more details</li>
|
||||
* <li>Pattern slashes are implementation neutral (use '/' always and you'll be fine)</li>
|
||||
* <li>Recursive searching is limited to 30 levels deep (not configurable)</li>
|
||||
* <li>File System loops are detected and skipped</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param pattern
|
||||
* the pattern to search.
|
||||
* @return the collection of paths found
|
||||
* @throws IOException
|
||||
* if error during search operation
|
||||
*/
|
||||
public List<Path> getPaths(String pattern) throws IOException
|
||||
{
|
||||
List<Path> hits = new ArrayList<>();
|
||||
|
||||
if (PathMatchers.isAbsolute(pattern))
|
||||
{
|
||||
Path root = PathMatchers.getSearchRoot(pattern);
|
||||
PathMatcher matcher = PathMatchers.getMatcher(pattern);
|
||||
|
||||
if (FS.isValidDirectory(root))
|
||||
{
|
||||
PathFinder finder = new PathFinder();
|
||||
finder.setFileMatcher(matcher);
|
||||
finder.setBase(root);
|
||||
Files.walkFileTree(root,SEARCH_VISIT_OPTIONS,MAX_SEARCH_DEPTH,finder);
|
||||
hits.addAll(finder.getHits());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Path relativePath = PathMatchers.getSearchRoot(pattern);
|
||||
PathMatcher matcher = PathMatchers.getMatcher(pattern);
|
||||
PathFinder finder = new PathFinder();
|
||||
finder.setFileMatcher(matcher);
|
||||
|
||||
Path homePath = homeDir.toPath().resolve(relativePath);
|
||||
|
||||
if (FS.isValidDirectory(homePath))
|
||||
{
|
||||
finder.setBase(homePath);
|
||||
Files.walkFileTree(homePath,SEARCH_VISIT_OPTIONS,MAX_SEARCH_DEPTH,finder);
|
||||
}
|
||||
|
||||
if (isBaseDifferent())
|
||||
{
|
||||
Path basePath = baseDir.toPath().resolve(relativePath);
|
||||
if (FS.isValidDirectory(basePath))
|
||||
{
|
||||
finder.setBase(basePath);
|
||||
Files.walkFileTree(basePath,SEARCH_VISIT_OPTIONS,MAX_SEARCH_DEPTH,finder);
|
||||
}
|
||||
}
|
||||
hits.addAll(finder.getHits());
|
||||
}
|
||||
|
||||
Collections.sort(hits,new NaturalSort.Paths());
|
||||
return hits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search specified Path with pattern and return hits
|
||||
*
|
||||
* @param dir
|
||||
* the path to a directory to start search from
|
||||
* @param searchDepth
|
||||
* the number of directories deep to perform the search
|
||||
* @param pattern
|
||||
* the raw pattern to use for the search (must be relative)
|
||||
* @return the list of Paths found
|
||||
* @throws IOException
|
||||
* if unable to search the path
|
||||
*/
|
||||
public List<Path> getPaths(Path dir, int searchDepth, String pattern) throws IOException
|
||||
{
|
||||
if (PathMatchers.isAbsolute(pattern))
|
||||
{
|
||||
throw new RuntimeException("Pattern cannot be absolute: " + pattern);
|
||||
}
|
||||
|
||||
List<Path> hits = new ArrayList<>();
|
||||
if (FS.isValidDirectory(dir))
|
||||
{
|
||||
PathMatcher matcher = PathMatchers.getMatcher(pattern);
|
||||
PathFinder finder = new PathFinder();
|
||||
finder.setFileMatcher(matcher);
|
||||
finder.setBase(dir);
|
||||
Files.walkFileTree(dir,SEARCH_VISIT_OPTIONS,searchDepth,finder);
|
||||
hits.addAll(finder.getHits());
|
||||
Collections.sort(hits,new NaturalSort.Paths());
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
public String getHome()
|
||||
{
|
||||
return homeDir.getAbsolutePath();
|
||||
|
@ -213,183 +350,6 @@ public class BaseHome
|
|||
return homeDir.compareTo(baseDir) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the files that are in a specific relative directory.
|
||||
* <p>
|
||||
* If the same found path exists in both <code>${jetty.base}</code> and <code>${jetty.home}</code>, then the one in <code>${jetty.base}</code> is returned
|
||||
* (it overrides the one in ${jetty.home})
|
||||
*
|
||||
* @param relPathToDirectory
|
||||
* the relative path to the directory
|
||||
* @return the list of files found.
|
||||
*/
|
||||
public List<File> listFiles(String relPathToDirectory)
|
||||
{
|
||||
return listFiles(relPathToDirectory,FS.AllFilter.INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the files that are in a specific relative directory, with applied {@link FileFilter}
|
||||
* <p>
|
||||
* If the same found path exists in both <code>${jetty.base}</code> and <code>${jetty.home}</code>, then the one in <code>${jetty.base}</code> is returned
|
||||
* (it overrides the one in ${jetty.home})
|
||||
*
|
||||
* @param relPathToDirectory
|
||||
* the relative path to the directory
|
||||
* @param filter
|
||||
* the filter to use
|
||||
* @return the list of files found.
|
||||
*/
|
||||
public List<File> listFiles(String relPathToDirectory, FileFilter filter)
|
||||
{
|
||||
Objects.requireNonNull(filter,"FileFilter cannot be null");
|
||||
|
||||
File homePath = new File(homeDir,FS.separators(relPathToDirectory));
|
||||
List<File> homeFiles = new ArrayList<>();
|
||||
if (FS.canReadDirectory(homePath))
|
||||
{
|
||||
homeFiles.addAll(Arrays.asList(homePath.listFiles(filter)));
|
||||
}
|
||||
|
||||
if (isBaseDifferent())
|
||||
{
|
||||
// merge
|
||||
File basePath = new File(baseDir,FS.separators(relPathToDirectory));
|
||||
List<File> ret = new ArrayList<>();
|
||||
if (FS.canReadDirectory(basePath))
|
||||
{
|
||||
File baseFiles[] = basePath.listFiles(filter);
|
||||
|
||||
if (baseFiles != null)
|
||||
{
|
||||
for (File base : baseFiles)
|
||||
{
|
||||
String relpath = toRelativePath(baseDir,base);
|
||||
File home = new File(homeDir,FS.separators(relpath));
|
||||
if (home.exists())
|
||||
{
|
||||
homeFiles.remove(home);
|
||||
}
|
||||
ret.add(base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add any remaining home files.
|
||||
ret.addAll(homeFiles);
|
||||
|
||||
Collections.sort(ret,new NaturalSort.Files());
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
// simple return
|
||||
Collections.sort(homeFiles,new NaturalSort.Files());
|
||||
return homeFiles;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the files that are in a specific relative directory, with applied regex.
|
||||
* <p>
|
||||
* If the same found path exists in both <code>${jetty.base}</code> and <code>${jetty.home}</code>, then the one in <code>${jetty.base}</code> is returned
|
||||
* (it overrides the one in ${jetty.home})
|
||||
* <p>
|
||||
* All regex paths are assumed to be in unix notation (use of <code>"/"</code> to separate paths, as <code>"\"</code> is used to escape in regex)
|
||||
*
|
||||
* @param regex
|
||||
* the regex to use to match against the found files.
|
||||
* @return the list of files found.
|
||||
*/
|
||||
public List<File> listFilesRegex(String regex)
|
||||
{
|
||||
Objects.requireNonNull(regex,"Glob cannot be null");
|
||||
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
|
||||
List<File> homeFiles = new ArrayList<>();
|
||||
if (FS.canReadDirectory(homeDir))
|
||||
{
|
||||
StartLog.debug("Finding files in ${jetty.home} that match: %s",regex);
|
||||
recurseDir(homeFiles,homeDir,new FS.RelativeRegexFilter(homeDir,pattern));
|
||||
StartLog.debug("Found %,d files",homeFiles.size());
|
||||
}
|
||||
|
||||
if (isBaseDifferent())
|
||||
{
|
||||
// merge
|
||||
List<File> ret = new ArrayList<>();
|
||||
if (FS.canReadDirectory(baseDir))
|
||||
{
|
||||
List<File> baseFiles = new ArrayList<>();
|
||||
StartLog.debug("Finding files in ${jetty.base} that match: %s",regex);
|
||||
recurseDir(baseFiles,baseDir,new FS.RelativeRegexFilter(baseDir,pattern));
|
||||
StartLog.debug("Found %,d files",baseFiles.size());
|
||||
|
||||
for (File base : baseFiles)
|
||||
{
|
||||
String relpath = toRelativePath(baseDir,base);
|
||||
File home = new File(homeDir,FS.separators(relpath));
|
||||
if (home.exists())
|
||||
{
|
||||
homeFiles.remove(home);
|
||||
}
|
||||
ret.add(base);
|
||||
}
|
||||
}
|
||||
|
||||
// add any remaining home files.
|
||||
ret.addAll(homeFiles);
|
||||
StartLog.debug("Merged Files: %,d files%n",ret.size());
|
||||
|
||||
Collections.sort(ret,new NaturalSort.Files());
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
// simple return
|
||||
Collections.sort(homeFiles,new NaturalSort.Files());
|
||||
return homeFiles;
|
||||
}
|
||||
}
|
||||
|
||||
private void recurseDir(List<File> files, File dir, RelativeRegexFilter filter)
|
||||
{
|
||||
// find matches first
|
||||
files.addAll(Arrays.asList(dir.listFiles(filter)));
|
||||
|
||||
// now dive down into sub-directories
|
||||
for (File subdir : dir.listFiles(FS.DirFilter.INSTANCE))
|
||||
{
|
||||
recurseDir(files,subdir,filter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the list of files in both <code>${jetty.base}</code> and <code>${jetty.home}</code>, even if the same file shows up in both places.
|
||||
*/
|
||||
public List<File> rawListFiles(String relPathToDirectory, FileFilter filter)
|
||||
{
|
||||
Objects.requireNonNull(filter,"FileFilter cannot be null");
|
||||
|
||||
List<File> ret = new ArrayList<>();
|
||||
|
||||
// Home Dir
|
||||
File homePath = new File(homeDir,FS.separators(relPathToDirectory));
|
||||
ret.addAll(Arrays.asList(homePath.listFiles(filter)));
|
||||
|
||||
if (isBaseDifferent())
|
||||
{
|
||||
// Base Dir
|
||||
File basePath = new File(baseDir,FS.separators(relPathToDirectory));
|
||||
ret.addAll(Arrays.asList(basePath.listFiles(filter)));
|
||||
}
|
||||
|
||||
// Sort
|
||||
Collections.sort(ret,new NaturalSort.Files());
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void setBaseDir(File dir)
|
||||
{
|
||||
try
|
||||
|
@ -416,12 +376,6 @@ public class BaseHome
|
|||
}
|
||||
}
|
||||
|
||||
// TODO - inline
|
||||
private String toRelativePath(File dir, File path)
|
||||
{
|
||||
return FS.toRelativePath(dir,path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for <code>toShortForm(file.getCanonicalPath())</code>
|
||||
*/
|
||||
|
|
|
@ -22,11 +22,15 @@ import java.io.Closeable;
|
|||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class FS
|
||||
{
|
||||
@Deprecated
|
||||
public static class AllFilter implements FileFilter
|
||||
{
|
||||
public static final AllFilter INSTANCE = new AllFilter();
|
||||
|
@ -37,7 +41,8 @@ public class FS
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public static class DirFilter implements FileFilter
|
||||
{
|
||||
public static final DirFilter INSTANCE = new DirFilter();
|
||||
|
@ -48,7 +53,8 @@ public class FS
|
|||
return path.isDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public static class RelativeRegexFilter implements FileFilter
|
||||
{
|
||||
private final File baseDir;
|
||||
|
@ -65,12 +71,13 @@ public class FS
|
|||
{
|
||||
// get relative path
|
||||
String relativePath = FS.toRelativePath(baseDir,path);
|
||||
|
||||
|
||||
// see if it matches
|
||||
return (pattern.matcher(relativePath).matches());
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static class FilenameRegexFilter implements FileFilter
|
||||
{
|
||||
private final Pattern pattern;
|
||||
|
@ -87,6 +94,7 @@ public class FS
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static class FileNamesFilter implements FileFilter
|
||||
{
|
||||
private final String filenames[];
|
||||
|
@ -114,6 +122,7 @@ public class FS
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static class IniFilter extends FilenameRegexFilter
|
||||
{
|
||||
public IniFilter()
|
||||
|
@ -122,6 +131,7 @@ public class FS
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static class XmlFilter extends FilenameRegexFilter
|
||||
{
|
||||
public XmlFilter()
|
||||
|
@ -130,11 +140,36 @@ public class FS
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean isValidDirectory(Path path)
|
||||
{
|
||||
LinkOption lopts[] = new LinkOption[0];
|
||||
if (!Files.exists(path,lopts))
|
||||
{
|
||||
// doesn't exist, not a valid directory
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Files.isDirectory(path,lopts))
|
||||
{
|
||||
// not a directory (as expected)
|
||||
StartLog.warn("Not a directory: " + path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean canReadDirectory(File path)
|
||||
{
|
||||
return (path.exists() && path.isDirectory() && path.canRead());
|
||||
}
|
||||
|
||||
public static boolean canReadDirectory(Path path)
|
||||
{
|
||||
LinkOption lopts[] = new LinkOption[0];
|
||||
return Files.exists(path,lopts) && Files.isDirectory(path,lopts) && Files.isReadable(path);
|
||||
}
|
||||
|
||||
public static boolean canReadFile(File path)
|
||||
{
|
||||
return (path.exists() && path.isFile() && path.canRead());
|
||||
|
@ -168,7 +203,7 @@ public class FS
|
|||
throw new IOException("Unable to create directory: " + dir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void ensureDirectoryWritable(File dir) throws IOException
|
||||
{
|
||||
if (!dir.exists())
|
||||
|
@ -194,7 +229,7 @@ public class FS
|
|||
{
|
||||
return filename.toLowerCase(Locale.ENGLISH).endsWith(".xml");
|
||||
}
|
||||
|
||||
|
||||
public static String toRelativePath(File baseDir, File path)
|
||||
{
|
||||
return baseDir.toURI().relativize(path.toURI()).toASCIIString();
|
||||
|
@ -216,4 +251,9 @@ public class FS
|
|||
}
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
public static boolean exists(Path path)
|
||||
{
|
||||
return Files.exists(path,new LinkOption[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.start;
|
||||
|
||||
import static org.eclipse.jetty.start.UsageException.ERR_INVOKE_MAIN;
|
||||
import static org.eclipse.jetty.start.UsageException.ERR_NOT_STOPPED;
|
||||
import static org.eclipse.jetty.start.UsageException.ERR_UNKNOWN;
|
||||
import static org.eclipse.jetty.start.UsageException.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
|
@ -39,6 +37,7 @@ import java.net.InetAddress;
|
|||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -534,17 +533,12 @@ public class Main
|
|||
File start_d = baseHome.getBaseFile("start.d");
|
||||
if (FS.canReadDirectory(start_d))
|
||||
{
|
||||
List<File> files = new ArrayList<>();
|
||||
for (File file : start_d.listFiles(new FS.IniFilter()))
|
||||
List<Path> paths = baseHome.getPaths(start_d.toPath(),1,"*.ini");
|
||||
Collections.sort(paths,new NaturalSort.Paths());
|
||||
for (Path path: paths)
|
||||
{
|
||||
files.add(file);
|
||||
}
|
||||
|
||||
Collections.sort(files,new NaturalSort.Files());
|
||||
for (File file : files)
|
||||
{
|
||||
StartLog.debug("Reading ${jetty.base}/start.d/%s - %s",file.getName(),file);
|
||||
args.parse(baseHome,new StartIni(file));
|
||||
StartLog.debug("Reading ${jetty.base}/start.d/%s - %s",path.getFileName(),path);
|
||||
args.parse(baseHome,new StartIni(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.start;
|
|||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -45,7 +46,7 @@ public class Modules implements Iterable<Module>
|
|||
* ex: modules/npn/npn-1.7.0_01.mod (property expansion resolves to non-existent file)
|
||||
*/
|
||||
private Set<String> missingModules = new HashSet<String>();
|
||||
|
||||
|
||||
private int maxDepth = -1;
|
||||
|
||||
private Set<String> asNameSet(Set<Module> moduleSet)
|
||||
|
@ -294,10 +295,10 @@ public class Modules implements Iterable<Module>
|
|||
|
||||
private void findParents(Module module, Map<String, Module> ret)
|
||||
{
|
||||
ret.put(module.getName(), module);
|
||||
ret.put(module.getName(),module);
|
||||
for (Module parent : module.getParentEdges())
|
||||
{
|
||||
ret.put(parent.getName(), parent);
|
||||
ret.put(parent.getName(),parent);
|
||||
findParents(parent,ret);
|
||||
}
|
||||
}
|
||||
|
@ -371,13 +372,13 @@ public class Modules implements Iterable<Module>
|
|||
|
||||
public void registerAll(BaseHome basehome, StartArgs args) throws IOException
|
||||
{
|
||||
for (File file : basehome.listFiles("modules",new FS.FilenameRegexFilter("^.*\\.mod$")))
|
||||
for (Path path : basehome.getPaths("modules/*.mod"))
|
||||
{
|
||||
registerModule(basehome,args,file);
|
||||
registerModule(basehome,args,path.toFile());
|
||||
}
|
||||
|
||||
// load missing post-expanded dependent modules
|
||||
boolean done = false;
|
||||
boolean done = false;
|
||||
while (!done)
|
||||
{
|
||||
done = true;
|
||||
|
@ -399,14 +400,14 @@ public class Modules implements Iterable<Module>
|
|||
for (String missingParent : missingParents)
|
||||
{
|
||||
File file = basehome.getFile("modules/" + missingParent + ".mod");
|
||||
if ( FS.canReadFile(file) )
|
||||
if (FS.canReadFile(file))
|
||||
{
|
||||
Module module = registerModule(basehome,args,file);
|
||||
updateParentReferencesTo(module);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartLog.debug("Missing module definition: [ Mod: %s | File: %s]", missingParent, file);
|
||||
StartLog.debug("Missing module definition: [ Mod: %s | File: %s]",missingParent,file);
|
||||
missingModules.add(missingParent);
|
||||
}
|
||||
}
|
||||
|
@ -440,7 +441,7 @@ public class Modules implements Iterable<Module>
|
|||
*/
|
||||
public List<Module> resolveEnabled()
|
||||
{
|
||||
Map<String, Module> active = new HashMap<String,Module>();
|
||||
Map<String, Module> active = new HashMap<String, Module>();
|
||||
|
||||
for (Module module : modules.values())
|
||||
{
|
||||
|
@ -455,20 +456,20 @@ public class Modules implements Iterable<Module>
|
|||
*
|
||||
* Ex: npn should match anything under npn/
|
||||
*/
|
||||
for ( String missing : missingModules )
|
||||
for (String missing : missingModules)
|
||||
{
|
||||
for (String activeModule: active.keySet())
|
||||
{
|
||||
if ( missing.startsWith(activeModule) )
|
||||
for (String activeModule : active.keySet())
|
||||
{
|
||||
if (missing.startsWith(activeModule))
|
||||
{
|
||||
StartLog.warn("** Unable to continue, required dependency missing. [%s]", missing);
|
||||
StartLog.warn("** Unable to continue, required dependency missing. [%s]",missing);
|
||||
StartLog.warn("** As configured, Jetty is unable to start due to a missing enabled module dependency.");
|
||||
StartLog.warn("** This may be due to a transitive dependency akin to spdy on npn, which resolves based on the JDK in use.");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<Module> ordered = new ArrayList<>();
|
||||
ordered.addAll(active.values());
|
||||
Collections.sort(ordered,new Module.DepthComparator());
|
||||
|
@ -477,7 +478,7 @@ public class Modules implements Iterable<Module>
|
|||
|
||||
public Set<String> resolveParentModulesOf(String moduleName)
|
||||
{
|
||||
Map<String,Module> ret = new HashMap<>();
|
||||
Map<String, Module> ret = new HashMap<>();
|
||||
Module module = get(moduleName);
|
||||
findParents(module,ret);
|
||||
return ret.keySet();
|
||||
|
@ -524,4 +525,26 @@ public class Modules implements Iterable<Module>
|
|||
m.setParentNames(resolvedParents);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append("Modules[");
|
||||
str.append("count=").append(modules.size());
|
||||
str.append(",<");
|
||||
boolean delim = false;
|
||||
for (String name : modules.keySet())
|
||||
{
|
||||
if (delim)
|
||||
{
|
||||
str.append(',');
|
||||
}
|
||||
str.append(name);
|
||||
delim = true;
|
||||
}
|
||||
str.append(">");
|
||||
str.append("]");
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.start;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.text.CollationKey;
|
||||
import java.text.Collator;
|
||||
import java.util.Comparator;
|
||||
|
@ -28,6 +29,19 @@ import java.util.Comparator;
|
|||
*/
|
||||
public class NaturalSort
|
||||
{
|
||||
public static class Paths implements Comparator<Path>
|
||||
{
|
||||
private final Collator collator = Collator.getInstance();
|
||||
|
||||
@Override
|
||||
public int compare(Path o1, Path o2)
|
||||
{
|
||||
CollationKey key1 = collator.getCollationKey(o1.toString());
|
||||
CollationKey key2 = collator.getCollationKey(o2.toString());
|
||||
return key1.compareTo(key2);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Files implements Comparator<File>
|
||||
{
|
||||
private final Collator collator = Collator.getInstance();
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.start;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystemLoopException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PathFinder extends SimpleFileVisitor<Path>
|
||||
{
|
||||
private boolean includeDirsInResults = false;
|
||||
private Map<String, Path> hits = new HashMap<>();
|
||||
private Path basePath = null;
|
||||
private PathMatcher dirMatcher = PathMatchers.getNonHidden();
|
||||
private PathMatcher fileMatcher = PathMatchers.getNonHidden();
|
||||
|
||||
private void addHit(Path path)
|
||||
{
|
||||
String relPath = basePath.relativize(path).toString();
|
||||
StartLog.debug("addHit(" + path + ") = [" + relPath + "," + path + "]");
|
||||
hits.put(relPath,path);
|
||||
}
|
||||
|
||||
public PathMatcher getDirMatcher()
|
||||
{
|
||||
return dirMatcher;
|
||||
}
|
||||
|
||||
public PathMatcher getFileMatcher()
|
||||
{
|
||||
return fileMatcher;
|
||||
}
|
||||
|
||||
public List<File> getHitList()
|
||||
{
|
||||
List<File> ret = new ArrayList<>();
|
||||
for (Path path : hits.values())
|
||||
{
|
||||
ret.add(path.toFile());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public Collection<Path> getHits()
|
||||
{
|
||||
return hits.values();
|
||||
}
|
||||
|
||||
public boolean isIncludeDirsInResults()
|
||||
{
|
||||
return includeDirsInResults;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
|
||||
{
|
||||
if (dirMatcher.matches(dir))
|
||||
{
|
||||
StartLog.debug("Following dir: " + dir);
|
||||
if (includeDirsInResults)
|
||||
{
|
||||
addHit(dir);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
StartLog.debug("Skipping dir: " + dir);
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the active basePath, used for resolving relative paths.
|
||||
* <p>
|
||||
* When a hit arrives for a subsequent find that has the same relative path as a prior hit, the new hit overrides the prior path as the active hit.
|
||||
*
|
||||
* @param basePath
|
||||
* the basePath to tag all hits with
|
||||
*/
|
||||
public void setBase(Path basePath)
|
||||
{
|
||||
this.basePath = basePath;
|
||||
}
|
||||
|
||||
public void setDirMatcher(PathMatcher dirMatcher)
|
||||
{
|
||||
this.dirMatcher = dirMatcher;
|
||||
}
|
||||
|
||||
public void setFileMatcher(PathMatcher fileMatcher)
|
||||
{
|
||||
this.fileMatcher = fileMatcher;
|
||||
}
|
||||
|
||||
public void setFileMatcher(String pattern)
|
||||
{
|
||||
this.fileMatcher = PathMatchers.getMatcher(pattern);
|
||||
}
|
||||
|
||||
public void setIncludeDirsInResults(boolean includeDirsInResults)
|
||||
{
|
||||
this.includeDirsInResults = includeDirsInResults;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
|
||||
{
|
||||
if (fileMatcher.matches(file))
|
||||
{
|
||||
StartLog.debug("Found file: " + file);
|
||||
addHit(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartLog.debug("Ignoring file: " + file);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
|
||||
{
|
||||
if (exc instanceof FileSystemLoopException)
|
||||
{
|
||||
StartLog.warn("skipping detected filesystem loop: " + file);
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
}
|
||||
else
|
||||
{
|
||||
StartLog.warn(exc);
|
||||
return super.visitFileFailed(file,exc);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.start;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
|
||||
/**
|
||||
* Common PathMatcher implementations.
|
||||
*/
|
||||
public class PathMatchers
|
||||
{
|
||||
private static class NonHiddenMatcher implements PathMatcher
|
||||
{
|
||||
@Override
|
||||
public boolean matches(Path path)
|
||||
{
|
||||
try
|
||||
{
|
||||
return !Files.isHidden(path);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
StartLog.debug(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final char GLOB_CHARS[] = "*?".toCharArray();
|
||||
private static final char SYNTAXED_GLOB_CHARS[] = "{}[]|:".toCharArray();
|
||||
private static final Path EMPTY_PATH = new File(".").toPath();
|
||||
|
||||
/**
|
||||
* Convert a pattern to a Path object.
|
||||
*
|
||||
* @param pattern
|
||||
* the raw pattern (can contain "glob:" or "regex:" syntax indicator)
|
||||
* @return the Path version of the pattern provided.
|
||||
*/
|
||||
private static Path asPath(String pattern)
|
||||
{
|
||||
String test = pattern;
|
||||
if (test.startsWith("glob:"))
|
||||
{
|
||||
test = test.substring("glob:".length());
|
||||
}
|
||||
else if (test.startsWith("regex:"))
|
||||
{
|
||||
test = test.substring("regex:".length());
|
||||
}
|
||||
return new File(test).toPath();
|
||||
}
|
||||
|
||||
public static PathMatcher getMatcher(String pattern)
|
||||
{
|
||||
FileSystem fs = FileSystems.getDefault();
|
||||
|
||||
// If using FileSystem.getPathMatcher() with "glob:" or "regex:"
|
||||
// use FileSystem default pattern behavior
|
||||
if (pattern.startsWith("glob:") || pattern.startsWith("regex:"))
|
||||
{
|
||||
StartLog.debug("Using Standard " + fs.getClass().getName() + " pattern: " + pattern);
|
||||
return fs.getPathMatcher(pattern);
|
||||
}
|
||||
|
||||
// If the pattern starts with a root path then its assumed to
|
||||
// be a full system path
|
||||
for (Path root : fs.getRootDirectories())
|
||||
{
|
||||
StartLog.debug("root: " + root);
|
||||
if (pattern.startsWith(root.toString()))
|
||||
{
|
||||
String pat = "glob:" + pattern;
|
||||
StartLog.debug("Using absolute path pattern: " + pat);
|
||||
return fs.getPathMatcher(pat);
|
||||
}
|
||||
}
|
||||
|
||||
// Doesn't start with filesystem root, then assume the pattern
|
||||
// is a relative file path pattern.
|
||||
String pat = "glob:**/" + pattern;
|
||||
StartLog.debug("Using relative path pattern: " + pat);
|
||||
return fs.getPathMatcher(pat);
|
||||
}
|
||||
|
||||
public static PathMatcher getNonHidden()
|
||||
{
|
||||
return new NonHiddenMatcher();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the non-glob / non-regex prefix on the pattern as a Path reference.
|
||||
*
|
||||
* @param pattern
|
||||
* the pattern to test
|
||||
* @return the Path representing the search root for the pattern provided.
|
||||
*/
|
||||
public static Path getSearchRoot(final String pattern)
|
||||
{
|
||||
Path path = asPath(pattern);
|
||||
Path test = path.getRoot();
|
||||
|
||||
boolean isSyntaxed = pattern.startsWith("glob:") || pattern.startsWith("regex:");
|
||||
|
||||
int len = path.getNameCount();
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
Path part = path.getName(i);
|
||||
if (isGlob(part.toString(),isSyntaxed))
|
||||
{
|
||||
// found a glob part, return prior parts now
|
||||
break;
|
||||
}
|
||||
|
||||
// is this the last entry?
|
||||
if (i == (len - 1))
|
||||
{
|
||||
// always return prior entries
|
||||
break;
|
||||
}
|
||||
|
||||
if (test == null)
|
||||
{
|
||||
test = part;
|
||||
}
|
||||
else
|
||||
{
|
||||
test = test.resolve(part);
|
||||
}
|
||||
}
|
||||
|
||||
if (test == null)
|
||||
{
|
||||
return EMPTY_PATH;
|
||||
}
|
||||
return test;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if provided pattern is an absolute reference (or not)
|
||||
*
|
||||
* @param pattern
|
||||
* the pattern to test
|
||||
* @return true if pattern is an absolute reference.
|
||||
*/
|
||||
public static boolean isAbsolute(final String pattern)
|
||||
{
|
||||
return asPath(pattern).isAbsolute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if part is a glob pattern.
|
||||
*
|
||||
* @param part
|
||||
* the string to check
|
||||
* @param syntaxed
|
||||
* true if overall pattern is syntaxed with <code>"glob:"</code> or <code>"regex:"</code>
|
||||
* @return true if part has glob characters
|
||||
*/
|
||||
private static boolean isGlob(String part, boolean syntaxed)
|
||||
{
|
||||
int len = part.length();
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
char c = part.charAt(i);
|
||||
for (char g : GLOB_CHARS)
|
||||
{
|
||||
if (c == g)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (syntaxed)
|
||||
{
|
||||
for (char g : SYNTAXED_GLOB_CHARS)
|
||||
{
|
||||
if (c == g)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -21,9 +21,9 @@ package org.eclipse.jetty.start;
|
|||
import static org.eclipse.jetty.start.UsageException.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -325,66 +325,10 @@ public class StartArgs
|
|||
StartLog.debug("rawlibref = " + rawlibref);
|
||||
String libref = properties.expand(rawlibref);
|
||||
StartLog.debug("expanded = " + libref);
|
||||
|
||||
if (libref.startsWith("regex:"))
|
||||
|
||||
for (Path libpath : baseHome.getPaths(libref))
|
||||
{
|
||||
String regex = libref.substring("regex:".length());
|
||||
for (File libfile : baseHome.listFilesRegex(regex))
|
||||
{
|
||||
classpath.addComponent(libfile);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
libref = FS.separators(libref);
|
||||
|
||||
// Any globs here?
|
||||
if (libref.contains("*"))
|
||||
{
|
||||
// Glob Reference
|
||||
int idx = libref.lastIndexOf(File.separatorChar);
|
||||
|
||||
String relativePath = "/";
|
||||
String filenameRef = libref;
|
||||
if (idx >= 0)
|
||||
{
|
||||
relativePath = libref.substring(0,idx);
|
||||
filenameRef = libref.substring(idx + 1);
|
||||
}
|
||||
|
||||
StringBuilder regex = new StringBuilder();
|
||||
regex.append('^');
|
||||
for (char c : filenameRef.toCharArray())
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '*':
|
||||
regex.append(".*");
|
||||
break;
|
||||
case '.':
|
||||
regex.append("\\.");
|
||||
break;
|
||||
default:
|
||||
regex.append(c);
|
||||
}
|
||||
}
|
||||
regex.append('$');
|
||||
StartLog.debug("regex = " + regex);
|
||||
|
||||
FileFilter filter = new FS.FilenameRegexFilter(regex.toString());
|
||||
|
||||
List<File> libs = baseHome.listFiles(relativePath,filter);
|
||||
StartLog.debug("found " + libs.size() + " libs");
|
||||
for (File libfile : libs)
|
||||
{
|
||||
classpath.addComponent(libfile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Straight Reference
|
||||
File libfile = baseHome.getFile(libref);
|
||||
classpath.addComponent(libfile);
|
||||
classpath.addComponent(libpath.toFile());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.start;
|
|||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Simple Start .INI handler
|
||||
|
@ -32,6 +33,11 @@ public class StartIni extends TextFile
|
|||
super(file);
|
||||
}
|
||||
|
||||
public StartIni(Path path) throws FileNotFoundException, IOException
|
||||
{
|
||||
this(path.toFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addUniqueLine(String line)
|
||||
{
|
||||
|
|
|
@ -22,6 +22,7 @@ import static org.hamcrest.Matchers.*;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -32,7 +33,55 @@ import org.junit.Test;
|
|||
|
||||
public class BaseHomeTest
|
||||
{
|
||||
private void assertFileList(BaseHome hb, String message, List<String> expected, List<File> files)
|
||||
public static void assertPathList(BaseHome hb, String message, List<String> expected, PathFinder finder)
|
||||
{
|
||||
List<String> actual = new ArrayList<>();
|
||||
for (Path path : finder.getHits())
|
||||
{
|
||||
actual.add(hb.toShortForm(path.toFile()));
|
||||
}
|
||||
|
||||
if (actual.size() != expected.size())
|
||||
{
|
||||
System.out.printf("Actual Path(s): %,d hits%n",actual.size());
|
||||
for (String path : actual)
|
||||
{
|
||||
System.out.printf(" %s%n",path);
|
||||
}
|
||||
System.out.printf("Expected Path(s): %,d entries%n",expected.size());
|
||||
for (String path : expected)
|
||||
{
|
||||
System.out.printf(" %s%n",path);
|
||||
}
|
||||
}
|
||||
Assert.assertThat(message + ": " + Main.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));
|
||||
}
|
||||
|
||||
public static void assertPathList(BaseHome hb, String message, List<String> expected, List<Path> paths)
|
||||
{
|
||||
List<String> actual = new ArrayList<>();
|
||||
for (Path path : paths)
|
||||
{
|
||||
actual.add(hb.toShortForm(path.toFile()));
|
||||
}
|
||||
|
||||
if (actual.size() != expected.size())
|
||||
{
|
||||
System.out.printf("Actual Path(s): %,d hits%n",actual.size());
|
||||
for (String path : actual)
|
||||
{
|
||||
System.out.printf(" %s%n",path);
|
||||
}
|
||||
System.out.printf("Expected Path(s): %,d entries%n",expected.size());
|
||||
for (String path : expected)
|
||||
{
|
||||
System.out.printf(" %s%n",path);
|
||||
}
|
||||
}
|
||||
Assert.assertThat(message + ": " + Main.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));
|
||||
}
|
||||
|
||||
public static void assertFileList(BaseHome hb, String message, List<String> expected, List<File> files)
|
||||
{
|
||||
List<String> actual = new ArrayList<>();
|
||||
for (File file : files)
|
||||
|
@ -42,15 +91,6 @@ public class BaseHomeTest
|
|||
Assert.assertThat(message + ": " + Main.join(actual,", "),actual,containsInAnyOrder(expected.toArray()));
|
||||
}
|
||||
|
||||
private void toOsSeparators(List<String> expected)
|
||||
{
|
||||
for (int i = 0; i < expected.size(); i++)
|
||||
{
|
||||
String fixed = FS.separators(expected.get(i));
|
||||
expected.set(i,fixed);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFile_OnlyHome() throws IOException
|
||||
{
|
||||
|
@ -68,13 +108,13 @@ public class BaseHomeTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testListFiles_OnlyHome() throws IOException
|
||||
public void testGetPaths_OnlyHome() throws IOException
|
||||
{
|
||||
File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home");
|
||||
File baseDir = null;
|
||||
|
||||
BaseHome hb = new BaseHome(homeDir,baseDir);
|
||||
List<File> files = hb.listFiles("/start.d");
|
||||
List<Path> paths = hb.getPaths("start.d/*");
|
||||
|
||||
List<String> expected = new ArrayList<>();
|
||||
expected.add("${jetty.home}/start.d/jmx.ini");
|
||||
|
@ -82,19 +122,19 @@ public class BaseHomeTest
|
|||
expected.add("${jetty.home}/start.d/jsp.ini");
|
||||
expected.add("${jetty.home}/start.d/logging.ini");
|
||||
expected.add("${jetty.home}/start.d/ssl.ini");
|
||||
toOsSeparators(expected);
|
||||
FSTest.toOsSeparators(expected);
|
||||
|
||||
assertFileList(hb,"Files found",expected,files);
|
||||
assertPathList(hb,"Paths found",expected,paths);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListFiles_Filtered_OnlyHome() throws IOException
|
||||
public void testGetPaths_OnlyHome_InisOnly() throws IOException
|
||||
{
|
||||
File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home");
|
||||
File baseDir = null;
|
||||
|
||||
BaseHome hb = new BaseHome(homeDir,baseDir);
|
||||
List<File> files = hb.listFiles("/start.d",new FS.IniFilter());
|
||||
List<Path> paths = hb.getPaths("start.d/*.ini");
|
||||
|
||||
List<String> expected = new ArrayList<>();
|
||||
expected.add("${jetty.home}/start.d/jmx.ini");
|
||||
|
@ -102,19 +142,19 @@ public class BaseHomeTest
|
|||
expected.add("${jetty.home}/start.d/jsp.ini");
|
||||
expected.add("${jetty.home}/start.d/logging.ini");
|
||||
expected.add("${jetty.home}/start.d/ssl.ini");
|
||||
toOsSeparators(expected);
|
||||
FSTest.toOsSeparators(expected);
|
||||
|
||||
assertFileList(hb,"Files found",expected,files);
|
||||
assertPathList(hb,"Paths found",expected,paths);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListFiles_Both() throws IOException
|
||||
public void testGetPaths_Both() throws IOException
|
||||
{
|
||||
File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home");
|
||||
File baseDir = MavenTestingUtils.getTestResourceDir("hb.1/base");
|
||||
|
||||
BaseHome hb = new BaseHome(homeDir,baseDir);
|
||||
List<File> files = hb.listFiles("/start.d");
|
||||
List<Path> paths = hb.getPaths("start.d/*.ini");
|
||||
|
||||
List<String> expected = new ArrayList<>();
|
||||
expected.add("${jetty.base}/start.d/jmx.ini");
|
||||
|
@ -123,9 +163,9 @@ public class BaseHomeTest
|
|||
expected.add("${jetty.base}/start.d/logging.ini");
|
||||
expected.add("${jetty.home}/start.d/ssl.ini");
|
||||
expected.add("${jetty.base}/start.d/myapp.ini");
|
||||
toOsSeparators(expected);
|
||||
FSTest.toOsSeparators(expected);
|
||||
|
||||
assertFileList(hb,"Files found",expected,files);
|
||||
assertPathList(hb,"Paths found",expected,paths);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.start;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class FSTest
|
||||
{
|
||||
@Test
|
||||
public void testCanReadDirectory()
|
||||
{
|
||||
File targetDir = MavenTestingUtils.getTargetDir();
|
||||
Assert.assertTrue("Can read dir: " + targetDir,FS.canReadDirectory(targetDir));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanReadDirectory_NotDir()
|
||||
{
|
||||
File bogusFile = MavenTestingUtils.getTestResourceFile("bogus.xml");
|
||||
Assert.assertFalse("Can read dir: " + bogusFile,FS.canReadDirectory(bogusFile));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCanReadFile()
|
||||
{
|
||||
File pom = MavenTestingUtils.getProjectFile("pom.xml");
|
||||
Assert.assertTrue("Can read file: " + pom,FS.canReadFile(pom));
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method used by other test cases
|
||||
*/
|
||||
public static void toOsSeparators(List<String> expected)
|
||||
{
|
||||
for (int i = 0; i < expected.size(); i++)
|
||||
{
|
||||
String fixed = FS.separators(expected.get(i));
|
||||
expected.set(i,fixed);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -98,7 +98,7 @@ public class MainTest
|
|||
List<String> cmdLineArgs = new ArrayList<>();
|
||||
|
||||
addUseCasesHome(cmdLineArgs);
|
||||
|
||||
|
||||
// JVM args
|
||||
cmdLineArgs.add("--exec");
|
||||
cmdLineArgs.add("-Xms1024m");
|
||||
|
|
|
@ -35,7 +35,7 @@ public class ModulesTest
|
|||
{
|
||||
private final static List<String> TEST_SOURCE = Collections.singletonList("<test>");
|
||||
private StartArgs DEFAULT_ARGS = new StartArgs(new String[] { "jetty.version=TEST" }).parseCommandLine();
|
||||
|
||||
|
||||
@Test
|
||||
public void testLoadAllModules() throws IOException
|
||||
{
|
||||
|
@ -43,10 +43,26 @@ public class ModulesTest
|
|||
BaseHome basehome = new BaseHome(homeDir,homeDir);
|
||||
|
||||
Modules modules = new Modules();
|
||||
modules.registerAll(basehome, DEFAULT_ARGS);
|
||||
Assert.assertThat("Module count",modules.count(),is(30));
|
||||
modules.registerAll(basehome,DEFAULT_ARGS);
|
||||
|
||||
List<String> moduleNames = new ArrayList<>();
|
||||
for (Module mod : modules)
|
||||
{
|
||||
// skip npn-boot in this test (as its behavior is jdk specific)
|
||||
if (mod.getName().equals("npn-boot"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
moduleNames.add(mod.getName());
|
||||
}
|
||||
|
||||
String expected[] = { "jmx", "client", "stats", "spdy", "deploy", "debug", "security", "npn", "ext", "websocket", "rewrite", "ipaccess", "xinetd",
|
||||
"proxy", "webapp", "jndi", "lowresources", "https", "plus", "requestlog", "jsp", "monitor", "xml", "servlet", "jaas", "http", "base", "server",
|
||||
"annotations" };
|
||||
|
||||
Assert.assertThat("Module count: " + moduleNames,moduleNames.size(),is(expected.length));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEnableRegexSimple() throws IOException
|
||||
{
|
||||
|
@ -54,11 +70,11 @@ public class ModulesTest
|
|||
BaseHome basehome = new BaseHome(homeDir,homeDir);
|
||||
|
||||
Modules modules = new Modules();
|
||||
modules.registerAll(basehome, DEFAULT_ARGS);
|
||||
modules.registerAll(basehome,DEFAULT_ARGS);
|
||||
modules.enable("[sj]{1}.*",TEST_SOURCE);
|
||||
|
||||
|
||||
String expected[] = { "jmx", "stats", "spdy", "security", "jndi", "jsp", "servlet", "jaas", "server" };
|
||||
|
||||
|
||||
Assert.assertThat("Enabled Module count",modules.resolveEnabled().size(),is(expected.length));
|
||||
}
|
||||
|
||||
|
@ -70,7 +86,7 @@ public class ModulesTest
|
|||
|
||||
// Register modules
|
||||
Modules modules = new Modules();
|
||||
modules.registerAll(basehome, DEFAULT_ARGS);
|
||||
modules.registerAll(basehome,DEFAULT_ARGS);
|
||||
modules.buildGraph();
|
||||
|
||||
// Enable 2 modules
|
||||
|
@ -108,12 +124,12 @@ public class ModulesTest
|
|||
|
||||
List<String> actualLibs = modules.normalizeLibs(active);
|
||||
Assert.assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
|
||||
|
||||
|
||||
// Assert XML List
|
||||
List<String> expectedXmls = new ArrayList<>();
|
||||
expectedXmls.add("etc/jetty.xml");
|
||||
expectedXmls.add("etc/jetty-http.xml");
|
||||
|
||||
|
||||
List<String> actualXmls = modules.normalizeXmls(active);
|
||||
Assert.assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
|
||||
}
|
||||
|
@ -126,7 +142,7 @@ public class ModulesTest
|
|||
|
||||
// Register modules
|
||||
Modules modules = new Modules();
|
||||
modules.registerAll(basehome, DEFAULT_ARGS);
|
||||
modules.registerAll(basehome,DEFAULT_ARGS);
|
||||
modules.buildGraph();
|
||||
// modules.dump();
|
||||
|
||||
|
@ -136,7 +152,7 @@ public class ModulesTest
|
|||
|
||||
// Collect active module list
|
||||
List<Module> active = modules.resolveEnabled();
|
||||
|
||||
|
||||
// Assert names are correct, and in the right order
|
||||
List<String> expectedNames = new ArrayList<>();
|
||||
expectedNames.add("base");
|
||||
|
@ -174,10 +190,10 @@ public class ModulesTest
|
|||
expectedLibs.add("lib/jetty-annotations-${jetty.version}.jar");
|
||||
expectedLibs.add("lib/annotations/*.jar");
|
||||
expectedLibs.add("lib/websocket/*.jar");
|
||||
|
||||
|
||||
List<String> actualLibs = modules.normalizeLibs(active);
|
||||
Assert.assertThat("Resolved Libs: " + actualLibs,actualLibs,contains(expectedLibs.toArray()));
|
||||
|
||||
|
||||
// Assert XML List
|
||||
List<String> expectedXmls = new ArrayList<>();
|
||||
expectedXmls.add("etc/jetty.xml");
|
||||
|
@ -185,7 +201,7 @@ public class ModulesTest
|
|||
expectedXmls.add("etc/jetty-plus.xml");
|
||||
expectedXmls.add("etc/jetty-annotations.xml");
|
||||
expectedXmls.add("etc/jetty-websockets.xml");
|
||||
|
||||
|
||||
List<String> actualXmls = modules.normalizeXmls(active);
|
||||
Assert.assertThat("Resolved XMLs: " + actualXmls,actualXmls,contains(expectedXmls.toArray()));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.start;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PathFinderTest
|
||||
{
|
||||
@Test
|
||||
public void testFindInis() throws IOException
|
||||
{
|
||||
File homeDir = MavenTestingUtils.getTestResourceDir("hb.1/home");
|
||||
Path homePath = homeDir.toPath();
|
||||
|
||||
PathFinder finder = new PathFinder();
|
||||
finder.setFileMatcher("glob:**/*.ini");
|
||||
finder.setBase(homePath);
|
||||
|
||||
Files.walkFileTree(homePath,EnumSet.of(FileVisitOption.FOLLOW_LINKS),30,finder);
|
||||
|
||||
List<String> expected = new ArrayList<>();
|
||||
expected.add("${jetty.home}/start.d/jmx.ini");
|
||||
expected.add("${jetty.home}/start.d/jndi.ini");
|
||||
expected.add("${jetty.home}/start.d/jsp.ini");
|
||||
expected.add("${jetty.home}/start.d/logging.ini");
|
||||
expected.add("${jetty.home}/start.d/ssl.ini");
|
||||
expected.add("${jetty.home}/start.ini");
|
||||
FSTest.toOsSeparators(expected);
|
||||
|
||||
BaseHome hb = new BaseHome(homeDir,null);
|
||||
BaseHomeTest.assertPathList(hb,"Files found",expected,finder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindMods() throws IOException
|
||||
{
|
||||
File homeDir = MavenTestingUtils.getTestResourceDir("usecases/home");
|
||||
|
||||
List<String> expected = new ArrayList<>();
|
||||
File modulesDir = new File(homeDir,"modules");
|
||||
for (File file : modulesDir.listFiles())
|
||||
{
|
||||
if (file.getName().endsWith(".mod"))
|
||||
{
|
||||
expected.add("${jetty.home}/modules/" + file.getName());
|
||||
}
|
||||
}
|
||||
FSTest.toOsSeparators(expected);
|
||||
|
||||
Path modulesPath = modulesDir.toPath();
|
||||
|
||||
PathFinder finder = new PathFinder();
|
||||
finder.setFileMatcher(PathMatchers.getMatcher("modules/*.mod"));
|
||||
finder.setBase(modulesPath);
|
||||
|
||||
Files.walkFileTree(modulesPath,EnumSet.of(FileVisitOption.FOLLOW_LINKS),1,finder);
|
||||
|
||||
BaseHome hb = new BaseHome(homeDir,null);
|
||||
BaseHomeTest.assertPathList(hb,"Files found",expected,finder);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.start;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.OS;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PathMatchersTest
|
||||
{
|
||||
private void assertIsAbsolute(String pattern, boolean expected)
|
||||
{
|
||||
Assert.assertThat("isAbsolute(\"" + pattern + "\")",PathMatchers.isAbsolute(pattern),is(expected));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAbsolute()
|
||||
{
|
||||
if (OS.IS_UNIX)
|
||||
{
|
||||
assertIsAbsolute("/opt/app",true);
|
||||
assertIsAbsolute("/opt/florb",true);
|
||||
assertIsAbsolute("/home/user/benfranklin",true);
|
||||
assertIsAbsolute("glob:/home/user/benfranklin/*.jar",true);
|
||||
assertIsAbsolute("glob:/**/*.jar",true);
|
||||
assertIsAbsolute("regex:/*-[^dev].ini",true);
|
||||
}
|
||||
|
||||
if (OS.IS_WINDOWS)
|
||||
{
|
||||
assertIsAbsolute("C:\\\\System32",true);
|
||||
assertIsAbsolute("C:\\\\Program Files",true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsNotAbsolute()
|
||||
{
|
||||
assertIsAbsolute("etc",false);
|
||||
assertIsAbsolute("lib",false);
|
||||
assertIsAbsolute("${user.dir}",false);
|
||||
assertIsAbsolute("**/*.jar",false);
|
||||
assertIsAbsolute("glob:*.ini",false);
|
||||
assertIsAbsolute("regex:*-[^dev].ini",false);
|
||||
}
|
||||
|
||||
private void assertSearchRoot(String pattern, String expectedSearchRoot)
|
||||
{
|
||||
Path actual = PathMatchers.getSearchRoot(pattern);
|
||||
String expectedNormal = FS.separators(expectedSearchRoot);
|
||||
Assert.assertThat(".getSearchRoot(\"" + pattern + "\")",actual.toString(),is(expectedNormal));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSearchRoot()
|
||||
{
|
||||
if (OS.IS_UNIX)
|
||||
{
|
||||
// absolute first
|
||||
assertSearchRoot("/opt/app/*.jar","/opt/app");
|
||||
assertSearchRoot("/lib/jvm/**/jre/lib/*.jar","/lib/jvm");
|
||||
assertSearchRoot("glob:/var/lib/*.xml","/var/lib");
|
||||
assertSearchRoot("glob:/var/lib/*.{xml,java}","/var/lib");
|
||||
assertSearchRoot("glob:/opt/corporate/lib-{dev,prod}/*.ini","/opt/corporate");
|
||||
assertSearchRoot("regex:/opt/jetty/.*/lib-(dev|prod)/*.ini","/opt/jetty");
|
||||
|
||||
assertSearchRoot("/*.ini","/");
|
||||
assertSearchRoot("/etc/jetty.conf","/etc");
|
||||
assertSearchRoot("/common.conf","/");
|
||||
}
|
||||
|
||||
if (OS.IS_WINDOWS)
|
||||
{
|
||||
// absolute patterns (complete with required windows slash escaping)
|
||||
assertSearchRoot("C:\\\\corp\\\\lib\\\\*.jar","C:\\corp\\lib");
|
||||
assertSearchRoot("D:\\\\lib\\\\**\\\\jre\\\\lib\\\\*.jar","C:\\lib");
|
||||
}
|
||||
|
||||
// some relative paths
|
||||
assertSearchRoot("lib/*.jar","lib");
|
||||
assertSearchRoot("etc/jetty.xml","etc");
|
||||
assertSearchRoot("start.ini",".");
|
||||
assertSearchRoot("start.d/",".");
|
||||
}
|
||||
}
|
|
@ -76,7 +76,6 @@ public class TestUseCases
|
|||
@Test
|
||||
public void testWithSpdyBadNpnVersion() throws Exception
|
||||
{
|
||||
//StartLog.enableDebug();
|
||||
assertUseCase("home","base.enable.spdy.bad.npn.version","assert-enable-spdy-bad-npn-version.txt","java.version=1.7.0_01");
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
|
||||
[lib]
|
||||
regex:lib/ext/.*\.jar$
|
||||
lib/ext/**.jar
|
||||
|
||||
[files]
|
||||
lib/
|
||||
|
|
Loading…
Reference in New Issue