424168 - Module [ext] should load libraries recursively from lib/ext/

+ Added support for [LIB] definitions that use regex.
+ Using new expression for [LIB] sections in ext.mod
    regex:lib/ext/.*\.jar$
This commit is contained in:
Joakim Erdfelt 2013-12-27 10:30:08 -07:00
parent 3b85ef6174
commit f8e44a1ae7
20 changed files with 211 additions and 9 deletions

View File

@ -3,7 +3,7 @@
# #
[lib] [lib]
lib/ext/*.jar regex:lib/ext/.*\.jar$
[files] [files]
lib/ lib/

View File

@ -32,6 +32,8 @@ import java.util.Objects;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.eclipse.jetty.start.FS.RelativeRegexFilter;
/** /**
* File access for <code>${jetty.home}</code>, <code>${jetty.base}</code>, directories. * File access for <code>${jetty.home}</code>, <code>${jetty.base}</code>, directories.
* <p> * <p>
@ -286,9 +288,85 @@ public class BaseHome
return homeFiles; 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>, with , even if the same file shows up in both places. * 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) public List<File> rawListFiles(String relPathToDirectory, FileFilter filter)
{ {
@ -338,9 +416,10 @@ public class BaseHome
} }
} }
// TODO - inline
private String toRelativePath(File dir, File path) private String toRelativePath(File dir, File path)
{ {
return dir.toURI().relativize(path.toURI()).toASCIIString(); return FS.toRelativePath(dir,path);
} }
/** /**

View File

@ -75,6 +75,7 @@ public class Classpath implements Iterable<File>
public boolean addComponent(File path) public boolean addComponent(File path)
{ {
StartLog.debug("Adding classpath component: %s",path);
if ((path == null) || (!path.exists())) if ((path == null) || (!path.exists()))
{ {
// not a valid component // not a valid component

View File

@ -37,6 +37,39 @@ public class FS
return true; return true;
} }
} }
public static class DirFilter implements FileFilter
{
public static final DirFilter INSTANCE = new DirFilter();
@Override
public boolean accept(File path)
{
return path.isDirectory();
}
}
public static class RelativeRegexFilter implements FileFilter
{
private final File baseDir;
private final Pattern pattern;
public RelativeRegexFilter(File baseDir, Pattern pattern)
{
this.baseDir = baseDir;
this.pattern = pattern;
}
@Override
public boolean accept(File path)
{
// get relative path
String relativePath = FS.toRelativePath(baseDir,path);
// see if it matches
return (pattern.matcher(relativePath).matches());
}
}
public static class FilenameRegexFilter implements FileFilter public static class FilenameRegexFilter implements FileFilter
{ {
@ -149,6 +182,11 @@ public class FS
{ {
return filename.toLowerCase(Locale.ENGLISH).endsWith(".xml"); return filename.toLowerCase(Locale.ENGLISH).endsWith(".xml");
} }
public static String toRelativePath(File baseDir, File path)
{
return baseDir.toURI().relativize(path.toURI()).toASCIIString();
}
public static String separators(String path) public static String separators(String path)
{ {

View File

@ -306,7 +306,7 @@ public class Module
} }
else else
{ {
// blank lines and comments are valid for initialize section // blank lines and comments are valid for ini-template section
if ((line.length() == 0) || line.startsWith("#")) if ((line.length() == 0) || line.startsWith("#"))
{ {
if ("INI-TEMPLATE".equals(sectionType)) if ("INI-TEMPLATE".equals(sectionType))

View File

@ -323,8 +323,20 @@ public class StartArgs
for (String rawlibref : module.getLibs()) for (String rawlibref : module.getLibs())
{ {
String libref = properties.expand(rawlibref); String libref = properties.expand(rawlibref);
if (libref.startsWith("regex:"))
{
String regex = libref.substring("regex:".length());
for (File libfile : baseHome.listFilesRegex(regex))
{
classpath.addComponent(libfile);
}
continue;
}
libref = FS.separators(libref); libref = FS.separators(libref);
// Any globs here?
if (libref.contains("*")) if (libref.contains("*"))
{ {
// Glob Reference // Glob Reference
@ -895,7 +907,7 @@ public class StartArgs
{ {
parse(line,StartArgs.CMD_LINE_SOURCE); parse(line,StartArgs.CMD_LINE_SOURCE);
} }
return this; return this;
} }

View File

@ -96,7 +96,7 @@ public class ConfigurationAssert
} }
} }
List<String> actualProperties = new ArrayList<>(); List<String> actualProperties = new ArrayList<>();
for(Prop prop: args.getProperties()) for (Prop prop : args.getProperties())
{ {
String name = prop.key; String name = prop.key;
if ("jetty.home".equals(name) || "jetty.base".equals(name) || prop.origin.equals(Props.ORIGIN_SYSPROP)) if ("jetty.home".equals(name) || "jetty.base".equals(name) || prop.origin.equals(Props.ORIGIN_SYSPROP))
@ -120,10 +120,31 @@ public class ConfigurationAssert
List<String> actualDownloads = new ArrayList<>(); List<String> actualDownloads = new ArrayList<>();
for (FileArg darg : args.getFiles()) for (FileArg darg : args.getFiles())
{ {
actualDownloads.add(String.format("%s:%s",darg.uri,darg.location)); if (darg.uri != null)
{
actualDownloads.add(String.format("%s:%s",darg.uri,darg.location));
}
} }
assertContainsUnordered("Downloads",expectedDownloads,actualDownloads); assertContainsUnordered("Downloads",expectedDownloads,actualDownloads);
// Validate Files/Dirs creation
List<String> expectedFiles = new ArrayList<>();
for(String line: textFile)
{
if(line.startsWith("FILE|"))
{
expectedFiles.add(getValue(line));
}
}
List<String> actualFiles = new ArrayList<>();
for(FileArg farg: args.getFiles())
{
if(farg.uri == null)
{
actualFiles.add(farg.location);
}
}
assertContainsUnordered("Files/Dirs",expectedFiles,actualFiles);
} }
private static String shorten(BaseHome baseHome, File path, File testResourcesDir) private static String shorten(BaseHome baseHome, File path, File testResourcesDir)

View File

@ -44,7 +44,7 @@ public class ModulesTest
Modules modules = new Modules(); Modules modules = new Modules();
modules.registerAll(basehome, DEFAULT_ARGS); modules.registerAll(basehome, DEFAULT_ARGS);
Assert.assertThat("Module count",modules.count(),is(29)); Assert.assertThat("Module count",modules.count(),is(30));
} }
@Test @Test

View File

@ -73,6 +73,12 @@ public class TestUseCases
assertUseCase("home","base.with.db","assert-with-db.txt"); assertUseCase("home","base.with.db","assert-with-db.txt");
} }
@Test
public void testWithDeepExt() throws Exception
{
assertUseCase("home","base.with.ext","assert-with.ext.txt");
}
@Test @Test
public void testWithPropsBasic() throws Exception public void testWithPropsBasic() throws Exception
{ {

View File

@ -0,0 +1,26 @@
# The XMLs we expect (order is important)
XML|${jetty.home}/etc/jetty.xml
XML|${jetty.home}/etc/jetty-http.xml
# The LIBs we expect (order is irrelevant)
LIB|${jetty.home}/lib/jetty-continuation-TEST.jar
LIB|${jetty.home}/lib/jetty-http-TEST.jar
LIB|${jetty.home}/lib/jetty-io-TEST.jar
LIB|${jetty.home}/lib/jetty-schemas-3.1.jar
LIB|${jetty.home}/lib/jetty-server-TEST.jar
LIB|${jetty.home}/lib/jetty-util-TEST.jar
LIB|${jetty.home}/lib/jetty-xml-TEST.jar
LIB|${jetty.home}/lib/servlet-api-3.1.jar
LIB|${jetty.base}/lib/ext/agent.jar
LIB|${jetty.base}/lib/ext/jdbc/mariadb-jdbc.jar
LIB|${jetty.base}/lib/ext/logging/slf4j-api.jar
LIB|${jetty.base}/lib/ext/logging/jul-to-slf4j.jar
LIB|${jetty.base}/lib/ext/logging/logback-core.jar
LIB|${jetty.base}/lib/ext/logging/logback-classic.jar
# The Properties we expect (order is irrelevant)
PROP|jetty.port=9090
# Files / Directories to create
FILE|lib/
FILE|lib/ext/

View File

@ -0,0 +1,6 @@
--module=server
--module=http
--module=ext
jetty.port=9090

View File

@ -0,0 +1,10 @@
#
# ext module
#
[lib]
regex:lib/ext/.*\.jar$
[files]
lib/
lib/ext/

View File

@ -2,6 +2,9 @@
# Base server # Base server
# #
[optional]
ext
[depend] [depend]
base base
xml xml