git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@713173 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -20,20 +20,18 @@ package org.apache.tools.ant.taskdefs; | |||||
| import java.io.File; | import java.io.File; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.io.OutputStream; | |||||
| import java.io.Writer; | |||||
| import java.io.BufferedWriter; | |||||
| import java.io.OutputStreamWriter; | |||||
| import java.io.FileOutputStream; | |||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
| import org.apache.tools.ant.Task; | import org.apache.tools.ant.Task; | ||||
| import org.apache.tools.ant.util.FileUtils; | |||||
| import org.apache.tools.ant.util.ResourceUtils; | |||||
| import org.apache.tools.ant.util.StringUtils; | |||||
| import org.apache.tools.ant.types.LogLevel; | import org.apache.tools.ant.types.LogLevel; | ||||
| import org.apache.tools.ant.types.Resource; | import org.apache.tools.ant.types.Resource; | ||||
| import org.apache.tools.ant.types.resources.FileProvider; | import org.apache.tools.ant.types.resources.FileProvider; | ||||
| import org.apache.tools.ant.types.resources.FileResource; | import org.apache.tools.ant.types.resources.FileResource; | ||||
| import org.apache.tools.ant.types.resources.LogOutputResource; | |||||
| import org.apache.tools.ant.types.resources.StringResource; | |||||
| /** | /** | ||||
| * Writes a message to the Ant logging facilities. | * Writes a message to the Ant logging facilities. | ||||
| @@ -62,23 +60,14 @@ public class Echo extends Task { | |||||
| * @exception BuildException if something goes wrong with the build | * @exception BuildException if something goes wrong with the build | ||||
| */ | */ | ||||
| public void execute() throws BuildException { | public void execute() throws BuildException { | ||||
| if (output == null) { | |||||
| log(message, logLevel); | |||||
| } else { | |||||
| Writer out = null; | |||||
| try { | |||||
| OutputStream os = output instanceof FileProvider ? os = new FileOutputStream( | |||||
| ((FileProvider) output).getFile(), append) : output.getOutputStream(); | |||||
| OutputStreamWriter osw = (encoding == null || "".equals(encoding)) ? new OutputStreamWriter( | |||||
| os) | |||||
| : new OutputStreamWriter(os, encoding); | |||||
| out = new BufferedWriter(osw); | |||||
| out.write(message, 0, message.length()); | |||||
| } catch (IOException ioe) { | |||||
| throw new BuildException(ioe, getLocation()); | |||||
| } finally { | |||||
| FileUtils.close(out); | |||||
| } | |||||
| final String msg = "".equals(message) ? StringUtils.LINE_SEP : message; | |||||
| try { | |||||
| ResourceUtils | |||||
| .copyResource(new StringResource(msg), output == null ? new LogOutputResource( | |||||
| this, logLevel) : output, null, null, false, false, append, null, "" | |||||
| .equals(encoding) ? null : encoding, getProject()); | |||||
| } catch (IOException ioe) { | |||||
| throw new BuildException(ioe, getLocation()); | |||||
| } | } | ||||
| } | } | ||||
| @@ -88,7 +77,7 @@ public class Echo extends Task { | |||||
| * @param msg Sets the value for the message variable. | * @param msg Sets the value for the message variable. | ||||
| */ | */ | ||||
| public void setMessage(String msg) { | public void setMessage(String msg) { | ||||
| this.message = msg; | |||||
| this.message = msg == null ? "" : msg; | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -97,7 +86,6 @@ public class Echo extends Task { | |||||
| * standard output | * standard output | ||||
| */ | */ | ||||
| public void setFile(File file) { | public void setFile(File file) { | ||||
| this.file = file; | |||||
| setOutput(new FileResource(getProject(), file)); | setOutput(new FileResource(getProject(), file)); | ||||
| } | } | ||||
| @@ -0,0 +1,35 @@ | |||||
| /* | |||||
| * 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.types.resources; | |||||
| import java.io.IOException; | |||||
| import java.io.OutputStream; | |||||
| /** | |||||
| * Interface to be implemented by "appendable" resources. | |||||
| * @since Ant 1.8 | |||||
| */ | |||||
| public interface Appendable { | |||||
| /** | |||||
| * Get an appending OutputStream. | |||||
| * @return OutputStream | |||||
| * @throws IOException if anything goes wrong | |||||
| */ | |||||
| OutputStream getAppendOutputStream() throws IOException; | |||||
| } | |||||
| @@ -36,7 +36,7 @@ import org.apache.tools.ant.types.ResourceFactory; | |||||
| * @since Ant 1.7 | * @since Ant 1.7 | ||||
| */ | */ | ||||
| public class FileResource extends Resource implements Touchable, FileProvider, | public class FileResource extends Resource implements Touchable, FileProvider, | ||||
| ResourceFactory { | |||||
| ResourceFactory, Appendable { | |||||
| private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | ||||
| private static final int NULL_FILE | private static final int NULL_FILE | ||||
| @@ -209,11 +209,25 @@ public class FileResource extends Resource implements Touchable, FileProvider, | |||||
| */ | */ | ||||
| public OutputStream getOutputStream() throws IOException { | public OutputStream getOutputStream() throws IOException { | ||||
| if (isReference()) { | if (isReference()) { | ||||
| return ((Resource) getCheckedRef()).getOutputStream(); | |||||
| return ((FileResource) getCheckedRef()).getOutputStream(); | |||||
| } | } | ||||
| return getOutputStream(false); | |||||
| } | |||||
| /** | |||||
| * {@inheritDoc} | |||||
| */ | |||||
| public OutputStream getAppendOutputStream() throws IOException { | |||||
| if (isReference()) { | |||||
| return ((FileResource) getCheckedRef()).getAppendOutputStream(); | |||||
| } | |||||
| return getOutputStream(true); | |||||
| } | |||||
| private OutputStream getOutputStream(boolean append) throws IOException { | |||||
| File f = getNotNullFile(); | File f = getNotNullFile(); | ||||
| if (f.exists()) { | if (f.exists()) { | ||||
| if (f.isFile()) { | |||||
| if (f.isFile() && !append) { | |||||
| f.delete(); | f.delete(); | ||||
| } | } | ||||
| } else { | } else { | ||||
| @@ -222,7 +236,7 @@ public class FileResource extends Resource implements Touchable, FileProvider, | |||||
| p.mkdirs(); | p.mkdirs(); | ||||
| } | } | ||||
| } | } | ||||
| return new FileOutputStream(f); | |||||
| return append ? new FileOutputStream(f.getAbsolutePath(), true) : new FileOutputStream(f); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -0,0 +1,68 @@ | |||||
| /* | |||||
| * 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.types.resources; | |||||
| import java.io.IOException; | |||||
| import java.io.OutputStream; | |||||
| import org.apache.tools.ant.ProjectComponent; | |||||
| import org.apache.tools.ant.taskdefs.LogOutputStream; | |||||
| import org.apache.tools.ant.types.Resource; | |||||
| /** | |||||
| * Output-only Resource that always appends to Ant's log. | |||||
| * @since Ant 1.8 | |||||
| */ | |||||
| public class LogOutputResource extends Resource implements Appendable { | |||||
| private static final String NAME = "[Ant log]"; | |||||
| private LogOutputStream outputStream; | |||||
| /** | |||||
| * Create a new LogOutputResource. | |||||
| * @param managingComponent | |||||
| */ | |||||
| public LogOutputResource(ProjectComponent managingComponent) { | |||||
| super(NAME); | |||||
| outputStream = new LogOutputStream(managingComponent); | |||||
| } | |||||
| /** | |||||
| * Create a new LogOutputResource. | |||||
| * @param managingComponent owning log content | |||||
| * @param level log level | |||||
| */ | |||||
| public LogOutputResource(ProjectComponent managingComponent, int level) { | |||||
| super(NAME); | |||||
| outputStream = new LogOutputStream(managingComponent, level); | |||||
| } | |||||
| /** | |||||
| * {@inheritDoc} | |||||
| */ | |||||
| public OutputStream getAppendOutputStream() throws IOException { | |||||
| return outputStream; | |||||
| } | |||||
| /** | |||||
| * {@inheritDoc} | |||||
| */ | |||||
| public OutputStream getOutputStream() throws IOException { | |||||
| return outputStream; | |||||
| } | |||||
| } | |||||
| @@ -469,15 +469,52 @@ public class FileUtils { | |||||
| * | * | ||||
| * @since Ant 1.6 | * @since Ant 1.6 | ||||
| */ | */ | ||||
| public void copyFile(File sourceFile, File destFile, | |||||
| FilterSetCollection filters, Vector filterChains, | |||||
| boolean overwrite, boolean preserveLastModified, | |||||
| String inputEncoding, String outputEncoding, | |||||
| Project project) throws IOException { | |||||
| copyFile(sourceFile, destFile, filters, filterChains, overwrite, preserveLastModified, | |||||
| false, inputEncoding, outputEncoding, project); | |||||
| } | |||||
| /** | |||||
| * 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. | |||||
| * | |||||
| * | |||||
| * @throws IOException if the copying fails. | |||||
| * | |||||
| * @since Ant 1.8 | |||||
| */ | |||||
| public void copyFile(File sourceFile, File destFile, | public void copyFile(File sourceFile, File destFile, | ||||
| FilterSetCollection filters, Vector filterChains, | FilterSetCollection filters, Vector filterChains, | ||||
| boolean overwrite, boolean preserveLastModified, | |||||
| boolean overwrite, boolean preserveLastModified, boolean append, | |||||
| String inputEncoding, String outputEncoding, | String inputEncoding, String outputEncoding, | ||||
| Project project) throws IOException { | Project project) throws IOException { | ||||
| ResourceUtils.copyResource( | |||||
| new FileResource(sourceFile), new FileResource(destFile), | |||||
| filters, filterChains, overwrite, preserveLastModified, | |||||
| inputEncoding, outputEncoding, project); | |||||
| ResourceUtils.copyResource(new FileResource(sourceFile), new FileResource(destFile), | |||||
| filters, filterChains, overwrite, preserveLastModified, append, inputEncoding, | |||||
| outputEncoding, project); | |||||
| } | } | ||||
| // CheckStyle:ParameterNumberCheck ON | // CheckStyle:ParameterNumberCheck ON | ||||
| @@ -39,6 +39,7 @@ import org.apache.tools.ant.types.TimeComparison; | |||||
| import org.apache.tools.ant.types.ResourceFactory; | import org.apache.tools.ant.types.ResourceFactory; | ||||
| import org.apache.tools.ant.types.ResourceCollection; | import org.apache.tools.ant.types.ResourceCollection; | ||||
| import org.apache.tools.ant.types.FilterSetCollection; | import org.apache.tools.ant.types.FilterSetCollection; | ||||
| import org.apache.tools.ant.types.resources.Appendable; | |||||
| import org.apache.tools.ant.types.resources.FileProvider; | import org.apache.tools.ant.types.resources.FileProvider; | ||||
| import org.apache.tools.ant.types.resources.FileResource; | import org.apache.tools.ant.types.resources.FileResource; | ||||
| import org.apache.tools.ant.types.resources.Union; | import org.apache.tools.ant.types.resources.Union; | ||||
| @@ -265,12 +266,46 @@ public class ResourceUtils { | |||||
| String inputEncoding, String outputEncoding, | String inputEncoding, String outputEncoding, | ||||
| Project project) | Project project) | ||||
| throws IOException { | throws IOException { | ||||
| if (!overwrite) { | |||||
| long slm = source.getLastModified(); | |||||
| if (dest.isExists() && slm != 0 | |||||
| && dest.getLastModified() > slm) { | |||||
| return; | |||||
| } | |||||
| copyResource(source, dest, filters, filterChains, overwrite, preserveLastModified, false, inputEncoding, outputEncoding, project); | |||||
| } | |||||
| // CheckStyle:ParameterNumberCheck OFF - bc | |||||
| /** | |||||
| * 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. | |||||
| * | |||||
| * @throws IOException if the copying fails. | |||||
| * | |||||
| * @since Ant 1.8 | |||||
| */ | |||||
| public static void copyResource(Resource source, Resource dest, | |||||
| FilterSetCollection filters, Vector filterChains, | |||||
| boolean overwrite, boolean preserveLastModified, boolean append, | |||||
| String inputEncoding, String outputEncoding, | |||||
| Project project) | |||||
| throws IOException { | |||||
| if (!(overwrite || SelectorUtils.isOutOfDate(source, dest, FileUtils.getFileUtils() | |||||
| .getFileTimestampGranularity()))) { | |||||
| return; | |||||
| } | } | ||||
| final boolean filterSetsAvailable = (filters != null | final boolean filterSetsAvailable = (filters != null | ||||
| && filters.hasFilters()); | && filters.hasFilters()); | ||||
| @@ -288,12 +323,12 @@ public class ResourceUtils { | |||||
| inputEncoding); | inputEncoding); | ||||
| } | } | ||||
| in = new BufferedReader(isr); | in = new BufferedReader(isr); | ||||
| OutputStreamWriter osw = null; | |||||
| OutputStream os = getOutputStream(dest, append, project); | |||||
| OutputStreamWriter osw; | |||||
| if (outputEncoding == null) { | if (outputEncoding == null) { | ||||
| osw = new OutputStreamWriter(dest.getOutputStream()); | |||||
| osw = new OutputStreamWriter(os); | |||||
| } else { | } else { | ||||
| osw = new OutputStreamWriter(dest.getOutputStream(), | |||||
| outputEncoding); | |||||
| osw = new OutputStreamWriter(os, outputEncoding); | |||||
| } | } | ||||
| out = new BufferedWriter(osw); | out = new BufferedWriter(osw); | ||||
| if (filterChainsAvailable) { | if (filterChainsAvailable) { | ||||
| @@ -339,12 +374,12 @@ public class ResourceUtils { | |||||
| inputEncoding); | inputEncoding); | ||||
| } | } | ||||
| in = new BufferedReader(isr); | in = new BufferedReader(isr); | ||||
| OutputStreamWriter osw = null; | |||||
| OutputStream os = getOutputStream(dest, append, project); | |||||
| OutputStreamWriter osw; | |||||
| if (outputEncoding == null) { | if (outputEncoding == null) { | ||||
| osw = new OutputStreamWriter(dest.getOutputStream()); | |||||
| osw = new OutputStreamWriter(os); | |||||
| } else { | } else { | ||||
| osw = new OutputStreamWriter(dest.getOutputStream(), | |||||
| outputEncoding); | |||||
| osw = new OutputStreamWriter(os, outputEncoding); | |||||
| } | } | ||||
| out = new BufferedWriter(osw); | out = new BufferedWriter(osw); | ||||
| if (filterChainsAvailable) { | if (filterChainsAvailable) { | ||||
| @@ -373,7 +408,7 @@ public class ResourceUtils { | |||||
| OutputStream out = null; | OutputStream out = null; | ||||
| try { | try { | ||||
| in = source.getInputStream(); | in = source.getInputStream(); | ||||
| out = dest.getOutputStream(); | |||||
| out = getOutputStream(dest, append, project); | |||||
| byte[] buffer = new byte[FileUtils.BUF_SIZE]; | byte[] buffer = new byte[FileUtils.BUF_SIZE]; | ||||
| int count = 0; | int count = 0; | ||||
| @@ -587,4 +622,15 @@ public class ResourceUtils { | |||||
| } | } | ||||
| } | } | ||||
| private static OutputStream getOutputStream(Resource resource, boolean append, Project project) | |||||
| throws IOException { | |||||
| if (append) { | |||||
| if (resource instanceof Appendable) { | |||||
| return ((Appendable) resource).getAppendOutputStream(); | |||||
| } | |||||
| project.log("Appendable OutputStream not available for non-appendable resource " | |||||
| + resource + "; using plain OutputStream", Project.MSG_VERBOSE); | |||||
| } | |||||
| return resource.getOutputStream(); | |||||
| } | |||||
| } | } | ||||
| @@ -86,6 +86,9 @@ | |||||
| <target name="testAppend"> | <target name="testAppend"> | ||||
| <echo file="${output}/echo.txt">Simple text</echo> | <echo file="${output}/echo.txt">Simple text</echo> | ||||
| <echo file="${output}/echo.txt" append="true">Appended</echo> | <echo file="${output}/echo.txt" append="true">Appended</echo> | ||||
| <concat> | |||||
| <file file="${output}/echo.txt" /> | |||||
| </concat> | |||||
| <au:assertTrue> | <au:assertTrue> | ||||
| <resourcecount count="1"> | <resourcecount count="1"> | ||||
| <restrict> | <restrict> | ||||