git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@942752 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -4,6 +4,15 @@ Changes from Ant 1.8.1 TO current SVN version | |||
| Changes that could break older environments: | |||
| ------------------------------------------- | |||
| * Prior to Ant 1.8.0 the <copy> task would overwrite read-only | |||
| destination files. Starting with 1.8.0 it would only do so if | |||
| under special circumstances. Ant 1.8.2 now consistently won't | |||
| replace a read-only file by default. The same is true for a number | |||
| of other tasks. | |||
| The <copy> task now has a new force attribute that can be used to | |||
| make the task overwrite read-only destinations. | |||
| Bugzilla Report 49261. | |||
| Fixed bugs: | |||
| ----------- | |||
| @@ -89,6 +89,12 @@ operation as <a href="../CoreTypes/filterset.html">filtersets</a>. | |||
| files are newer.</td> | |||
| <td valign="top" align="center">No; defaults to false.</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">force</td> | |||
| <td valign="top">Overwrite read-only destination | |||
| files. <em>since Ant 1.8.2</em></td> | |||
| <td valign="top" align="center">No; defaults to false.</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">filtering</td> | |||
| <td valign="top">Indicates whether token filtering using the <a href="../using.html#filters">global | |||
| @@ -100,6 +100,7 @@ public class Copy extends Task { | |||
| private String inputEncoding = null; | |||
| private String outputEncoding = null; | |||
| private long granularity = 0; | |||
| private boolean force = false; | |||
| /** | |||
| * Copy task constructor. | |||
| @@ -228,6 +229,17 @@ public class Copy extends Task { | |||
| this.forceOverwrite = overwrite; | |||
| } | |||
| /** | |||
| * Whether read-only destinations will be overwritten. | |||
| * | |||
| * <p>Defaults to false</p> | |||
| * | |||
| * @since Ant 1.8.2 | |||
| */ | |||
| public void setForce(boolean f) { | |||
| force = f; | |||
| } | |||
| /** | |||
| * Set whether files copied from directory trees will be "flattened" | |||
| * into a single directory. If there are multiple files with | |||
| @@ -838,10 +850,13 @@ public class Copy extends Task { | |||
| executionFilters | |||
| .addFilterSet((FilterSet) filterEnum.nextElement()); | |||
| } | |||
| fileUtils.copyFile(fromFile, toFile, executionFilters, | |||
| fileUtils.copyFile(new File(fromFile), new File(toFile), | |||
| executionFilters, | |||
| filterChains, forceOverwrite, | |||
| preserveLastModified, inputEncoding, | |||
| outputEncoding, getProject()); | |||
| preserveLastModified, | |||
| /* append: */ false, inputEncoding, | |||
| outputEncoding, getProject(), | |||
| force); | |||
| } catch (IOException ioe) { | |||
| String msg = "Failed to copy " + fromFile + " to " + toFile | |||
| + " due to " + getDueTo(ioe); | |||
| @@ -928,9 +943,11 @@ public class Copy extends Task { | |||
| filterChains, | |||
| forceOverwrite, | |||
| preserveLastModified, | |||
| /* append: */ false, | |||
| inputEncoding, | |||
| outputEncoding, | |||
| getProject()); | |||
| getProject(), | |||
| force); | |||
| } catch (IOException ioe) { | |||
| String msg = "Failed to copy " + fromResource | |||
| + " to " + toFile | |||
| @@ -513,12 +513,55 @@ public class FileUtils { | |||
| */ | |||
| public void copyFile(File sourceFile, File destFile, | |||
| FilterSetCollection filters, Vector filterChains, | |||
| boolean overwrite, boolean preserveLastModified, boolean append, | |||
| boolean overwrite, boolean preserveLastModified, | |||
| boolean append, | |||
| String inputEncoding, String outputEncoding, | |||
| Project project) throws IOException { | |||
| ResourceUtils.copyResource(new FileResource(sourceFile), new FileResource(destFile), | |||
| filters, filterChains, overwrite, preserveLastModified, append, inputEncoding, | |||
| outputEncoding, project); | |||
| copyFile(sourceFile, destFile, filters, filterChains, overwrite, | |||
| preserveLastModified, append, inputEncoding, outputEncoding, | |||
| project, /* force: */ false); | |||
| } | |||
| /** | |||
| * Convenience method to copy a file from a source to a | |||
| * destination specifying if token filtering must be used, if | |||
| * filter chains must be used, if source files may overwrite | |||
| * newer destination files and the last modified time of | |||
| * <code>destFile</code> file should be made equal | |||
| * to the last modified time of <code>sourceFile</code>. | |||
| * | |||
| * @param sourceFile the file to copy from. | |||
| * Must not be <code>null</code>. | |||
| * @param destFile the file 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 file should be | |||
| * overwritten if it already exists. | |||
| * @param preserveLastModified Whether or not the last modified time of | |||
| * the resulting file should be set to that | |||
| * of the source file. | |||
| * @param append whether to append to the destination file. | |||
| * @param inputEncoding the encoding used to read the files. | |||
| * @param outputEncoding the encoding used to write the files. | |||
| * @param project the project instance. | |||
| * @param force whether to overwrite read-only destination files. | |||
| * | |||
| * @throws IOException if the copying fails. | |||
| * | |||
| * @since Ant 1.8.2 | |||
| */ | |||
| public void copyFile(File sourceFile, File destFile, | |||
| FilterSetCollection filters, Vector filterChains, | |||
| boolean overwrite, boolean preserveLastModified, | |||
| boolean append, | |||
| String inputEncoding, String outputEncoding, | |||
| Project project, boolean force) throws IOException { | |||
| ResourceUtils.copyResource(new FileResource(sourceFile), | |||
| new FileResource(destFile), | |||
| filters, filterChains, overwrite, | |||
| preserveLastModified, append, inputEncoding, | |||
| outputEncoding, project, force); | |||
| } | |||
| // CheckStyle:ParameterNumberCheck ON | |||
| @@ -339,10 +339,51 @@ public class ResourceUtils { | |||
| */ | |||
| public static void copyResource(Resource source, Resource dest, | |||
| FilterSetCollection filters, Vector filterChains, | |||
| boolean overwrite, boolean preserveLastModified, boolean append, | |||
| boolean overwrite, boolean preserveLastModified, | |||
| boolean append, | |||
| String inputEncoding, String outputEncoding, | |||
| Project project) | |||
| throws IOException { | |||
| copyResource(source, dest, filters, filterChains, overwrite, | |||
| preserveLastModified, append, inputEncoding, | |||
| outputEncoding, project, /* force: */ false); | |||
| } | |||
| /** | |||
| * 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 append Whether to append to an Appendable Resource. | |||
| * @param inputEncoding the encoding used to read the files. | |||
| * @param outputEncoding the encoding used to write the files. | |||
| * @param project the project instance. | |||
| * @param force whether read-only taret files will be overwritten | |||
| * | |||
| * @throws IOException if the copying fails. | |||
| * | |||
| * @since Ant 1.8.2 | |||
| */ | |||
| public static void copyResource(Resource source, Resource dest, | |||
| FilterSetCollection filters, Vector filterChains, | |||
| boolean overwrite, boolean preserveLastModified, | |||
| boolean append, | |||
| String inputEncoding, String outputEncoding, | |||
| Project project, boolean force) | |||
| throws IOException { | |||
| if (!(overwrite || SelectorUtils.isOutOfDate(source, dest, FileUtils.getFileUtils() | |||
| .getFileTimestampGranularity()))) { | |||
| return; | |||
| @@ -351,6 +392,21 @@ public class ResourceUtils { | |||
| && filters.hasFilters()); | |||
| final boolean filterChainsAvailable = (filterChains != null | |||
| && filterChains.size() > 0); | |||
| File destFile = null; | |||
| if (dest.as(FileProvider.class) != null) { | |||
| destFile = ((FileProvider) dest.as(FileProvider.class)).getFile(); | |||
| } | |||
| if (destFile != null && destFile.isFile() && !destFile.canWrite()) { | |||
| if (!force) { | |||
| throw new IOException("can't write to read-only destination " | |||
| + "file " + destFile); | |||
| } else if (!FILE_UTILS.tryHardToDelete(destFile)) { | |||
| throw new IOException("failed to delete read-only " | |||
| + "destination file " + destFile); | |||
| } | |||
| } | |||
| if (filterSetsAvailable) { | |||
| BufferedReader in = null; | |||
| BufferedWriter out = null; | |||
| @@ -444,11 +500,9 @@ public class ResourceUtils { | |||
| FileUtils.close(in); | |||
| } | |||
| } else if (source.as(FileProvider.class) != null | |||
| && dest.as(FileProvider.class) != null) { | |||
| && destFile != null) { | |||
| File sourceFile = | |||
| ((FileProvider) source.as(FileProvider.class)).getFile(); | |||
| File destFile = | |||
| ((FileProvider) dest.as(FileProvider.class)).getFile(); | |||
| File parent = destFile.getParentFile(); | |||
| if (parent != null && !parent.isDirectory() | |||
| @@ -314,18 +314,69 @@ public class NullByteStreamResource extends Resource { | |||
| <attrib file="${output}/${file}" readonly="true"/> | |||
| </target> | |||
| <target name="XtestCopyOverReadOnlyFile" depends="makeFileUnwritable"> | |||
| <target name="testCopyOverReadOnlyFile" depends="makeFileUnwritable"> | |||
| <sleep seconds="2"/> | |||
| <touch file="${input}/${file}"/> | |||
| <copy toDir="${output}"> | |||
| <au:expectfailure | |||
| expectedMessage="can't write to read-only destination file "> | |||
| <copy toDir="${output}"> | |||
| <fileset dir="${input}"/> | |||
| </copy> | |||
| </au:expectfailure> | |||
| </target> | |||
| <target name="testFilteredCopyOverReadOnlyFile" depends="makeFileUnwritable"> | |||
| <sleep seconds="2"/> | |||
| <touch file="${input}/${file}"/> | |||
| <au:expectfailure | |||
| expectedMessage="can't write to read-only destination file "> | |||
| <copy toDir="${output}"> | |||
| <fileset dir="${input}"/> | |||
| <filterset> | |||
| <filter token="foo" value="bar"/> | |||
| </filterset> | |||
| </copy> | |||
| </au:expectfailure> | |||
| </target> | |||
| <target name="testCopyOverReadOnlyFileWithOverwrite" | |||
| depends="makeFileUnwritable"> | |||
| <touch file="${input}/${file}"/> | |||
| <au:expectfailure | |||
| expectedMessage="can't write to read-only destination file "> | |||
| <copy toDir="${output}" overwrite="true"> | |||
| <fileset dir="${input}"/> | |||
| </copy> | |||
| </au:expectfailure> | |||
| </target> | |||
| <target name="testFilteredCopyOverReadOnlyFileWithOverwrite" | |||
| depends="makeFileUnwritable"> | |||
| <touch file="${input}/${file}"/> | |||
| <au:expectfailure | |||
| expectedMessage="can't write to read-only destination file "> | |||
| <copy toDir="${output}" overwrite="true"> | |||
| <fileset dir="${input}"/> | |||
| <filterset> | |||
| <filter token="foo" value="bar"/> | |||
| </filterset> | |||
| </copy> | |||
| </au:expectfailure> | |||
| </target> | |||
| <target name="testForcedCopyOverReadOnlyFile" depends="makeFileUnwritable"> | |||
| <sleep seconds="2"/> | |||
| <touch file="${input}/${file}"/> | |||
| <copy toDir="${output}" force="true"> | |||
| <fileset dir="${input}"/> | |||
| </copy> | |||
| </target> | |||
| <target name="testFilteredCopyOverReadOnlyFile" depends="makeFileUnwritable"> | |||
| <target name="testForcedFilteredCopyOverReadOnlyFile" | |||
| depends="makeFileUnwritable"> | |||
| <sleep seconds="2"/> | |||
| <touch file="${input}/${file}"/> | |||
| <copy toDir="${output}"> | |||
| <copy toDir="${output}" force="true"> | |||
| <fileset dir="${input}"/> | |||
| <filterset> | |||
| <filter token="foo" value="bar"/> | |||
| @@ -333,18 +384,18 @@ public class NullByteStreamResource extends Resource { | |||
| </copy> | |||
| </target> | |||
| <target name="XtestCopyOverReadOnlyFileWithOverwrite" | |||
| <target name="testForcedCopyOverReadOnlyFileWithOverwrite" | |||
| depends="makeFileUnwritable"> | |||
| <touch file="${input}/${file}"/> | |||
| <copy toDir="${output}" overwrite="true"> | |||
| <copy toDir="${output}" overwrite="true" force="true"> | |||
| <fileset dir="${input}"/> | |||
| </copy> | |||
| </target> | |||
| <target name="testFilteredCopyOverReadOnlyFileWithOverwrite" | |||
| <target name="testForcedFilteredCopyOverReadOnlyFileWithOverwrite" | |||
| depends="makeFileUnwritable"> | |||
| <touch file="${input}/${file}"/> | |||
| <copy toDir="${output}" overwrite="true"> | |||
| <copy toDir="${output}" overwrite="true" force="true"> | |||
| <fileset dir="${input}"/> | |||
| <filterset> | |||
| <filter token="foo" value="bar"/> | |||