|
Appended to this note are fixes for two related Ant
bugs:
BUG 1 -
Project.translatePath()
1. org.apache.tools.ant.taskdefs.Javac uses Project.translatePath() to convert various paths to native
format (i.e., Unix to Win32, etc.). But Project.translatePath() does not always correctly handle
Win32 paths with forward slashes, converting for example
d:/jdk1.3/jre/lib/ext
to
d;\jdk1.3\jre\lib\ext
which is interpreted as two directories instead of
one.
Here is what happens (I added the DEBUG messages to the source code): --- CUT HERE ---
D:\jspcr\docs>ant
Buildfile: build.xml Project base dir set to: D:\jspcr\docs DEBUG: Javac: setExtdirs: entry DEBUG: Javac: setExtdirs: extdirs=d:/jdk1.3/jre/lib/ext DEBUG: Javac: setExtdirs: after project.translatePath() DEBUG: Javac: setExtdirs: this.extdirs=d;\jdk1.3\jre\lib\ext DEBUG: Javac: setExtdirs: exit Executing Target: init Executing Target: compile Compiling 1 source files to D:\jspcr\docs DEBUG: addExtdirsToClasspath: entry DEBUG: addExtdirsToClasspath: classpath=D:\jspcr\docs;D:\ant\lib\ant.jar;D:\jdk1.3\lib\tools.jar DEBUG: addExtdirsToClasspath: extdirs=d;\jdk1.3\jre\lib\ext DEBUG: addExtdirsToClasspath: dir=D:\jspcr\docs\d Exception in thread "main" java.lang.NullPointerException at org.apache.tools.ant.taskdefs.Javac.addExtdirsToClasspath(Javac.java:605) at org.apache.tools.ant.taskdefs.Javac.doJikesCompile(Javac.java:466) at org.apache.tools.ant.taskdefs.Javac.execute(Javac.java:227) at org.apache.tools.ant.Target.execute(Target.java:122) at org.apache.tools.ant.Project.runTarget(Project.java:675) at org.apache.tools.ant.Project.executeTarget(Project.java:422) at org.apache.tools.ant.Main.runBuild(Main.java:248) at org.apache.tools.ant.Main.main(Main.java:191) D:\jspcr\docs>
--- END CUT ---
Here is the build.xml file:
--- CUT HERE ---
<project default="compile" basedir="."
>
<target
name="init">
<tstamp/> <property name="java_home" value="d:/jdk1.3"/> <property name="extdirs" value="${java_home}/jre/lib/ext" /> <property name="build.compiler" value="jikes" /> </target> <target name="compile"
depends="init">
<javac srcdir="." destdir="." extdirs="${extdirs}" /> </target> </project>
--- END CUT ---
Unfortunately, the translatePath() problem is not always
possible to solve because the Unix and Win32 path formats do not map
completely. For example, what should we make of c:/test? It could be a single Win32 directory or two
Unix directories. (Forward slashes should be treated as valid, even on
Win32).
The best we can do is employ a heuristic to determine what platform the string is coded for, and then apply the following decision table: String
Runtime
Platform Platform Action -------- -------- ------ Unix Unix No change required Unix
Win32 Change ":" to ";", "/" to
"\\"
Win32
Unix Remove
"<driveletter>:",
then change ";" to ":", "\\" to "/" Win32
Win32 No change required
A string is considered to be a Win32 path
if
1. It contains any ";" characters, OR
2. It contains any "\\" characters, OR 3. It begins with a letter followed by a ":" I fiddled with Project.translatePath() but ended up writing a
replacement. Here is the patch:
--- CUT HERE ---
--- Project.java Wed May 10 16:20:34 2000 +++ Project.java.new Sat May 13 15:15:03 2000 @@ -482,43 +482,127 @@ } /** - Translate a path into its native (platform specific) - path. This should be extremely fast, code is - borrowed from ECS project. - <p> - All it does is translate the : into ; and / into \ - if needed. In other words, it isn't perfect. - - @returns translated string or empty string if to_process is null or empty - @author Jon S. Stevens <a href="">[EMAIL PROTECTED]</a> + * Translates a path into its native (platform specific) + * path. + * <P> + * This is not always possible because the + * Unix and Win32 path formats do not map completely. + * For example, what should we make of <CODE>c:/test</CODE>? + * It could be a single Win32 directory or two Unix + * directories. (Forward slashes should be treated + * as valid, even on Win32). + * <P> + * The best we can do is employ a heuristic to determine + * what platform the string is coded for, and then apply + * the following decision table: + * <PRE> + * String Runtime + * Platform Platform Action + * -------- -------- ------ + * Unix Unix No change required + * + * Unix Win32 Change ":" to ";", "/" to "\\" + * + * Win32 Unix Remove "<driveletter>:", + * then change ";" to ":", "\\" to "/" + * + * Win32 Win32 No change required + * </PRE> + * A string is considered to be a Win32 path if + * <OL> + * <LI>It contains any ";" characters, <B>OR</B> + * <LI>It contains any "\\" characters, <B>OR</B> + * <LI>It begins with a letter followed by a ":" + * </OL> + * + * @param pathString a path string + * @return translated string + * or empty string if pathString is null or empty */ - public String translatePath(String to_process) { - if ( to_process == null || to_process.length() == 0 ) return ""; + public String translatePath(String pathString) { + + // Simple cases first + + if (pathString == null) + return ""; + int length = pathString.length(); + if (length == 0) + return null; + + // The string to process is considered a Win32 path if + // it contains any semicolons, backslashes, or if it + // begins with a drive letter + ":" + + boolean string_is_win32 = + (pathString.indexOf(";") != -1) || + (pathString.indexOf("\\") != -1) || + ((length > 1) + && (Character.isLetter(pathString.charAt(0))) + && (pathString.charAt(1) == ':')); + + // The runtime platform is considered to be Win32 + // if the path separator is ";" + + boolean platform_is_win32 = + System.getProperty("path.separator").equals(";"); + + // No change is required if the platforms are the same + + if (string_is_win32 == platform_is_win32) + return pathString; + + // Win32 to Unix translation: - StringBuffer bs = new StringBuffer(to_process.length() + 50); - StringCharacterIterator sci = new StringCharacterIterator(to_process); - String path = System.getProperty("path.separator"); - String file = System.getProperty("file.separator"); - String tmp = null; - for (char c = sci.first(); c != CharacterIterator.DONE; c = sci.next()) { - tmp = String.valueOf(c); - - if (tmp.equals(":")) { - // could be a DOS drive or a Unix path separator... - // if followed by a backslash, assume it is a drive - c = sci.next(); - tmp = String.valueOf(c); - bs.append( tmp.equals("\\") ? ":" : path ); - if (c == CharacterIterator.DONE) break; + if (string_is_win32) { + + // Ugly problem: There is no completely correct + // way to translate drive letters, since Unix + // does not use them. Moreover, if an absolute + // path is intended, it probably does not make + // sense to convert it to "/" - it is more likely + // to be "~/" or something. + // + // Solution: Remove drive letters and the colons + // that follow them altogether. If the user has + // a mix of "C:" and "D:" designations in the + // path and wants to run it on Unix, the user must + // untangle it first. + + int p = pathString.indexOf(":"); + if (p != -1) { + StringBuffer sb = new StringBuffer(); + int goodLength = 0; // Last known good length + for (int i = 0; i < length; i++) { + char c = pathString.charAt(i); + if (c == ':') { + sb.setLength(goodLength); + } + else { + sb.append(c); + if (c == ';') + goodLength = sb.length(); + } + } + pathString = sb.toString(); } - if (tmp.equals(":") || tmp.equals(";")) - tmp = path; - else if (tmp.equals("/") || tmp.equals ("\\")) - tmp = file; - bs.append(tmp); + // Now translate ";" to ":" and "\\" to "/" + + pathString = pathString.replace(';', ':'); + pathString = pathString.replace('\\', '/'); } - return(bs.toString()); + + // Unix to Win32 translation: + + else { + + // Translate ":" to ";" and "/" to "\\" + + pathString = pathString.replace(':', ';'); + pathString = pathString.replace('/', '\\'); + } + + return pathString; } /** --- END CUT ---
BUG 2 - Javac.addExtdirsToClasspath()
2. org.apache.tools.ant.taskdefs.Javac gets a null pointer
exception in addExtdirsToClasspath() if any element of
the path refers to a directory which does not exist. The fix consists of testing the file list for null before entering
the loop. Here is the patch:
--- CUT HERE ---
--- Javac.java Wed May 10 16:20:34 2000
+++ Javac.java.new Sat May 13 15:45:58 2000 @@ -593,6 +593,7 @@ while (tok.hasMoreTokens()) { File dir = project.resolveFile(tok.nextToken()); String[] files = dir.list(new JarFilenameFilter()); + if (files == null) continue; for (int i=0 ; i < files.length ; i++) { File f = new File(dir,files[i]); if (f.exists() && f.isFile()) { --- END CUT ---
Thanks,
Phil Hanna |
- Re: Fixes for org.apache.tools.ant.taskdefs.Javac and org.... Phil Hanna
- Re: Fixes for org.apache.tools.ant.taskdefs.Javac and... Tom Cook
- Beginner questions for setting up build environme... tom goodman
- Re: Beginner questions for setting up build e... Stefan Bodewig
- RE: Fixes for org.apache.tools.ant.taskdefs.Javac and... Conor MacNeill
- Fw: Fixes for org.apache.tools.ant.taskdefs.Javac and... Phil Hanna
- RE: Fixes for org.apache.tools.ant.taskdefs.Javac... Conor MacNeill
- Re: Fixes for org.apache.tools.ant.taskdefs.J... Eugene Bekker
- RE: Fixes for org.apache.tools.ant.taskdefs.Javac and... wolf . siberski
