git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@513901 13f79535-47bb-0310-9956-ffa450edef68master
@@ -83,6 +83,8 @@ Other changes: | |||
* Add a <last> resource collection, corresponding to <first>. | |||
* Add new <truncate> task. | |||
Changes from Ant 1.6.5 to Ant 1.7.0 | |||
=================================== | |||
@@ -0,0 +1,106 @@ | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Language" content="en-us"> | |||
<link rel="stylesheet" type="text/css" href="../stylesheets/style.css"> | |||
<title>Truncate Task</title> | |||
</head> | |||
<body> | |||
<h2><a name="touch">Truncate</a></h2> | |||
<h3>Description</h3> | |||
<p>Set the length of one or more files, as the intermittently available | |||
<code>truncate</code> Unix utility/function. In addition to working with | |||
a single file, this Task can also work on | |||
<a href="../CoreTypes/resource.html">resources</a> and resource collections. | |||
<strong>Since Ant 1.7.1</strong>. | |||
</p> | |||
<h3>Parameters</h3> | |||
<table border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
<td valign="top"><b>Attribute</b></td> | |||
<td valign="top"><b>Description</b></td> | |||
<td align="center" valign="top"><b>Required</b></td> | |||
</tr> | |||
<tr> | |||
<td valign="top">file</td> | |||
<td valign="top">The name of the file.</td> | |||
<td valign="top" align="center">Unless a nested resource collection element | |||
has been specified.</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">length</td> | |||
<td valign="top">Specifies the new file length to set. The following | |||
suffixes are supported: | |||
<ul> | |||
<li>K : Kilobytes (1024 bytes)</li> | |||
<li>M : Megabytes (1024 K)</li> | |||
<li>G : Gigabytes (1024 M)</li> | |||
<li>T : Terabytes (1024 G)</li> | |||
<li>P : Petabytes (1024 T)</li> | |||
</ul> | |||
</td> | |||
<td valign="center" align="center" rowspan="2">One of these or neither. | |||
Specifying neither is equivalent to length="0". | |||
</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">adjust</td> | |||
<td valign="top">Specifies the amount (and positive/negative direction) | |||
by which to adjust file lengths.</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">create</td> | |||
<td valign="top">Whether to create nonexistent files.</td> | |||
<td valign="top" align="center">No, default <i>true</i>.</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">mkdirs</td> | |||
<td valign="top">Whether to create nonexistent parent | |||
directories when creating new files.</td> | |||
<td valign="top" align="center">No, default <i>false</i>.</td> | |||
</tr> | |||
</table> | |||
<h3>Parameters specified as nested elements</h3> | |||
<h4>any resource collection</h4> | |||
<p>You can use any number of nested resource collection elements to | |||
define the resources for this task and refer to resources defined | |||
elsewhere. <b>Note:</b> resources passed to this task are expected | |||
to be filesystem-based.</p> | |||
<h3>Examples</h3> | |||
<pre> <truncate file="foo" /></pre> | |||
<p>Sets the length of file <code>foo</code> to zero.</p> | |||
<pre> <truncate file="foo" length="1K" /></pre> | |||
<p>Sets the length of file <code>foo</code> to 1 kilobyte (1024 bytes).</p> | |||
<pre> <truncate file="foo" adjust="1K" /></pre> | |||
<p>Adjusts the length of file <code>foo</code> upward by 1 kilobyte.</p> | |||
<pre> <truncate file="foo" adjust="-1M" /></pre> | |||
<p>Adjusts the length of file <code>foo</code> downward by 1 megabyte.</p> | |||
</body> | |||
</html> |
@@ -113,6 +113,7 @@ | |||
<a href="CoreTasks/taskdef.html">Taskdef</a><br/> | |||
<a href="CoreTasks/tempfile.html">Tempfile</a><br/> | |||
<a href="CoreTasks/touch.html">Touch</a><br/> | |||
<a href="CoreTasks/truncate.html">Truncate</a><br/> | |||
<a href="CoreTasks/tstamp.html">TStamp</a><br/> | |||
<a href="CoreTasks/typedef.html">Typedef</a><br/> | |||
<a href="CoreTasks/unzip.html">Unjar</a><br/> | |||
@@ -0,0 +1,204 @@ | |||
/* | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* | |||
*/ | |||
package org.apache.tools.ant.taskdefs; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.RandomAccessFile; | |||
import java.util.Iterator; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.types.EnumeratedAttribute; | |||
import org.apache.tools.ant.types.Path; | |||
import org.apache.tools.ant.types.ResourceCollection; | |||
import org.apache.tools.ant.types.resources.FileResource; | |||
import org.apache.tools.ant.util.FileUtils; | |||
import org.apache.tools.ant.util.StringUtils; | |||
/** | |||
* Set the length of one or more files, as the intermittently available | |||
* <code>truncate</code> Unix utility/function. | |||
* @since Ant 1.7.1 | |||
*/ | |||
public class Truncate extends Task { | |||
private static final Long ZERO = new Long(0L); | |||
private static final String NO_CHILD = "No files specified."; | |||
private static final String INVALID_LENGTH = "Cannot truncate to length "; | |||
private static final String READ_WRITE = "rw"; | |||
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | |||
private static final byte[] FILL_BUFFER = new byte[1024]; | |||
private Path path; | |||
private boolean create = true; | |||
private boolean mkdirs = false; | |||
private Long length; | |||
private Long adjust; | |||
/** | |||
* Set a single target File. | |||
* @param f the single File | |||
*/ | |||
public void setFile(File f) { | |||
add(new FileResource(f)); | |||
} | |||
/** | |||
* Add a nested (filesystem-only) ResourceCollection. | |||
* @param rc the ResourceCollection to add. | |||
*/ | |||
public void add(ResourceCollection rc) { | |||
getPath().add(rc); | |||
} | |||
/** | |||
* Set the amount by which files' lengths should be adjusted. | |||
* It is permissible to append K / M / G / T / P. | |||
* @param adjust (positive or negative) adjustment amount. | |||
*/ | |||
public void setAdjust(Long adjust) { | |||
this.adjust = adjust; | |||
} | |||
/** | |||
* Set the length to which files should be set. | |||
* It is permissible to append K / M / G / T / P. | |||
* @param adjust (positive) adjustment amount. | |||
*/ | |||
public void setLength(Long length) { | |||
this.length = length; | |||
if (length != null && length.longValue() < 0) { | |||
throw new BuildException(INVALID_LENGTH + length); | |||
} | |||
} | |||
/** | |||
* Set whether to create nonexistent files. | |||
* @param create boolean, default <code>true</code>. | |||
*/ | |||
public void setCreate(boolean create) { | |||
this.create = create; | |||
} | |||
/** | |||
* Set whether, when creating nonexistent files, nonexistent directories | |||
* should also be created. | |||
* @param mkdirs boolean, default <code>false</code>. | |||
*/ | |||
public void setMkdirs(boolean mkdirs) { | |||
this.mkdirs = mkdirs; | |||
} | |||
/** {@inheritDoc}. */ | |||
public void execute() { | |||
if (length != null && adjust != null) { | |||
throw new BuildException( | |||
"length and adjust are mutually exclusive options"); | |||
} | |||
if (length == null && adjust == null) { | |||
length = ZERO; | |||
} | |||
if (path == null) { | |||
throw new BuildException(NO_CHILD); | |||
} | |||
for (Iterator it = path.iterator(); it.hasNext();) { | |||
File f = ((FileResource) it.next()).getFile(); | |||
if (shouldProcess(f)) { | |||
process(f); | |||
} | |||
} | |||
} | |||
private boolean shouldProcess(File f) { | |||
if (f.isFile()) { | |||
return true; | |||
} | |||
if (!create) { | |||
return false; | |||
} | |||
Exception exception = null; | |||
try { | |||
if (FILE_UTILS.createNewFile(f, mkdirs)) { | |||
return true; | |||
} | |||
} catch (IOException e) { | |||
exception = e; | |||
} | |||
String msg = "Unable to create " + f; | |||
if (exception == null) { | |||
log(msg, Project.MSG_WARN); | |||
return false; | |||
} | |||
throw new BuildException(msg, exception); | |||
} | |||
private void process(File f) { | |||
long len = f.length(); | |||
long newLength = length == null | |||
? len + adjust.longValue() : length.longValue(); | |||
if (len == newLength) { | |||
//nothing to do! | |||
return; | |||
} | |||
RandomAccessFile raf = null; | |||
try { | |||
raf = new RandomAccessFile(f, READ_WRITE); | |||
} catch (Exception e) { | |||
throw new BuildException("Could not open " + f + " for writing", e); | |||
} | |||
try { | |||
if (newLength > len) { | |||
long pos = len; | |||
raf.seek(pos); | |||
while (pos < newLength) { | |||
long writeCount = Math.min(FILL_BUFFER.length, | |||
newLength - pos); | |||
raf.write(FILL_BUFFER, 0, (int) writeCount); | |||
pos += writeCount; | |||
} | |||
} else { | |||
raf.setLength(newLength); | |||
} | |||
} catch (IOException e) { | |||
throw new BuildException("Exception working with " + raf, e); | |||
} finally { | |||
try { | |||
raf.close(); | |||
} catch (IOException e) { | |||
log("Caught " + e + " closing " + raf, Project.MSG_WARN); | |||
} | |||
} | |||
} | |||
private synchronized Path getPath() { | |||
if (path == null) { | |||
path = new Path(getProject()); | |||
} | |||
return path; | |||
} | |||
} |
@@ -71,6 +71,7 @@ taskdef=org.apache.tools.ant.taskdefs.Taskdef | |||
tempfile=org.apache.tools.ant.taskdefs.TempFile | |||
touch=org.apache.tools.ant.taskdefs.Touch | |||
tstamp=org.apache.tools.ant.taskdefs.Tstamp | |||
truncate=org.apache.tools.ant.taskdefs.Truncate | |||
typedef=org.apache.tools.ant.taskdefs.Typedef | |||
unjar=org.apache.tools.ant.taskdefs.Expand | |||
untar=org.apache.tools.ant.taskdefs.Untar | |||
@@ -0,0 +1,128 @@ | |||
<project name="truncate-test" default="default" | |||
xmlns:au="antlib:org.apache.ant.antunit"> | |||
<target name="default"> | |||
<au:antunit> | |||
<file file="${ant.file}" /> | |||
</au:antunit> | |||
</target> | |||
<target name="tearDown"> | |||
<delete file="foo" /> | |||
<delete file="bar" /> | |||
<delete dir="baz" /> | |||
</target> | |||
<target name="test-basic"> | |||
<truncate file="foo" /> | |||
<au:assertTrue> | |||
<length file="foo" length="0" /> | |||
</au:assertTrue> | |||
</target> | |||
<target name="test-explicit"> | |||
<truncate file="foo" length="1034" /> | |||
<au:assertTrue> | |||
<length file="foo" length="1034" /> | |||
</au:assertTrue> | |||
</target> | |||
<target name="test-extend"> | |||
<truncate file="foo" length="5" /> | |||
<au:assertTrue> | |||
<length file="foo" length="5" /> | |||
</au:assertTrue> | |||
<truncate file="foo" adjust="5" /> | |||
<au:assertTrue> | |||
<length file="foo" length="10" /> | |||
</au:assertTrue> | |||
</target> | |||
<target name="test-truncate"> | |||
<truncate file="foo" length="5" /> | |||
<au:assertTrue> | |||
<length file="foo" length="5" /> | |||
</au:assertTrue> | |||
<truncate file="foo" adjust="-5" /> | |||
<au:assertTrue> | |||
<length file="foo" length="0" /> | |||
</au:assertTrue> | |||
</target> | |||
<target name="test-bigger"> | |||
<truncate file="foo" length="1K" /> | |||
<au:assertTrue> | |||
<and> | |||
<length file="foo" length="1K" /> | |||
<length file="foo" length="1024" /> | |||
</and> | |||
</au:assertTrue> | |||
</target> | |||
<target name="truncate-bigger"> | |||
<truncate file="foo" length="3K" /> | |||
<au:assertTrue> | |||
<length file="foo" length="3K" /> | |||
</au:assertTrue> | |||
<truncate file="foo" adjust="-2K" /> | |||
<au:assertTrue> | |||
<length file="foo" length="1K" /> | |||
</au:assertTrue> | |||
</target> | |||
<target name="test-no-create"> | |||
<au:assertFileDoesntExist file="foo" /> | |||
<truncate file="foo" create="false" length="0" /> | |||
<au:assertFileDoesntExist file="foo" /> | |||
</target> | |||
<target name="test-mkdirs"> | |||
<au:assertFileDoesntExist file="baz" /> | |||
<truncate file="baz/foo" mkdirs="true" length="0" /> | |||
<au:assertTrue> | |||
<length file="baz/foo" length="0" /> | |||
</au:assertTrue> | |||
</target> | |||
<target name="test-rc"> | |||
<truncate length="10"> | |||
<resources> | |||
<file file="foo" /> | |||
<file file="bar" /> | |||
</resources> | |||
</truncate> | |||
<au:assertTrue> | |||
<and> | |||
<length file="foo" length="10" /> | |||
<length file="bar" length="10" /> | |||
</and> | |||
</au:assertTrue> | |||
</target> | |||
<target name="test-bad-resource"> | |||
<au:expectfailure> | |||
<truncate length="1P"> | |||
<string value="blah" /> | |||
</truncate> | |||
</au:expectfailure> | |||
</target> | |||
<target name="test-invalid-attrs"> | |||
<au:expectfailure> | |||
<truncate file="foo" length="0" adjust="0" /> | |||
</au:expectfailure> | |||
</target> | |||
<target name="test-bad-length"> | |||
<au:expectfailure> | |||
<truncate file="foo" length="-1P" /> | |||
</au:expectfailure> | |||
</target> | |||
<target name="test-no-files"> | |||
<au:expectfailure> | |||
<truncate length="0" /> | |||
</au:expectfailure> | |||
</target> | |||
</project> |