Return-Path: Delivered-To: apmail-jakarta-ant-dev-archive@apache.org Received: (qmail 97549 invoked from network); 25 Mar 2002 16:43:00 -0000 Received: from unknown (HELO nagoya.betaversion.org) (192.18.49.131) by daedalus.apache.org with SMTP; 25 Mar 2002 16:43:00 -0000 Received: (qmail 9494 invoked by uid 97); 25 Mar 2002 16:42:44 -0000 Delivered-To: qmlist-jakarta-archive-ant-dev@jakarta.apache.org Received: (qmail 9425 invoked by uid 97); 25 Mar 2002 16:42:43 -0000 Mailing-List: contact ant-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Ant Developers List" Reply-To: "Ant Developers List" Delivered-To: mailing list ant-dev@jakarta.apache.org Received: (qmail 9395 invoked from network); 25 Mar 2002 16:42:43 -0000 Message-ID: <1B42761E4CBED5119FF10002A587DD9132BFE1@NEBULA> From: Nigel Magnay To: 'Ant Developers List' Subject: RE: ? [Bug 7320] New: - Suggestion: new attribute in replace bu ilt-in-task Date: Mon, 25 Mar 2002 16:44:31 -0000 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2653.19) Content-Type: text/plain; charset="iso-8859-1" X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N That's nearly there; taking the example There's a couple of problems 1) I have to specify each name/value pair that I want to replace that isn't in a property file - in this example, date. So If I need to add one to a template file, I have to potentially adjust umpteen build.xml files to reflect this (I have a 'template' set of build.xml files - it's nice if most projects don't need to customise them too heavily) 2) I have to specify each .properties file - again, this can be a great number of them. Would be nicer if I just imported them with and the filter used anything that it could see. It's just makes life easier... If I could replace it with it'd be great > -----Original Message----- > From: Erik Hatcher [mailto:jakarta-ant@ehatchersolutions.com] > Sent: 25 March 2002 16:33 > To: Ant Developers List > Subject: Re: ? [Bug 7320] New: - Suggestion: new attribute in replace > built-in-task > > > What's wrong with the filtersfile option of of the > datatype? > > http://jakarta.apache.org/ant/manual/CoreTypes/filterset.html > ----- Original Message ----- > From: "Nigel Magnay" > To: "'Ant Developers List'" > Sent: Monday, March 25, 2002 11:22 AM > Subject: ? [Bug 7320] New: - Suggestion: new attribute in replace > built-in-task > > > > > > This is interesting - I have a very similar requirement, but I'm not > > sure this is the best way of doing it. > > > > I have a number of 'template' files that I use when building a > > 'distribution' > > for my product. These contain tags that I wish to have replaced. For > > example, > > I have something like > > > > sysConfig.ini > > serverLdapHost=@config.ldapHost@ > > > > The key things are that > > 1) I don't want my build file knowing about which properties I may > > want to replace. Just 'everything that is a valid property'. Thus > > my programmers can know all they need to do is update the template > > and, say, a properties file for that target. > > 2) I want to build up some properties in my build file as a part > > of other properties. > > 3) I tend to do this 'en-masse'. I have a 'templates' directory > > that I specialise all in one go. > > > > The way I have done it is to duplicate the 'Copy' task and called > > it 'TranslateCopy'. Strikes me that a better way to do this would > > be to have another filter definition, that you could tell it the > > 'start' and 'end' tokens to treat as property delimiters in files, > > and it would transform any properties it sees. > > > > > > Is there another way? If not, I could write the patch.. > > > > > > Nigel > > > > > > > -----Original Message----- > > > From: bugzilla@apache.org [mailto:bugzilla@apache.org] > > > Sent: 21 March 2002 13:33 > > > To: ant-dev@jakarta.apache.org > > > Subject: DO NOT REPLY [Bug 7320] New: - Suggestion: new > attribute in > > > replace built-in-task > > > > > > > > > DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG > > > RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT > > > . > > > ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND > > > INSERTED IN THE BUG DATABASE. > > > > > > http://nagoya.apache.org/bugzilla/show_bug.cgi?id=7320 > > > > > > Suggestion: new attribute in replace built-in-task > > > > > > Summary: Suggestion: new attribute in replace > built-in-task > > > Product: Ant > > > Version: 1.4.1 > > > Platform: Other > > > OS/Version: Other > > > Status: NEW > > > Severity: Enhancement > > > Priority: Other > > > Component: Core tasks > > > AssignedTo: ant-dev@jakarta.apache.org > > > ReportedBy: Wolfgang.Jakel@lutzwolf.de > > > > > > > > > The ant 'replace' built-in-task supports multiple > > > , but I see > > > no way to define the tokens outside the build.xml. Especially > > > I have the task > > > to read a property file with each key interpreted as token > > > and replace the key > > > with his value in a number of files. > > > It is convenient to indroduce a new attribute > > > 'replaceFilterFile' reading a > > > valid property file and create for each key-value pair > internally a > > > . > > > I modified the file > > > /src/main/org/apache/tools/ant/taskdefs/Replace.java. > > > See the code below and look at the variable replaceFilterFile > > > to see what I > > > did. I think this feature is of some general interest. > > > Anyway, the modification works fine for my purposes. > > > > > > > > > /* > > > * The Apache Software License, Version 1.1 > > > * > > > * Copyright (c) 1999 The Apache Software Foundation. All rights > > > * reserved. > > > * > > > * Redistribution and use in source and binary forms, > with or without > > > * modification, are permitted provided that the > following conditions > > > * are met: > > > * > > > * 1. Redistributions of source code must retain the > above copyright > > > * notice, this list of conditions and the following > disclaimer. > > > * > > > * 2. Redistributions in binary form must reproduce the above > > > copyright > > > * notice, this list of conditions and the following > disclaimer in > > > * the documentation and/or other materials provided with the > > > * distribution. > > > * > > > * 3. The end-user documentation included with the > redistribution, if > > > * any, must include the following acknowlegement: > > > * "This product includes software developed by the > > > * Apache Software Foundation (http://www.apache.org/)." > > > * Alternately, this acknowlegement may appear in the > > > software itself, > > > * if and wherever such third-party acknowlegements > > > normally appear. > > > * > > > * 4. The names "The Jakarta Project", "Ant", and "Apache Software > > > * Foundation" must not be used to endorse or promote > > > products derived > > > * from this software without prior written permission. > > > For written > > > * permission, please contact apache@apache.org. > > > * > > > * 5. Products derived from this software may not be > called "Apache" > > > * nor may "Apache" appear in their names without prior written > > > * permission of the Apache Group. > > > * > > > * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED > OR IMPLIED > > > * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED > WARRANTIES > > > * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > > > * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE > FOUNDATION OR > > > * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, > INCIDENTAL, > > > * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES > (INCLUDING, BUT NOT > > > * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR > SERVICES; LOSS OF > > > * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > HOWEVER CAUSED AND > > > * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, > STRICT LIABILITY, > > > * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN > ANY WAY OUT > > > * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE > POSSIBILITY OF > > > * SUCH DAMAGE. > > > * > > > > ==================================================================== > > > * > > > * This software consists of voluntary contributions made by many > > > * individuals on behalf of the Apache Software > Foundation. For more > > > * information on the Apache Software Foundation, please see > > > * . > > > */ > > > > > > package org.apache.tools.ant.taskdefs; > > > > > > import org.apache.tools.ant.*; > > > import org.apache.tools.ant.taskdefs.*; > > > import java.io.*; > > > import java.util.*; > > > > > > /** > > > * Replaces all occurrences of one or more string tokens > with given > > > * values in the indicated files. Each value can be > either a string > > > * or the value of a property available in a designated > property file. > > > * > > > * @author Stefano Mazzocchi > > href="mailto:stefano@apache.org">stefano@apache.org > > > * @author Erik > Langenbach > > > */ > > > public class Replace extends MatchingTask { > > > > > > private File src = null; > > > private NestedString token = null; > > > private NestedString value = new NestedString(); > > > > > > private File propertyFile = null; > > > private File replaceFilterFile = null; > > > private Properties properties = null; > > > private Vector replacefilters = new Vector(); > > > > > > private File dir = null; > > > > > > private int fileCount; > > > private int replaceCount; > > > private boolean summary = false; > > > > > > //Inner class > > > public class NestedString { > > > > > > private StringBuffer buf = new StringBuffer(); > > > > > > public void addText(String val) { > > > buf.append(val); > > > } > > > > > > public String getText() { > > > return buf.toString(); > > > } > > > } > > > > > > //Inner class > > > public class Replacefilter > > > { > > > private String token; > > > private String value; > > > private String property; > > > > > > public void validate() throws BuildException { > > > //Validate mandatory attributes > > > if (token == null) { > > > String message = "token is a mandatory > > > attribute " + "of > > > replacefilter."; > > > throw new BuildException(message); > > > } > > > > > > if ("".equals(token)) { > > > String message ="The token attribute must not > > > be an empty > > > string."; > > > throw new BuildException(message); > > > } > > > > > > //value and property are mutually exclusive attributes > > > if ((value != null) && (property != null)) { > > > String message = "Either value or property " > > > + "can be > > > specified, but a replacefilter " + "element cannot have both."; > > > throw new BuildException(message); > > > } > > > > > > if ((property != null)) { > > > //the property attribute must have access to > > > a property file > > > if (propertyFile == null) { > > > String message = "The replacefilter's > > > property attribute " > > > + "can only be used with the replacetask's " + "propertyFile > > > attribute."; > > > throw new BuildException(message); > > > } > > > > > > //Make sure property exists in property file > > > if (properties == null || > > > properties.getProperty(property) > == null) { > > > String message = "property \"" + property > > > + "\" was not > > > found in " + propertyFile.getPath(); > > > throw new BuildException(message); > > > } > > > } > > > } > > > > > > public String getReplaceValue() > > > { > > > if (property != null) { > > > return (String)properties.getProperty(property); > > > } > > > else if (value != null) { > > > return value; > > > } > > > else if (Replace.this.value != null) { > > > return Replace.this.value.getText(); > > > } > > > else { > > > //Default is empty string > > > return new String(""); > > > } > > > } > > > > > > public void setToken(String token) { > > > this.token = token; > > > } > > > > > > public String getToken() { > > > return token; > > > } > > > > > > public void setValue(String value) { > > > this.value = value; > > > } > > > > > > public String getValue() { > > > return value; > > > } > > > > > > public void setProperty(String property) { > > > this.property = property; > > > } > > > > > > public String getProperty() { > > > return property; > > > } > > > } > > > > > > /** > > > * Do the execution. > > > */ > > > public void execute() throws BuildException { > > > > > > if (replaceFilterFile != null) { > > > Properties properties = > getProperties(replaceFilterFile); > > > Enumeration enum = properties.keys(); > > > while(enum.hasMoreElements()){ > > > String token = enum.nextElement().toString(); > > > Replacefilter replaceFilter = > createReplacefilter(); > > > replaceFilter.setToken(token); > > > > replaceFilter.setValue(properties.getProperty(token)); > > > } > > > } > > > > > > validateAttributes(); > > > > > > if (propertyFile != null) { > > > properties = getProperties(propertyFile); > > > } > > > > > > > > > validateReplacefilters(); > > > fileCount = 0; > > > replaceCount = 0; > > > > > > if (src != null) { > > > processFile(src); > > > } > > > > > > if (dir != null) { > > > DirectoryScanner ds = super.getDirectoryScanner(dir); > > > String[] srcs = ds.getIncludedFiles(); > > > > > > for(int i=0; i > > File file = new File(dir,srcs[i]); > > > processFile(file); > > > } > > > } > > > > > > if (summary) { > > > log("Replaced " + replaceCount + " occurrences in > > > " + fileCount + " > > > files.", Project.MSG_INFO); > > > } > > > } > > > > > > /** > > > * Validate attributes provided for this task in .xml > build file. > > > * > > > * @exception BuildException if any supplied attribute is > > > invalid or any > > > * mandatory attribute is missing > > > */ > > > public void validateAttributes() throws BuildException { > > > if (src == null && dir == null) { > > > String message = "Either the file or the dir > > > attribute " + "must be > > > specified"; > > > throw new BuildException(message, location); > > > } > > > if (propertyFile != null && !propertyFile.exists()) { > > > String message = "Property file " + > > > propertyFile.getPath() + " does > > > not exist."; > > > throw new BuildException(message, location); > > > } > > > if (token == null && replacefilters.size() == 0) { > > > String message = "Either token or a nested > replacefilter " > > > + "must be specified"; > > > throw new BuildException(message, location); > > > } > > > if (token != null && "".equals(token.getText())) { > > > String message ="The token attribute must not be > > > an empty string."; > > > throw new BuildException(message, location); > > > } > > > } > > > > > > /** > > > * Validate nested elements. > > > * > > > * @exception BuildException if any supplied attribute is > > > invalid or any > > > * mandatory attribute is missing > > > */ > > > public void validateReplacefilters() > > > throws BuildException { > > > for (int i = 0; i < replacefilters.size(); i++) { > > > Replacefilter element = (Replacefilter) > > > replacefilters.elementAt(i); > > > element.validate(); > > > } > > > } > > > > > > public Properties getProperties(File propertyFile) throws > > > BuildException { > > > Properties properties = new Properties(); > > > > > > try { > > > properties.load(new FileInputStream(propertyFile)); > > > } > > > catch (FileNotFoundException e) { > > > String message = "Property file (" + > > > propertyFile.getPath() + ") > > > not found."; > > > throw new BuildException(message); > > > } > > > catch (IOException e) { > > > String message = "Property file (" + > > > propertyFile.getPath() + ") > > > cannot be loaded."; > > > throw new BuildException(message); > > > } > > > > > > return properties; > > > } > > > > > > /** > > > * Perform the replacement on the given file. > > > * > > > * The replacement is performed on a temporary file which then > > > * replaces the original file. > > > * > > > * @param src the source file > > > */ > > > private void processFile(File src) throws BuildException { > > > if (!src.exists()) { > > > throw new BuildException("Replace: source file " > > > + src.getPath() > > > + " doesn't exist", location); > > > } > > > > > > File temp = new File(src.getPath() + ".temp"); > > > > > > if (temp.exists()) { > > > throw new BuildException("Replace: temporary file > > > " + temp.getPath > > > () + " already exists", location); > > > } > > > > > > try { > > > BufferedReader br = new BufferedReader(new > > > FileReader(src)); > > > BufferedWriter bw = new BufferedWriter(new > > > FileWriter(temp)); > > > > > > // read the entire file into a StringBuffer > > > // size of work buffer may be bigger than needed > > > // when multibyte characters exist in the > source file > > > // but then again, it might be smaller than > needed on > > > // platforms like Windows where length > can't be trusted > > > int fileLengthInBytes = (int)(src.length()); > > > StringBuffer tmpBuf = new > StringBuffer(fileLengthInBytes); > > > int readChar = 0; > > > int totread = 0; > > > while (true) { > > > readChar = br.read(); > > > if (readChar < 0) { break; } > > > tmpBuf.append((char)readChar); > > > totread++; > > > } > > > > > > // create a String so we can use indexOf > > > String buf = tmpBuf.toString(); > > > > > > //Preserve original string (buf) so we can > > > compare the result > > > String newString = new String(buf); > > > > > > if (token != null) > > > { > > > // line separators in values and tokens are "\n" > > > // in order to compare with the file > > > contents, replace them > > > // as needed > > > String linesep = > System.getProperty("line.separator"); > > > String val = stringReplace(value.getText(), > > > "\n", linesep); > > > String tok = stringReplace(token.getText(), > > > "\n", linesep); > > > > > > // for each found token, replace with value > > > log("Replacing in " + src.getPath() + ": " + > > > token.getText() > > > + " --> " + value.getText(), Project.MSG_VERBOSE); > > > newString = stringReplace(newString, tok, val); > > > } > > > > > > if (replacefilters.size() > 0) { > > > newString = processReplacefilters(newString, > > > src.getPath()); > > > } > > > > > > boolean changes = !newString.equals(buf); > > > if (changes) { > > > bw.write(newString,0,newString.length()); > > > bw.flush(); > > > } > > > > > > // cleanup > > > bw.close(); > > > br.close(); > > > > > > // If there were changes, move the new one to > the old one; > > > // otherwise, delete the new one > > > if (changes) { > > > ++fileCount; > > > src.delete(); > > > temp.renameTo(src); > > > } else { > > > temp.delete(); > > > } > > > } catch (IOException ioe) { > > > ioe.printStackTrace(); > > > throw new BuildException(ioe, location); > > > } > > > } > > > > > > private String processReplacefilters(String buffer, > > > String filename) { > > > String newString = new String(buffer); > > > > > > for (int i = 0; i < replacefilters.size(); i++) { > > > Replacefilter filter = (Replacefilter) > > > replacefilters.elementAt(i); > > > > > > //for each found token, replace with value > > > log("Replacing in " + filename + ": " + > > > filter.getToken() + " --> " > > > + filter.getReplaceValue(), Project.MSG_VERBOSE); > > > newString = stringReplace(newString, > filter.getToken(), > > > filter.getReplaceValue()); > > > } > > > > > > return newString; > > > } > > > > > > > > > /** > > > * Set the source file. > > > */ > > > public void setFile(File file) { > > > this.src = file; > > > } > > > > > > /** > > > * Request a summary > > > * > > > * @param summary true if you would like a summary logged > > > of the replace > > > operation > > > */ > > > public void setSummary(boolean summary) { > > > this.summary = summary; > > > } > > > > > > > > > /** > > > * Set the source files path when using matching tasks. > > > */ > > > public void setDir(File dir) { > > > this.dir = dir; > > > } > > > > > > /** > > > * Set the string token to replace. > > > */ > > > public void setToken(String token) { > > > createReplaceToken().addText(token); > > > } > > > > > > /** > > > * Set the string value to use as token replacement. > > > */ > > > public void setValue(String value) { > > > createReplaceValue().addText(value); > > > } > > > > > > /** > > > * Nested element. > > > */ > > > public NestedString createReplaceToken() { > > > if (token == null) { > > > token = new NestedString(); > > > } > > > return token; > > > } > > > > > > /** > > > * Nested element. > > > */ > > > public NestedString createReplaceValue() { > > > return value; > > > } > > > > > > /** > > > * Sets a file to be searched for property values. > > > */ > > > public void setPropertyFile(File filename) { > > > propertyFile = filename; > > > } > > > > > > /** > > > * Sets a file to be searched for property values. > > > */ > > > public void setReplaceFilterFile(File filename) { > > > replaceFilterFile = filename; > > > } > > > > > > > > > > > > /** > > > * Add nested element. > > > */ > > > public Replacefilter createReplacefilter() { > > > Replacefilter filter = new Replacefilter(); > > > replacefilters.addElement(filter); > > > return filter; > > > } > > > > > > /** > > > * Replace occurrences of str1 in string str with str2 > > > */ > > > private String stringReplace(String str, String str1, > > > String str2) { > > > StringBuffer ret = new StringBuffer(); > > > int start = 0; > > > int found = str.indexOf(str1); > > > while (found >= 0) { > > > // write everything up to the found str1 > > > if (found > start) { > > > ret.append(str.substring(start, found)); > > > } > > > > > > // write the replacement str2 > > > if (str2 != null) { > > > ret.append(str2); > > > } > > > > > > // search again > > > start = found + str1.length(); > > > found = str.indexOf(str1,start); > > > ++replaceCount; > > > } > > > > > > // write the remaining characters > > > if (str.length() > start) { > > > ret.append(str.substring(start, str.length())); > > > } > > > > > > return ret.toString(); > > > } > > > > > > } > > > > > > -- > > > To unsubscribe, e-mail: > > > > > > For additional commands, e-mail: > > > > > > > > > > -- > > To unsubscribe, e-mail: > > > For additional commands, e-mail: > > > > > > > > -- > To unsubscribe, e-mail: > > For additional commands, e-mail: > > -- To unsubscribe, e-mail: For additional commands, e-mail: