git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@943056 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -4,13 +4,13 @@ Changes from Ant 1.8.1 TO current SVN version | |||||
| Changes that could break older environments: | 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. | |||||
| * Prior to Ant 1.8.0 the <copy> task and several other tasks 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> and <move> task now have a new force attribute that can | |||||
| be used to make the task overwrite read-only destinations. | |||||
| Bugzilla Report 49261. | Bugzilla Report 49261. | ||||
| Fixed bugs: | Fixed bugs: | ||||
| @@ -85,6 +85,12 @@ there is a directory by the same name in <i>todir</i>, the action will fail. | |||||
| files are newer (default is "true")</td> | files are newer (default is "true")</td> | ||||
| <td valign="top" align="center">No</td> | <td valign="top" align="center">No</td> | ||||
| </tr> | </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> | <tr> | ||||
| <td valign="top">filtering</td> | <td valign="top">filtering</td> | ||||
| <td valign="top">indicates whether token filtering should take place during | <td valign="top">indicates whether token filtering should take place during | ||||
| @@ -240,6 +240,15 @@ public class Copy extends Task { | |||||
| force = f; | force = f; | ||||
| } | } | ||||
| /** | |||||
| * Whether read-only destinations will be overwritten. | |||||
| * | |||||
| * @since Ant 1.8.2 | |||||
| */ | |||||
| public boolean getForce() { | |||||
| return force; | |||||
| } | |||||
| /** | /** | ||||
| * Set whether files copied from directory trees will be "flattened" | * Set whether files copied from directory trees will be "flattened" | ||||
| * into a single directory. If there are multiple files with | * into a single directory. If there are multiple files with | ||||
| @@ -856,7 +865,7 @@ public class Copy extends Task { | |||||
| preserveLastModified, | preserveLastModified, | ||||
| /* append: */ false, inputEncoding, | /* append: */ false, inputEncoding, | ||||
| outputEncoding, getProject(), | outputEncoding, getProject(), | ||||
| force); | |||||
| getForce()); | |||||
| } catch (IOException ioe) { | } catch (IOException ioe) { | ||||
| String msg = "Failed to copy " + fromFile + " to " + toFile | String msg = "Failed to copy " + fromFile + " to " + toFile | ||||
| + " due to " + getDueTo(ioe); | + " due to " + getDueTo(ioe); | ||||
| @@ -947,7 +956,7 @@ public class Copy extends Task { | |||||
| inputEncoding, | inputEncoding, | ||||
| outputEncoding, | outputEncoding, | ||||
| getProject(), | getProject(), | ||||
| force); | |||||
| getForce()); | |||||
| } catch (IOException ioe) { | } catch (IOException ioe) { | ||||
| String msg = "Failed to copy " + fromResource | String msg = "Failed to copy " + fromResource | ||||
| + " to " + toFile | + " to " + toFile | ||||
| @@ -233,9 +233,10 @@ public class Move extends Copy { | |||||
| getFilterChains(), | getFilterChains(), | ||||
| forceOverwrite, | forceOverwrite, | ||||
| getPreserveLastModified(), | getPreserveLastModified(), | ||||
| /* append: */ false, | |||||
| getEncoding(), | getEncoding(), | ||||
| getOutputEncoding(), | getOutputEncoding(), | ||||
| getProject()); | |||||
| getProject(), getForce()); | |||||
| } catch (IOException ioe) { | } catch (IOException ioe) { | ||||
| String msg = "Failed to copy " + fromFile | String msg = "Failed to copy " + fromFile | ||||
| + " to " + toFile + " due to " + ioe.getMessage(); | + " to " + toFile + " due to " + ioe.getMessage(); | ||||
| @@ -329,6 +330,18 @@ public class Move extends Copy { | |||||
| || getFilterChains().size() > 0) { | || getFilterChains().size() > 0) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| // identical logic lives in ResourceUtils.copyResource(): | |||||
| if (destFile.isFile() && !destFile.canWrite()) { | |||||
| if (!getForce()) { | |||||
| throw new IOException("can't replace read-only destination " | |||||
| + "file " + destFile); | |||||
| } else if (!getFileUtils().tryHardToDelete(destFile)) { | |||||
| throw new IOException("failed to delete read-only " | |||||
| + "destination file " + destFile); | |||||
| } | |||||
| } | |||||
| // identical logic lives in FileUtils.rename(): | // identical logic lives in FileUtils.rename(): | ||||
| File parent = destFile.getParentFile(); | File parent = destFile.getParentFile(); | ||||
| if (parent != null && !parent.exists()) { | if (parent != null && !parent.exists()) { | ||||
| @@ -124,4 +124,111 @@ | |||||
| value="Y"/> | value="Y"/> | ||||
| </target> | </target> | ||||
| <!-- stolen from ../types/readwrite-test.xml - create a read-only file --> | |||||
| <property name="file" value="testfile"/> | |||||
| <condition property="unix"> | |||||
| <os family="unix"/> | |||||
| </condition> | |||||
| <target name="createTestdir"> | |||||
| <mkdir dir="${output}"/> | |||||
| <mkdir dir="${input}"/> | |||||
| <touch file="${output}/${file}"/> | |||||
| </target> | |||||
| <target name="makeFileUnwritable" | |||||
| depends="createTestdir,makeFileUnwritable-Unix,makeFileUnwritable-Windows"/> | |||||
| <target name="makeFileUnwritable-Unix" id="unix"> | |||||
| <chmod file="${output}/${file}" perm="444"/> | |||||
| </target> | |||||
| <target name="makeFileUnwritable-Windows" unless="unix"> | |||||
| <attrib file="${output}/${file}" readonly="true"/> | |||||
| </target> | |||||
| <target name="testMoveOverReadOnlyFile" depends="makeFileUnwritable"> | |||||
| <sleep seconds="2"/> | |||||
| <touch file="${input}/${file}"/> | |||||
| <au:expectfailure | |||||
| expectedMessage="can't replace read-only destination file "> | |||||
| <move toDir="${output}"> | |||||
| <fileset dir="${input}"/> | |||||
| </move> | |||||
| </au:expectfailure> | |||||
| </target> | |||||
| <target name="testFilteredMoveOverReadOnlyFile" depends="makeFileUnwritable"> | |||||
| <sleep seconds="2"/> | |||||
| <touch file="${input}/${file}"/> | |||||
| <au:expectfailure | |||||
| expectedMessage="can't write to read-only destination file "> | |||||
| <move toDir="${output}"> | |||||
| <fileset dir="${input}"/> | |||||
| <filterset> | |||||
| <filter token="foo" value="bar"/> | |||||
| </filterset> | |||||
| </move> | |||||
| </au:expectfailure> | |||||
| </target> | |||||
| <target name="testMoveOverReadOnlyFileWithOverwrite" | |||||
| depends="makeFileUnwritable"> | |||||
| <touch file="${input}/${file}"/> | |||||
| <au:expectfailure | |||||
| expectedMessage="can't replace read-only destination file "> | |||||
| <move toDir="${output}" overwrite="true"> | |||||
| <fileset dir="${input}"/> | |||||
| </move> | |||||
| </au:expectfailure> | |||||
| </target> | |||||
| <target name="testFilteredMoveOverReadOnlyFileWithOverwrite" | |||||
| depends="makeFileUnwritable"> | |||||
| <touch file="${input}/${file}"/> | |||||
| <au:expectfailure | |||||
| expectedMessage="can't write to read-only destination file "> | |||||
| <move toDir="${output}" overwrite="true"> | |||||
| <fileset dir="${input}"/> | |||||
| <filterset> | |||||
| <filter token="foo" value="bar"/> | |||||
| </filterset> | |||||
| </move> | |||||
| </au:expectfailure> | |||||
| </target> | |||||
| <target name="testForcedMoveOverReadOnlyFile" depends="makeFileUnwritable"> | |||||
| <sleep seconds="2"/> | |||||
| <touch file="${input}/${file}"/> | |||||
| <move toDir="${output}" force="true"> | |||||
| <fileset dir="${input}"/> | |||||
| </move> | |||||
| </target> | |||||
| <target name="testForcedFilteredMoveOverReadOnlyFile" | |||||
| depends="makeFileUnwritable"> | |||||
| <sleep seconds="2"/> | |||||
| <touch file="${input}/${file}"/> | |||||
| <move toDir="${output}" force="true"> | |||||
| <fileset dir="${input}"/> | |||||
| <filterset> | |||||
| <filter token="foo" value="bar"/> | |||||
| </filterset> | |||||
| </move> | |||||
| </target> | |||||
| <target name="testForcedMoveOverReadOnlyFileWithOverwrite" | |||||
| depends="makeFileUnwritable"> | |||||
| <touch file="${input}/${file}"/> | |||||
| <move toDir="${output}" overwrite="true" force="true"> | |||||
| <fileset dir="${input}"/> | |||||
| </move> | |||||
| </target> | |||||
| <target name="testForcedFilteredMoveOverReadOnlyFileWithOverwrite" | |||||
| depends="makeFileUnwritable"> | |||||
| <touch file="${input}/${file}"/> | |||||
| <move toDir="${output}" overwrite="true" force="true"> | |||||
| <fileset dir="${input}"/> | |||||
| <filterset> | |||||
| <filter token="foo" value="bar"/> | |||||
| </filterset> | |||||
| </move> | |||||
| </target> | |||||
| </project> | </project> | ||||