git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@292553 13f79535-47bb-0310-9956-ffa450edef68master
@@ -20,7 +20,7 @@ import java.io.IOException; | |||||
import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
import org.apache.tools.ant.types.Resource; | import org.apache.tools.ant.types.Resource; | ||||
import org.apache.tools.ant.util.FileUtils; | |||||
import org.apache.tools.ant.util.ResourceUtils; | |||||
/** | /** | ||||
* Compares Resources by content. | * Compares Resources by content. | ||||
@@ -60,7 +60,7 @@ public class Content extends ResourceComparator { | |||||
*/ | */ | ||||
protected int resourceCompare(Resource foo, Resource bar) { | protected int resourceCompare(Resource foo, Resource bar) { | ||||
try { | try { | ||||
return FileUtils.getFileUtils().compareContent(foo, bar, !binary); | |||||
return ResourceUtils.compareContent(foo, bar, !binary); | |||||
} catch (IOException e) { | } catch (IOException e) { | ||||
throw new BuildException(e); | throw new BuildException(e); | ||||
} | } | ||||
@@ -38,6 +38,7 @@ import org.apache.tools.ant.types.resources.FileResource; | |||||
import org.apache.tools.ant.types.resources.selectors.ResourceSelector; | import org.apache.tools.ant.types.resources.selectors.ResourceSelector; | ||||
import org.apache.tools.ant.types.selectors.BaseExtendSelector; | import org.apache.tools.ant.types.selectors.BaseExtendSelector; | ||||
import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
import org.apache.tools.ant.util.ResourceUtils; | |||||
/** | /** | ||||
@@ -540,7 +541,7 @@ public class ModifiedSelector extends BaseExtendSelector | |||||
FileUtils fu = FileUtils.getFileUtils(); | FileUtils fu = FileUtils.getFileUtils(); | ||||
File tmpFile = fu.createTempFile("modified-", ".tmp", null); | File tmpFile = fu.createTempFile("modified-", ".tmp", null); | ||||
Resource tmpResource = new FileResource(tmpFile); | Resource tmpResource = new FileResource(tmpFile); | ||||
fu.copyResource(resource, tmpResource); | |||||
ResourceUtils.copyResource(resource, tmpResource); | |||||
boolean isSelected = isSelected(tmpFile.getParentFile(), | boolean isSelected = isSelected(tmpFile.getParentFile(), | ||||
tmpFile.getName(), | tmpFile.getName(), | ||||
resource.toLongString()); | resource.toLongString()); | ||||
@@ -41,9 +41,7 @@ import org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.filters.util.ChainReaderHelper; | import org.apache.tools.ant.filters.util.ChainReaderHelper; | ||||
import org.apache.tools.ant.taskdefs.condition.Os; | import org.apache.tools.ant.taskdefs.condition.Os; | ||||
import org.apache.tools.ant.types.Resource; | |||||
import org.apache.tools.ant.types.FilterSetCollection; | import org.apache.tools.ant.types.FilterSetCollection; | ||||
import org.apache.tools.ant.types.resources.Touchable; | |||||
import org.apache.tools.ant.types.resources.FileResource; | import org.apache.tools.ant.types.resources.FileResource; | ||||
import org.apache.tools.ant.launch.Locator; | import org.apache.tools.ant.launch.Locator; | ||||
@@ -54,7 +52,6 @@ import org.apache.tools.ant.launch.Locator; | |||||
* their last modification time. | * their last modification time. | ||||
* | * | ||||
*/ | */ | ||||
public class FileUtils { | public class FileUtils { | ||||
private static final FileUtils PRIMARY_INSTANCE = new FileUtils(); | private static final FileUtils PRIMARY_INSTANCE = new FileUtils(); | ||||
@@ -68,7 +65,7 @@ public class FileUtils { | |||||
private static boolean onWin9x = Os.isFamily("win9x"); | private static boolean onWin9x = Os.isFamily("win9x"); | ||||
private static boolean onWindows = Os.isFamily("windows"); | private static boolean onWindows = Os.isFamily("windows"); | ||||
private static final int BUF_SIZE = 8192; | |||||
static final int BUF_SIZE = 8192; | |||||
// for toURI | // for toURI | ||||
private static boolean[] isSpecial = new boolean[256]; | private static boolean[] isSpecial = new boolean[256]; | ||||
@@ -520,206 +517,12 @@ public class FileUtils { | |||||
String inputEncoding, String outputEncoding, | String inputEncoding, String outputEncoding, | ||||
Project project) | Project project) | ||||
throws IOException { | throws IOException { | ||||
copyResource(new FileResource(sourceFile), new FileResource(destFile), | |||||
ResourceUtils.copyResource( | |||||
new FileResource(sourceFile), new FileResource(destFile), | |||||
filters, filterChains, overwrite, preserveLastModified, | filters, filterChains, overwrite, preserveLastModified, | ||||
inputEncoding, outputEncoding, project); | inputEncoding, outputEncoding, project); | ||||
} | } | ||||
/** | |||||
* Convenience method to copy content from one Resource to another. | |||||
* No filtering is performed. | |||||
* | |||||
* @param source the Resource to copy from. | |||||
* Must not be <code>null</code>. | |||||
* @param dest the Resource to copy to. | |||||
* Must not be <code>null</code>. | |||||
* | |||||
* @throws IOException if the copying fails. | |||||
* | |||||
* @since Ant 1.7 | |||||
*/ | |||||
public void copyResource(Resource source, Resource dest) throws IOException { | |||||
copyResource(source, dest, null); | |||||
} | |||||
/** | |||||
* Convenience method to copy content from one Resource to another. | |||||
* No filtering is performed. | |||||
* | |||||
* @param source the Resource to copy from. | |||||
* Must not be <code>null</code>. | |||||
* @param dest the Resource to copy to. | |||||
* Must not be <code>null</code>. | |||||
* @param project the project instance. | |||||
* | |||||
* @throws IOException if the copying fails. | |||||
* | |||||
* @since Ant 1.7 | |||||
*/ | |||||
public void copyResource(Resource source, Resource dest, Project project) | |||||
throws IOException { | |||||
copyResource(source, dest, null, null, false, | |||||
false, null, null, project); | |||||
} | |||||
/** | |||||
* Convenience method to copy content from one Resource to another | |||||
* specifying whether token filtering must be used, whether filter chains | |||||
* must be used, whether newer destination files may be overwritten and | |||||
* whether the last modified time of <code>dest</code> file should be made | |||||
* equal to the last modified time of <code>source</code>. | |||||
* | |||||
* @param source the Resource to copy from. | |||||
* Must not be <code>null</code>. | |||||
* @param dest the Resource to copy to. | |||||
* Must not be <code>null</code>. | |||||
* @param filters the collection of filters to apply to this copy. | |||||
* @param filterChains filterChains to apply during the copy. | |||||
* @param overwrite Whether or not the destination Resource should be | |||||
* overwritten if it already exists. | |||||
* @param preserveLastModified Whether or not the last modified time of | |||||
* the destination Resource should be set to that | |||||
* of the source. | |||||
* @param inputEncoding the encoding used to read the files. | |||||
* @param outputEncoding the encoding used to write the files. | |||||
* @param project the project instance. | |||||
* | |||||
* @throws IOException if the copying fails. | |||||
* | |||||
* @since Ant 1.7 | |||||
*/ | |||||
public void copyResource(Resource source, Resource dest, | |||||
FilterSetCollection filters, Vector filterChains, | |||||
boolean overwrite, boolean preserveLastModified, | |||||
String inputEncoding, String outputEncoding, | |||||
Project project) | |||||
throws IOException { | |||||
if (!overwrite) { | |||||
long slm = source.getLastModified(); | |||||
if (dest.isExists() && slm != 0 | |||||
&& dest.getLastModified() > slm) { | |||||
return; | |||||
} | |||||
} | |||||
final boolean filterSetsAvailable = (filters != null | |||||
&& filters.hasFilters()); | |||||
final boolean filterChainsAvailable = (filterChains != null | |||||
&& filterChains.size() > 0); | |||||
if (filterSetsAvailable) { | |||||
BufferedReader in = null; | |||||
BufferedWriter out = null; | |||||
try { | |||||
InputStreamReader isr = null; | |||||
if (inputEncoding == null) { | |||||
isr = new InputStreamReader(source.getInputStream()); | |||||
} else { | |||||
isr = new InputStreamReader(source.getInputStream(), | |||||
inputEncoding); | |||||
} | |||||
in = new BufferedReader(isr); | |||||
OutputStreamWriter osw = null; | |||||
if (outputEncoding == null) { | |||||
osw = new OutputStreamWriter(dest.getOutputStream()); | |||||
} else { | |||||
osw = new OutputStreamWriter(dest.getOutputStream(), | |||||
outputEncoding); | |||||
} | |||||
out = new BufferedWriter(osw); | |||||
if (filterChainsAvailable) { | |||||
ChainReaderHelper crh = new ChainReaderHelper(); | |||||
crh.setBufferSize(BUF_SIZE); | |||||
crh.setPrimaryReader(in); | |||||
crh.setFilterChains(filterChains); | |||||
crh.setProject(project); | |||||
Reader rdr = crh.getAssembledReader(); | |||||
in = new BufferedReader(rdr); | |||||
} | |||||
LineTokenizer lineTokenizer = new LineTokenizer(); | |||||
lineTokenizer.setIncludeDelims(true); | |||||
String newline = null; | |||||
String line = lineTokenizer.getToken(in); | |||||
while (line != null) { | |||||
if (line.length() == 0) { | |||||
// this should not happen, because the lines are | |||||
// returned with the end of line delimiter | |||||
out.newLine(); | |||||
} else { | |||||
newline = filters.replaceTokens(line); | |||||
out.write(newline); | |||||
} | |||||
line = lineTokenizer.getToken(in); | |||||
} | |||||
} finally { | |||||
close(out); | |||||
close(in); | |||||
} | |||||
} else if (filterChainsAvailable | |||||
|| (inputEncoding != null | |||||
&& !inputEncoding.equals(outputEncoding)) | |||||
|| (inputEncoding == null && outputEncoding != null)) { | |||||
BufferedReader in = null; | |||||
BufferedWriter out = null; | |||||
try { | |||||
InputStreamReader isr = null; | |||||
if (inputEncoding == null) { | |||||
isr = new InputStreamReader(source.getInputStream()); | |||||
} else { | |||||
isr = new InputStreamReader(source.getInputStream(), | |||||
inputEncoding); | |||||
} | |||||
in = new BufferedReader(isr); | |||||
OutputStreamWriter osw = null; | |||||
if (outputEncoding == null) { | |||||
osw = new OutputStreamWriter(dest.getOutputStream()); | |||||
} else { | |||||
osw = new OutputStreamWriter(dest.getOutputStream(), | |||||
outputEncoding); | |||||
} | |||||
out = new BufferedWriter(osw); | |||||
if (filterChainsAvailable) { | |||||
ChainReaderHelper crh = new ChainReaderHelper(); | |||||
crh.setBufferSize(BUF_SIZE); | |||||
crh.setPrimaryReader(in); | |||||
crh.setFilterChains(filterChains); | |||||
crh.setProject(project); | |||||
Reader rdr = crh.getAssembledReader(); | |||||
in = new BufferedReader(rdr); | |||||
} | |||||
char[] buffer = new char[BUF_SIZE]; | |||||
while (true) { | |||||
int nRead = in.read(buffer, 0, buffer.length); | |||||
if (nRead == -1) { | |||||
break; | |||||
} | |||||
out.write(buffer, 0, nRead); | |||||
} | |||||
} finally { | |||||
close(out); | |||||
close(in); | |||||
} | |||||
} else { | |||||
InputStream in = null; | |||||
OutputStream out = null; | |||||
try { | |||||
in = source.getInputStream(); | |||||
out = dest.getOutputStream(); | |||||
byte[] buffer = new byte[BUF_SIZE]; | |||||
int count = 0; | |||||
do { | |||||
out.write(buffer, 0, count); | |||||
count = in.read(buffer, 0, buffer.length); | |||||
} while (count != -1); | |||||
} finally { | |||||
close(out); | |||||
close(in); | |||||
} | |||||
} | |||||
if (preserveLastModified && dest instanceof Touchable) { | |||||
setLastModified((Touchable) dest, source.getLastModified()); | |||||
} | |||||
} | |||||
/** | /** | ||||
* Calls File.setLastModified(long time). Originally written to | * Calls File.setLastModified(long time). Originally written to | ||||
* to dynamically bind to that call on Java1.2+. | * to dynamically bind to that call on Java1.2+. | ||||
@@ -729,19 +532,7 @@ public class FileUtils { | |||||
* if this is -1, the current time is used. | * if this is -1, the current time is used. | ||||
*/ | */ | ||||
public void setFileLastModified(File file, long time) { | public void setFileLastModified(File file, long time) { | ||||
setLastModified(new FileResource(file), time); | |||||
} | |||||
/** | |||||
* Set the last modified time of an object implementing | |||||
* org.apache.tools.ant.types.resources.Touchable . | |||||
* | |||||
* @param t the Touchable whose modified time is to be set. | |||||
* @param time the time to which the last modified time is to be set. | |||||
* if this is -1, the current time is used. | |||||
*/ | |||||
public void setLastModified(Touchable t, long time) { | |||||
t.touch((time < 0) ? System.currentTimeMillis() : time); | |||||
ResourceUtils.setLastModified(new FileResource(file), time); | |||||
} | } | ||||
/** | /** | ||||
@@ -897,6 +688,7 @@ public class FileUtils { | |||||
* @param path the path to dissect. | * @param path the path to dissect. | ||||
* @return String[] {root, remaining path}. | * @return String[] {root, remaining path}. | ||||
* @throws java.lang.NullPointerException if path is null. | * @throws java.lang.NullPointerException if path is null. | ||||
* @since Ant 1.7 | |||||
*/ | */ | ||||
public String[] dissect(String path) { | public String[] dissect(String path) { | ||||
char sep = File.separatorChar; | char sep = File.separatorChar; | ||||
@@ -1063,143 +855,8 @@ public class FileUtils { | |||||
* @since Ant 1.6.3 | * @since Ant 1.6.3 | ||||
*/ | */ | ||||
public boolean contentEquals(File f1, File f2, boolean textfile) throws IOException { | public boolean contentEquals(File f1, File f2, boolean textfile) throws IOException { | ||||
return contentEquals(new FileResource(f1), new FileResource(f2), textfile); | |||||
} | |||||
/** | |||||
* Compares the contents of two Resources. | |||||
* | |||||
* @param r1 the Resource whose content is to be compared. | |||||
* @param r2 the other Resource whose content is to be compared. | |||||
* @param text true if the content is to be treated as text and | |||||
* differences in kind of line break are to be ignored. | |||||
* | |||||
* @return true if the content of the Resources is the same. | |||||
* | |||||
* @throws IOException if the Resources cannot be read. | |||||
* @since Ant 1.6.3 | |||||
*/ | |||||
public boolean contentEquals(Resource r1, Resource r2, boolean text) throws IOException { | |||||
if (r1.isExists() != r2.isExists()) { | |||||
return false; | |||||
} | |||||
if (!r1.isExists()) { | |||||
// two not existing files are equal | |||||
return true; | |||||
} | |||||
// should the following two be switched? If r1 and r2 refer to the same file, | |||||
// isn't their content equal regardless of whether that file is a directory? | |||||
if (r1.isDirectory() || r2.isDirectory()) { | |||||
// don't want to compare directory contents for now | |||||
return false; | |||||
} | |||||
if (r1.equals(r2)) { | |||||
return true; | |||||
} | |||||
if (!text && r1.getSize() != r2.getSize()) { | |||||
return false; | |||||
} | |||||
return compareContent(r1, r2, text) == 0; | |||||
} | |||||
/** | |||||
* Compare the content of two Resources. A nonexistent Resource's | |||||
* content is "less than" that of an existing Resource; a directory-type | |||||
* Resource's content is "less than" that of a file-type Resource. | |||||
* @param r1 the Resource whose content is to be compared. | |||||
* @param r2 the other Resource whose content is to be compared. | |||||
* @param text true if the content is to be treated as text and | |||||
* differences in kind of line break are to be ignored. | |||||
* @return a negative integer, zero, or a positive integer as the first | |||||
* argument is less than, equal to, or greater than the second. | |||||
* @throws IOException if the Resources cannot be read. | |||||
*/ | |||||
public int compareContent(Resource r1, Resource r2, boolean text) throws IOException { | |||||
if (r1.equals(r2)) { | |||||
return 0; | |||||
} | |||||
boolean e1 = r1.isExists(); | |||||
boolean e2 = r2.isExists(); | |||||
if (!(e1 || e2)) { | |||||
return 0; | |||||
} | |||||
if (e1 != e2) { | |||||
return e1 ? 1 : -1; | |||||
} | |||||
boolean d1 = r1.isDirectory(); | |||||
boolean d2 = r2.isDirectory(); | |||||
if (d1 && d2) { | |||||
return 0; | |||||
} | |||||
if (d1 || d2) { | |||||
return d1 ? -1 : 1; | |||||
} | |||||
return text ? textCompare(r1, r2) : binaryCompare(r1, r2); | |||||
} | |||||
/** | |||||
* Binary compares the contents of two Resources. | |||||
* <p> | |||||
* simple but sub-optimal comparision algorithm. written for working | |||||
* rather than fast. Better would be a block read into buffers followed | |||||
* by long comparisions apart from the final 1-7 bytes. | |||||
* </p> | |||||
* | |||||
* @param r1 the Resource whose content is to be compared. | |||||
* @param r2 the other Resource whose content is to be compared. | |||||
* @return a negative integer, zero, or a positive integer as the first | |||||
* argument is less than, equal to, or greater than the second. | |||||
* @throws IOException if the Resources cannot be read. | |||||
*/ | |||||
private int binaryCompare(Resource r1, Resource r2) throws IOException { | |||||
InputStream in1 = null; | |||||
InputStream in2 = null; | |||||
try { | |||||
in1 = new BufferedInputStream(r1.getInputStream()); | |||||
in2 = new BufferedInputStream(r2.getInputStream()); | |||||
for (int b1 = in1.read(); b1 != -1; b1 = in1.read()) { | |||||
int b2 = in2.read(); | |||||
if (b1 != b2) { | |||||
return b1 > b2 ? 1 : -1; | |||||
} | |||||
} | |||||
return in2.read() == -1 ? 0 : -1; | |||||
} finally { | |||||
close(in1); | |||||
close(in2); | |||||
} | |||||
} | |||||
/** | |||||
* Text compares the contents of two Resources. | |||||
* Ignores different kinds of line endings. | |||||
* @param r1 the Resource whose content is to be compared. | |||||
* @param r2 the other Resource whose content is to be compared. | |||||
* @return a negative integer, zero, or a positive integer as the first | |||||
* argument is less than, equal to, or greater than the second. | |||||
* @throws IOException if the Resources cannot be read. | |||||
*/ | |||||
private int textCompare(Resource r1, Resource r2) throws IOException { | |||||
BufferedReader in1 = null; | |||||
BufferedReader in2 = null; | |||||
try { | |||||
in1 = new BufferedReader(new InputStreamReader(r1.getInputStream())); | |||||
in2 = new BufferedReader(new InputStreamReader(r2.getInputStream())); | |||||
String expected = in1.readLine(); | |||||
while (expected != null) { | |||||
String actual = in2.readLine(); | |||||
if (!expected.equals(actual)) { | |||||
return expected.compareTo(actual); | |||||
} | |||||
expected = in1.readLine(); | |||||
} | |||||
return in2.readLine() == null ? 0 : -1; | |||||
} finally { | |||||
close(in1); | |||||
close(in2); | |||||
} | |||||
return ResourceUtils.contentEquals( | |||||
new FileResource(f1), new FileResource(f2), textfile); | |||||
} | } | ||||
/** | /** | ||||
@@ -17,18 +17,31 @@ | |||||
package org.apache.tools.ant.util; | package org.apache.tools.ant.util; | ||||
import java.io.File; | import java.io.File; | ||||
import java.io.Reader; | |||||
import java.io.InputStream; | |||||
import java.io.IOException; | |||||
import java.io.OutputStream; | |||||
import java.io.BufferedReader; | |||||
import java.io.BufferedWriter; | |||||
import java.io.InputStreamReader; | |||||
import java.io.OutputStreamWriter; | |||||
import java.io.BufferedInputStream; | |||||
import java.util.Arrays; | import java.util.Arrays; | ||||
import java.util.Vector; | |||||
import java.util.Iterator; | import java.util.Iterator; | ||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.ProjectComponent; | import org.apache.tools.ant.ProjectComponent; | ||||
import org.apache.tools.ant.filters.util.ChainReaderHelper; | |||||
import org.apache.tools.ant.types.Resource; | import org.apache.tools.ant.types.Resource; | ||||
import org.apache.tools.ant.types.TimeComparison; | import org.apache.tools.ant.types.TimeComparison; | ||||
import org.apache.tools.ant.types.ResourceFactory; | import org.apache.tools.ant.types.ResourceFactory; | ||||
import org.apache.tools.ant.types.ResourceCollection; | import org.apache.tools.ant.types.ResourceCollection; | ||||
import org.apache.tools.ant.types.FilterSetCollection; | |||||
import org.apache.tools.ant.types.resources.Union; | import org.apache.tools.ant.types.resources.Union; | ||||
import org.apache.tools.ant.types.resources.Restrict; | import org.apache.tools.ant.types.resources.Restrict; | ||||
import org.apache.tools.ant.types.resources.Resources; | import org.apache.tools.ant.types.resources.Resources; | ||||
import org.apache.tools.ant.types.resources.Touchable; | |||||
import org.apache.tools.ant.types.resources.selectors.Or; | import org.apache.tools.ant.types.resources.selectors.Or; | ||||
import org.apache.tools.ant.types.resources.selectors.And; | import org.apache.tools.ant.types.resources.selectors.And; | ||||
import org.apache.tools.ant.types.resources.selectors.Not; | import org.apache.tools.ant.types.resources.selectors.Not; | ||||
@@ -175,6 +188,360 @@ public class ResourceUtils { | |||||
return result; | return result; | ||||
} | } | ||||
/** | |||||
* Convenience method to copy content from one Resource to another. | |||||
* No filtering is performed. | |||||
* | |||||
* @param source the Resource to copy from. | |||||
* Must not be <code>null</code>. | |||||
* @param dest the Resource to copy to. | |||||
* Must not be <code>null</code>. | |||||
* | |||||
* @throws IOException if the copying fails. | |||||
* | |||||
* @since Ant 1.7 | |||||
*/ | |||||
public static void copyResource(Resource source, Resource dest) throws IOException { | |||||
copyResource(source, dest, null); | |||||
} | |||||
/** | |||||
* Convenience method to copy content from one Resource to another. | |||||
* No filtering is performed. | |||||
* | |||||
* @param source the Resource to copy from. | |||||
* Must not be <code>null</code>. | |||||
* @param dest the Resource to copy to. | |||||
* Must not be <code>null</code>. | |||||
* @param project the project instance. | |||||
* | |||||
* @throws IOException if the copying fails. | |||||
* | |||||
* @since Ant 1.7 | |||||
*/ | |||||
public static void copyResource(Resource source, Resource dest, Project project) | |||||
throws IOException { | |||||
copyResource(source, dest, null, null, false, | |||||
false, null, null, project); | |||||
} | |||||
/** | |||||
* Convenience method to copy content from one Resource to another | |||||
* specifying whether token filtering must be used, whether filter chains | |||||
* must be used, whether newer destination files may be overwritten and | |||||
* whether the last modified time of <code>dest</code> file should be made | |||||
* equal to the last modified time of <code>source</code>. | |||||
* | |||||
* @param source the Resource to copy from. | |||||
* Must not be <code>null</code>. | |||||
* @param dest the Resource to copy to. | |||||
* Must not be <code>null</code>. | |||||
* @param filters the collection of filters to apply to this copy. | |||||
* @param filterChains filterChains to apply during the copy. | |||||
* @param overwrite Whether or not the destination Resource should be | |||||
* overwritten if it already exists. | |||||
* @param preserveLastModified Whether or not the last modified time of | |||||
* the destination Resource should be set to that | |||||
* of the source. | |||||
* @param inputEncoding the encoding used to read the files. | |||||
* @param outputEncoding the encoding used to write the files. | |||||
* @param project the project instance. | |||||
* | |||||
* @throws IOException if the copying fails. | |||||
* | |||||
* @since Ant 1.7 | |||||
*/ | |||||
public static void copyResource(Resource source, Resource dest, | |||||
FilterSetCollection filters, Vector filterChains, | |||||
boolean overwrite, boolean preserveLastModified, | |||||
String inputEncoding, String outputEncoding, | |||||
Project project) | |||||
throws IOException { | |||||
if (!overwrite) { | |||||
long slm = source.getLastModified(); | |||||
if (dest.isExists() && slm != 0 | |||||
&& dest.getLastModified() > slm) { | |||||
return; | |||||
} | |||||
} | |||||
final boolean filterSetsAvailable = (filters != null | |||||
&& filters.hasFilters()); | |||||
final boolean filterChainsAvailable = (filterChains != null | |||||
&& filterChains.size() > 0); | |||||
if (filterSetsAvailable) { | |||||
BufferedReader in = null; | |||||
BufferedWriter out = null; | |||||
try { | |||||
InputStreamReader isr = null; | |||||
if (inputEncoding == null) { | |||||
isr = new InputStreamReader(source.getInputStream()); | |||||
} else { | |||||
isr = new InputStreamReader(source.getInputStream(), | |||||
inputEncoding); | |||||
} | |||||
in = new BufferedReader(isr); | |||||
OutputStreamWriter osw = null; | |||||
if (outputEncoding == null) { | |||||
osw = new OutputStreamWriter(dest.getOutputStream()); | |||||
} else { | |||||
osw = new OutputStreamWriter(dest.getOutputStream(), | |||||
outputEncoding); | |||||
} | |||||
out = new BufferedWriter(osw); | |||||
if (filterChainsAvailable) { | |||||
ChainReaderHelper crh = new ChainReaderHelper(); | |||||
crh.setBufferSize(FileUtils.BUF_SIZE); | |||||
crh.setPrimaryReader(in); | |||||
crh.setFilterChains(filterChains); | |||||
crh.setProject(project); | |||||
Reader rdr = crh.getAssembledReader(); | |||||
in = new BufferedReader(rdr); | |||||
} | |||||
LineTokenizer lineTokenizer = new LineTokenizer(); | |||||
lineTokenizer.setIncludeDelims(true); | |||||
String newline = null; | |||||
String line = lineTokenizer.getToken(in); | |||||
while (line != null) { | |||||
if (line.length() == 0) { | |||||
// this should not happen, because the lines are | |||||
// returned with the end of line delimiter | |||||
out.newLine(); | |||||
} else { | |||||
newline = filters.replaceTokens(line); | |||||
out.write(newline); | |||||
} | |||||
line = lineTokenizer.getToken(in); | |||||
} | |||||
} finally { | |||||
FileUtils.close(out); | |||||
FileUtils.close(in); | |||||
} | |||||
} else if (filterChainsAvailable | |||||
|| (inputEncoding != null | |||||
&& !inputEncoding.equals(outputEncoding)) | |||||
|| (inputEncoding == null && outputEncoding != null)) { | |||||
BufferedReader in = null; | |||||
BufferedWriter out = null; | |||||
try { | |||||
InputStreamReader isr = null; | |||||
if (inputEncoding == null) { | |||||
isr = new InputStreamReader(source.getInputStream()); | |||||
} else { | |||||
isr = new InputStreamReader(source.getInputStream(), | |||||
inputEncoding); | |||||
} | |||||
in = new BufferedReader(isr); | |||||
OutputStreamWriter osw = null; | |||||
if (outputEncoding == null) { | |||||
osw = new OutputStreamWriter(dest.getOutputStream()); | |||||
} else { | |||||
osw = new OutputStreamWriter(dest.getOutputStream(), | |||||
outputEncoding); | |||||
} | |||||
out = new BufferedWriter(osw); | |||||
if (filterChainsAvailable) { | |||||
ChainReaderHelper crh = new ChainReaderHelper(); | |||||
crh.setBufferSize(FileUtils.BUF_SIZE); | |||||
crh.setPrimaryReader(in); | |||||
crh.setFilterChains(filterChains); | |||||
crh.setProject(project); | |||||
Reader rdr = crh.getAssembledReader(); | |||||
in = new BufferedReader(rdr); | |||||
} | |||||
char[] buffer = new char[FileUtils.BUF_SIZE]; | |||||
while (true) { | |||||
int nRead = in.read(buffer, 0, buffer.length); | |||||
if (nRead == -1) { | |||||
break; | |||||
} | |||||
out.write(buffer, 0, nRead); | |||||
} | |||||
} finally { | |||||
FileUtils.close(out); | |||||
FileUtils.close(in); | |||||
} | |||||
} else { | |||||
InputStream in = null; | |||||
OutputStream out = null; | |||||
try { | |||||
in = source.getInputStream(); | |||||
out = dest.getOutputStream(); | |||||
byte[] buffer = new byte[FileUtils.BUF_SIZE]; | |||||
int count = 0; | |||||
do { | |||||
out.write(buffer, 0, count); | |||||
count = in.read(buffer, 0, buffer.length); | |||||
} while (count != -1); | |||||
} finally { | |||||
FileUtils.close(out); | |||||
FileUtils.close(in); | |||||
} | |||||
} | |||||
if (preserveLastModified && dest instanceof Touchable) { | |||||
setLastModified((Touchable) dest, source.getLastModified()); | |||||
} | |||||
} | |||||
/** | |||||
* Set the last modified time of an object implementing | |||||
* org.apache.tools.ant.types.resources.Touchable . | |||||
* | |||||
* @param t the Touchable whose modified time is to be set. | |||||
* @param time the time to which the last modified time is to be set. | |||||
* if this is -1, the current time is used. | |||||
* @since Ant 1.7 | |||||
*/ | |||||
public static void setLastModified(Touchable t, long time) { | |||||
t.touch((time < 0) ? System.currentTimeMillis() : time); | |||||
} | |||||
/** | |||||
* Compares the contents of two Resources. | |||||
* | |||||
* @param r1 the Resource whose content is to be compared. | |||||
* @param r2 the other Resource whose content is to be compared. | |||||
* @param text true if the content is to be treated as text and | |||||
* differences in kind of line break are to be ignored. | |||||
* | |||||
* @return true if the content of the Resources is the same. | |||||
* | |||||
* @throws IOException if the Resources cannot be read. | |||||
* @since Ant 1.7 | |||||
*/ | |||||
public static boolean contentEquals(Resource r1, Resource r2, boolean text) throws IOException { | |||||
if (r1.isExists() != r2.isExists()) { | |||||
return false; | |||||
} | |||||
if (!r1.isExists()) { | |||||
// two not existing files are equal | |||||
return true; | |||||
} | |||||
// should the following two be switched? If r1 and r2 refer to the same file, | |||||
// isn't their content equal regardless of whether that file is a directory? | |||||
if (r1.isDirectory() || r2.isDirectory()) { | |||||
// don't want to compare directory contents for now | |||||
return false; | |||||
} | |||||
if (r1.equals(r2)) { | |||||
return true; | |||||
} | |||||
if (!text && r1.getSize() != r2.getSize()) { | |||||
return false; | |||||
} | |||||
return compareContent(r1, r2, text) == 0; | |||||
} | |||||
/** | |||||
* Compare the content of two Resources. A nonexistent Resource's | |||||
* content is "less than" that of an existing Resource; a directory-type | |||||
* Resource's content is "less than" that of a file-type Resource. | |||||
* @param r1 the Resource whose content is to be compared. | |||||
* @param r2 the other Resource whose content is to be compared. | |||||
* @param text true if the content is to be treated as text and | |||||
* differences in kind of line break are to be ignored. | |||||
* @return a negative integer, zero, or a positive integer as the first | |||||
* argument is less than, equal to, or greater than the second. | |||||
* @throws IOException if the Resources cannot be read. | |||||
* @since Ant 1.7 | |||||
*/ | |||||
public static int compareContent(Resource r1, Resource r2, boolean text) throws IOException { | |||||
if (r1.equals(r2)) { | |||||
return 0; | |||||
} | |||||
boolean e1 = r1.isExists(); | |||||
boolean e2 = r2.isExists(); | |||||
if (!(e1 || e2)) { | |||||
return 0; | |||||
} | |||||
if (e1 != e2) { | |||||
return e1 ? 1 : -1; | |||||
} | |||||
boolean d1 = r1.isDirectory(); | |||||
boolean d2 = r2.isDirectory(); | |||||
if (d1 && d2) { | |||||
return 0; | |||||
} | |||||
if (d1 || d2) { | |||||
return d1 ? -1 : 1; | |||||
} | |||||
return text ? textCompare(r1, r2) : binaryCompare(r1, r2); | |||||
} | |||||
/** | |||||
* Binary compares the contents of two Resources. | |||||
* <p> | |||||
* simple but sub-optimal comparision algorithm. written for working | |||||
* rather than fast. Better would be a block read into buffers followed | |||||
* by long comparisions apart from the final 1-7 bytes. | |||||
* </p> | |||||
* | |||||
* @param r1 the Resource whose content is to be compared. | |||||
* @param r2 the other Resource whose content is to be compared. | |||||
* @return a negative integer, zero, or a positive integer as the first | |||||
* argument is less than, equal to, or greater than the second. | |||||
* @throws IOException if the Resources cannot be read. | |||||
* @since Ant 1.7 | |||||
*/ | |||||
private static int binaryCompare(Resource r1, Resource r2) throws IOException { | |||||
InputStream in1 = null; | |||||
InputStream in2 = null; | |||||
try { | |||||
in1 = new BufferedInputStream(r1.getInputStream()); | |||||
in2 = new BufferedInputStream(r2.getInputStream()); | |||||
for (int b1 = in1.read(); b1 != -1; b1 = in1.read()) { | |||||
int b2 = in2.read(); | |||||
if (b1 != b2) { | |||||
return b1 > b2 ? 1 : -1; | |||||
} | |||||
} | |||||
return in2.read() == -1 ? 0 : -1; | |||||
} finally { | |||||
FileUtils.close(in1); | |||||
FileUtils.close(in2); | |||||
} | |||||
} | |||||
/** | |||||
* Text compares the contents of two Resources. | |||||
* Ignores different kinds of line endings. | |||||
* @param r1 the Resource whose content is to be compared. | |||||
* @param r2 the other Resource whose content is to be compared. | |||||
* @return a negative integer, zero, or a positive integer as the first | |||||
* argument is less than, equal to, or greater than the second. | |||||
* @throws IOException if the Resources cannot be read. | |||||
* @since Ant 1.7 | |||||
*/ | |||||
private static int textCompare(Resource r1, Resource r2) throws IOException { | |||||
BufferedReader in1 = null; | |||||
BufferedReader in2 = null; | |||||
try { | |||||
in1 = new BufferedReader(new InputStreamReader(r1.getInputStream())); | |||||
in2 = new BufferedReader(new InputStreamReader(r2.getInputStream())); | |||||
String expected = in1.readLine(); | |||||
while (expected != null) { | |||||
String actual = in2.readLine(); | |||||
if (!expected.equals(actual)) { | |||||
return expected.compareTo(actual); | |||||
} | |||||
expected = in1.readLine(); | |||||
} | |||||
return in2.readLine() == null ? 0 : -1; | |||||
} finally { | |||||
FileUtils.close(in1); | |||||
FileUtils.close(in2); | |||||
} | |||||
} | |||||
/** | |||||
* Log which Resources (if any) have been modified in the future. | |||||
* @param logTo the ProjectComponent to do the logging. | |||||
* @param rc the collection of Resources to check. | |||||
* @param long the timestamp granularity to use. | |||||
* @since Ant 1.7 | |||||
*/ | |||||
private static void logFuture(ProjectComponent logTo, | private static void logFuture(ProjectComponent logTo, | ||||
ResourceCollection rc, long granularity) { | ResourceCollection rc, long granularity) { | ||||
long now = System.currentTimeMillis() + granularity; | long now = System.currentTimeMillis() + granularity; | ||||
@@ -34,6 +34,7 @@ import org.apache.tools.ant.types.resources.StringResource; | |||||
import org.apache.tools.ant.types.resources.PropertyResource; | import org.apache.tools.ant.types.resources.PropertyResource; | ||||
import org.apache.tools.ant.types.resources.ImmutableResourceException; | import org.apache.tools.ant.types.resources.ImmutableResourceException; | ||||
import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
import org.apache.tools.ant.util.ResourceUtils; | |||||
public class ResourceOutputTest extends BuildFileTest { | public class ResourceOutputTest extends BuildFileTest { | ||||
@@ -147,7 +148,7 @@ public class ResourceOutputTest extends BuildFileTest { | |||||
} | } | ||||
private void testoutput(Resource dest) throws IOException { | private void testoutput(Resource dest) throws IOException { | ||||
FILE_UTILS.copyResource(new StringResource("foo"), dest, null); | |||||
ResourceUtils.copyResource(new StringResource("foo"), dest, null); | |||||
} | } | ||||
} | } |