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 a <last> resource collection, corresponding to <first>. | ||||
| * Add new <truncate> task. | |||||
| Changes from Ant 1.6.5 to Ant 1.7.0 | 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/taskdef.html">Taskdef</a><br/> | ||||
| <a href="CoreTasks/tempfile.html">Tempfile</a><br/> | <a href="CoreTasks/tempfile.html">Tempfile</a><br/> | ||||
| <a href="CoreTasks/touch.html">Touch</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/tstamp.html">TStamp</a><br/> | ||||
| <a href="CoreTasks/typedef.html">Typedef</a><br/> | <a href="CoreTasks/typedef.html">Typedef</a><br/> | ||||
| <a href="CoreTasks/unzip.html">Unjar</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 | tempfile=org.apache.tools.ant.taskdefs.TempFile | ||||
| touch=org.apache.tools.ant.taskdefs.Touch | touch=org.apache.tools.ant.taskdefs.Touch | ||||
| tstamp=org.apache.tools.ant.taskdefs.Tstamp | tstamp=org.apache.tools.ant.taskdefs.Tstamp | ||||
| truncate=org.apache.tools.ant.taskdefs.Truncate | |||||
| typedef=org.apache.tools.ant.taskdefs.Typedef | typedef=org.apache.tools.ant.taskdefs.Typedef | ||||
| unjar=org.apache.tools.ant.taskdefs.Expand | unjar=org.apache.tools.ant.taskdefs.Expand | ||||
| untar=org.apache.tools.ant.taskdefs.Untar | 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> | |||||