Return-Path: Mailing-List: contact dev-help@ant.apache.org; run by ezmlm Delivered-To: mailing list dev@ant.apache.org Received: (qmail 72742 invoked from network); 16 Apr 2003 06:10:48 -0000 Received: from web11503.mail.yahoo.com (216.136.172.35) by daedalus.apache.org with SMTP; 16 Apr 2003 06:10:48 -0000 Message-ID: <20030416061059.77903.qmail@web11503.mail.yahoo.com> Received: from [203.97.2.243] by web11503.mail.yahoo.com via HTTP; Wed, 16 Apr 2003 18:10:59 NZST Date: Wed, 16 Apr 2003 18:10:59 +1200 (NZST) From: =?iso-8859-1?q?Andre=20Cesta?= Reply-To: aacesta@yahoo.com Subject: Replace task not suitable for my needs, wrote Ant extension to address problems. To: dev@ant.apache.org MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N The Replace task was not suitable for my needs, so I ended up writing my own "replace" Ant extension. Would the more active developers on the list please consider my case? ------------------------------------ Use case 1: Performing token replacements ala those performed via Unix m4 utility. Man page for m4 utility: http://www.unidata.ucar.edu/cgi-bin/man-cgi?m4+1 Use case 1 details: Given source file called java.properties.j4,; Given list of tokens and their values; Process java.properties.j4, generating on the same directory java.properties with the token substitutions. Given directory, scan the directory; Given list of tokens and their values; Scan the directory, perfoming the operations above on every individual .j4 file. Benefits: the original is not lost (it is lost on the replace task). the original is kept on version control. the end result requires less ant lines (copy file, filter, etc). Now some particularities of my extension: I don't allow specification of a token file, instead I consider the list of Ant properties to be my set of tokens. This can be VERY convenient, but I would like to improve the task to be able to receive a list of tokens as well. I have forced the .j4 extension for these files. I believe this should be the recommended extension, but not the only one possible. I am pasting my extension class code in line on this email, but first some usage examples on a build.xml file: ----------------8<----------------------- ----------------8<----------------------- Now the code for the extension, contained in one single class. Notice that it allows for conditional processing of .j4 file parts based on the value of Ant properties as well (extra feature that you might want to remove). Here is an example of a .j4 conditional and token: token=@ji.build.project@ token=@ji.build.project@ token=@ji.build.project@ ifelse(@ji.build.env@, dev, ` dev only. ',`dnl') ifelse(@ji.build.env@, prd, ` production environment. ',`dnl') Now the code for the extension: ----------------8<----------------------- package ji.ant.base; import java.io.*; import java.util.*; import org.apache.tools.ant.*; import org.apache.tools.ant.taskdefs.*; /** * This class performs token replacements on files automatically. * It is an Ant Task. * * You can escape back-quotes and quotes within conditionals by having two in a row * e.g. to escape `hello' put ``hello'' * * @author Andre Cesta */ public class JIJ4 extends MatchingTask { /** Directory where the file filtering operations will take place. */ private File dir; /** Flat that tells whether we are generating filtered files or not. */ private boolean replace = false; /** Flat that tells if we are cleaning filtered files or not. */ private boolean clean = false; /** Initial extension of files being filtered. */ private String initialExtension = ""; /** . */ private String finalExtension = ""; /** Empty constructor. */ public JIJ4() { super(); } /** * Sets replace flag that will cause it to replace the final/target file. */ public void setReplace(String pReplaceStr) { replace = Project.toBoolean(pReplaceStr); } /** * Sets the clean attribute */ public void setClean(String cleanString) { clean = Project.toBoolean(cleanString); if ( clean ) { // Force directory scan to report all files replace = true; } } /** Set initialExtension. **/ public void setInitialExtension(String pInitialExt) { initialExtension = pInitialExt; } /** Set finalExtension. **/ public void setFinalExtension(String pFinalExt) { finalExtension = pFinalExt; } /** * Set the source dir to find the files to be renamed. */ public void setDir(String pSrcDir) { dir = project.resolveFile(pSrcDir); } /** * Executes the task, i.e. does the actual compiler call */ public void execute() throws BuildException { // first off, make sure that we've got a from and to extension if (initialExtension == null || finalExtension == null || dir == null) throw new BuildException("dir, initialExtension and finalExtension attributes not provided!"); // scan source and dest dirs to build up rename list DirectoryScanner vDs = getDirectoryScanner(dir); String[] vFiles = vDs.getIncludedFiles(); Hashtable vFilterList = scanDir(dir, vFiles); Enumeration e = vFilterList.keys(); File vInitialFile = null; File vFinalFile = null; while (e.hasMoreElements()) { vInitialFile = (File)e.nextElement(); vFinalFile = (File)vFilterList.get(vInitialFile); if ( clean ) { System.out.println("J4 file deletion:" + vFinalFile); vFinalFile.delete(); } else { System.out.println("J4 file generation:" + vFinalFile); try { this.copyFile(vInitialFile, vFinalFile ); } catch ( java.io.IOException io ) { throw new BuildException( io.getMessage() ); } } } } /** Just copies a file applying the filtering. */ public void copyFile(File pInitialFile, File pDestFile ) throws IOException { if ( pDestFile.lastModified() < pInitialFile.lastModified()) { log("Generating: " + pInitialFile.getAbsolutePath() + " > " + pDestFile.getAbsolutePath(), Project.MSG_VERBOSE); // ensure that parent dir of dest file exists! // not using getParentFile method to stay 1.1 compat File vParent = new File(pDestFile.getParent()); if (!vParent.exists()) vParent.mkdirs(); BufferedReader in = new BufferedReader(new FileReader(pInitialFile)); BufferedWriter out = new BufferedWriter(new FileWriter(pDestFile)); boolean inConditional = false; boolean inElseConditional = false; boolean includeConditional = false; String conditional = ""; int length; String newline = null; String line = in.readLine(); while (line != null) { if (line.length() == 0) { out.newLine(); } else { // create a Map containing both filters and properties java.util.Map tokens = (java.util.Map)(project.getFilters().clone()); tokens.putAll(project.getProperties()); newline = replace( line, tokens ); if ( inConditional ) { if ( newline.indexOf( "`dnl'" ) != -1 ) { // 'else' conditional is empty inConditional = false; if ( includeConditional ) { out.write( conditional ); includeConditional = false; } conditional = ""; } else if ( ( newline.indexOf( "`" ) != -1 ) && ( newline.indexOf( "``" ) == -1 ) ) { // 'else' conditional does something inConditional = false; inElseConditional = true; if ( includeConditional ) out.write( conditional ); conditional = ""; } else { conditional += newline + "\n"; } } else if ( inElseConditional ) { if ( newline.startsWith( "'" ) && !newline.startsWith( "''" ) ) { inElseConditional = false; if ( !includeConditional ) { out.write( conditional ); out.newLine(); } includeConditional= false; conditional = ""; } else { conditional += newline + "\n"; } } else if ( newline.indexOf( "ifelse" ) != -1 ) { inConditional = true; String variable = newline.substring( newline.indexOf( "(" ) + 1 , newline.indexOf( "," ) ); String value = newline.substring( newline.indexOf( "," ) + 1 , newline.lastIndexOf( "," ) ); variable = variable.trim(); value = value.trim(); //Logic, ORs: '|' java.util.StringTokenizer valueTokenizer = new java.util.StringTokenizer( value ); while ( valueTokenizer.hasMoreTokens() ) { if ( variable.equals( valueTokenizer.nextToken( "|" ).trim() ) ) { includeConditional = true; } } } else { out.write(newline); out.newLine(); } } line = in.readLine(); } out.close(); in.close(); } } /** Replace tokens in string. */ private String replace(String s, java.util.Map tokens) { int index = s.indexOf(Project.TOKEN_START); if (index > -1) { try { StringBuffer b = new StringBuffer(); int i = 0; String token = null; String value = null; do { token = s.substring(index + Project.TOKEN_START.length(), s.indexOf(Project.TOKEN_END, index + Project.TOKEN_START.length() + 1)); b.append(s.substring(i, index)); if (tokens.containsKey(token)) { value = (String) tokens.get(token); log("Replacing: " + Project.TOKEN_START + token + Project.TOKEN_END + " -> " + value, Project.MSG_VERBOSE); b.append(value); } else { b.append(Project.TOKEN_START); b.append(token); b.append(Project.TOKEN_END); } i = index + Project.TOKEN_START.length() + token.length() + Project.TOKEN_END.length(); } while ((index = s.indexOf(Project.TOKEN_START, i)) > -1); b.append(s.substring(i)); return b.toString(); } catch (StringIndexOutOfBoundsException e) { return s; } } else { return s; } } /** Scans directory for files. */ private Hashtable scanDir(File dir, String[] files) { //System.out.println( "dir = " + dir ); Hashtable list = new Hashtable(); for (int i = 0; i < files.length; i++) { File srcFile = new File(dir, files[i]); String filename = files[i]; // if it's a file that ends in the initialExtension, copy to the rename list if (filename.toLowerCase().endsWith(initialExtension)) { File pDestFile = new File(dir, filename.substring(0, filename.lastIndexOf(initialExtension)) + finalExtension); if (replace || !pDestFile.exists()) { list.put(srcFile, pDestFile); } else { log("Rejecting file: '" + srcFile + "' for rename as replace is false and file exists", Project.MSG_VERBOSE); } } else { log("File '"+ filename + "' doesn't match initialExtension: '" + initialExtension + "'", Project.MSG_VERBOSE); } } return list; } } ===== --------------------------------------------------- Andre Cesta +64 9 4895311 home +64 9 9125644 work +64 21646975 mobile http://geocities.com/aacesta --------------------------------------------------- http://mobile.yahoo.com.au - Yahoo! Mobile - Check & compose your email via SMS on your Telstra or Vodafone mobile.