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: | |||
------------------------------------------- | |||
* 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. | |||
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> | |||
<td valign="top" align="center">No</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 should take place during | |||
@@ -240,6 +240,15 @@ public class Copy extends Task { | |||
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" | |||
* into a single directory. If there are multiple files with | |||
@@ -856,7 +865,7 @@ public class Copy extends Task { | |||
preserveLastModified, | |||
/* append: */ false, inputEncoding, | |||
outputEncoding, getProject(), | |||
force); | |||
getForce()); | |||
} catch (IOException ioe) { | |||
String msg = "Failed to copy " + fromFile + " to " + toFile | |||
+ " due to " + getDueTo(ioe); | |||
@@ -947,7 +956,7 @@ public class Copy extends Task { | |||
inputEncoding, | |||
outputEncoding, | |||
getProject(), | |||
force); | |||
getForce()); | |||
} catch (IOException ioe) { | |||
String msg = "Failed to copy " + fromResource | |||
+ " to " + toFile | |||
@@ -233,9 +233,10 @@ public class Move extends Copy { | |||
getFilterChains(), | |||
forceOverwrite, | |||
getPreserveLastModified(), | |||
/* append: */ false, | |||
getEncoding(), | |||
getOutputEncoding(), | |||
getProject()); | |||
getProject(), getForce()); | |||
} catch (IOException ioe) { | |||
String msg = "Failed to copy " + fromFile | |||
+ " to " + toFile + " due to " + ioe.getMessage(); | |||
@@ -329,6 +330,18 @@ public class Move extends Copy { | |||
|| getFilterChains().size() > 0) { | |||
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(): | |||
File parent = destFile.getParentFile(); | |||
if (parent != null && !parent.exists()) { | |||
@@ -124,4 +124,111 @@ | |||
value="Y"/> | |||
</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> |