All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tools.ant.taskdefs.optional.ReplaceRegExp Maven / Gradle / Ivy

There is a newer version: 1.0-rc5
Show newest version
/*
 * Copyright  2001-2004 The Apache Software Foundation
 *
 *  Licensed 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.optional;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.Vector;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.RegularExpression;
import org.apache.tools.ant.types.Substitution;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.regexp.Regexp;

/**
 * Performs regular expression string replacements in a text
 * file.  The input file(s) must be able to be properly processed by
 * a Reader instance.  That is, they must be text only, no binary.
 *
 * The syntax of the regular expression depends on the implementation that
 * you choose to use. The system property ant.regexp.regexpimpl
 * will be the classname of the implementation that will be used (the default
 * is org.apache.tools.ant.util.regexp.JakartaOroRegexp and
 * requires the Jakarta Oro Package).
 *
 * 
 * For jdk  <= 1.3, there are two available implementations:
 *   org.apache.tools.ant.util.regexp.JakartaOroRegexp (the default)
 *        Requires  the jakarta-oro package
 *
 *   org.apache.tools.ant.util.regexp.JakartaRegexpRegexp
 *        Requires the jakarta-regexp package
 *
 * For jdk >= 1.4 an additional implementation is available:
 *   org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp
 *        Requires the jdk 1.4 built in regular expression package.
 *
 * Usage:
 *
 *   Call Syntax:
 *
 *     <replaceregexp file="file"
 *                    match="pattern"
 *                    replace="pattern"
 *                    flags="options"?
 *                    byline="true|false"? >
 *       regexp?
 *       substitution?
 *       fileset*
 *     </replaceregexp>
 *
 *    NOTE: You must have either the file attribute specified, or at least one fileset subelement
 *    to operation on.  You may not have the file attribute specified if you nest fileset elements
 *    inside this task.  Also, you cannot specify both match and a regular expression subelement at
 *    the same time, nor can you specify the replace attribute and the substitution subelement at
 *    the same time.
 *
 *   Attributes:
 *
 *     file    --> A single file to operation on (mutually exclusive
 *                    with the fileset subelements)
 *     match   --> The Regular expression to match
 *     replace --> The Expression replacement string
 *     flags   --> The options to give to the replacement
 *                 g = Substitute all occurrences. default is to replace only the first one
 *                 i = Case insensitive match
 *
 *     byline  --> Should this file be processed a single line at a time (default is false)
 *                 "true" indicates to perform replacement on a line by line basis
 *                 "false" indicates to perform replacement on the whole file at once.
 *
 *  Example:
 *
 *     The following call could be used to replace an old property name in a ".properties"
 *     file with a new name.  In the replace attribute, you can refer to any part of the
 *     match expression in parenthesis using backslash followed by a number like '\1'.
 *
 *     <replaceregexp file="test.properties"
 *                    match="MyProperty=(.*)"
 *                    replace="NewProperty=\1"
 *                    byline="true" />
 *
 * 
* */ public class ReplaceRegExp extends Task { private File file; private String flags; private boolean byline; private Vector filesets;// Keep jdk 1.1 compliant so others can use this private RegularExpression regex; private Substitution subs; private FileUtils fileUtils = FileUtils.newFileUtils(); /** * Encoding to assume for the files */ private String encoding = null; /** Default Constructor */ public ReplaceRegExp() { super(); this.file = null; this.filesets = new Vector(); this.flags = ""; this.byline = false; this.regex = null; this.subs = null; } /** * file for which the regular expression should be replaced; * required unless a nested fileset is supplied. * @param file The file for which the reg exp should be replaced. */ public void setFile(File file) { this.file = file; } /** * the regular expression pattern to match in the file(s); * required if no nested <regexp> is used * @param match the match attribute. */ public void setMatch(String match) { if (regex != null) { throw new BuildException("Only one regular expression is allowed"); } regex = new RegularExpression(); regex.setPattern(match); } /** * The substitution pattern to place in the file(s) in place * of the regular expression. * Required if no nested <substitution> is used * @param replace the replace attribute */ public void setReplace(String replace) { if (subs != null) { throw new BuildException("Only one substitution expression is " + "allowed"); } subs = new Substitution(); subs.setExpression(replace); } /** * The flags to use when matching the regular expression. For more * information, consult the Perl5 syntax. *
    *
  • g : Global replacement. Replace all occurrences found *
  • i : Case Insensitive. Do not consider case in the match *
  • m : Multiline. Treat the string as multiple lines of input, * using "^" and "$" as the start or end of any line, respectively, * rather than start or end of string. *
  • s : Singleline. Treat the string as a single line of input, using * "." to match any character, including a newline, which normally, * it would not match. *
* @param flags the flags attribute */ public void setFlags(String flags) { this.flags = flags; } /** * Process the file(s) one line at a time, executing the replacement * on one line at a time. This is useful if you * want to only replace the first occurrence of a regular expression on * each line, which is not easy to do when processing the file as a whole. * Defaults to false. * @param byline the byline attribute as a string * @deprecated - use setByLine(boolean) */ public void setByLine(String byline) { Boolean res = Boolean.valueOf(byline); if (res == null) { res = Boolean.FALSE; } this.byline = res.booleanValue(); } /** * Process the file(s) one line at a time, executing the replacement * on one line at a time. This is useful if you * want to only replace the first occurrence of a regular expression on * each line, which is not easy to do when processing the file as a whole. * Defaults to false. * @param byline the byline attribute */ public void setByLine(boolean byline) { this.byline = byline; } /** * Specifies the encoding Ant expects the files to be in - * defaults to the platforms default encoding. * @param encoding the encoding attribute * * @since Ant 1.6 */ public void setEncoding(String encoding) { this.encoding = encoding; } /** * list files to apply the replacement to * @param set the fileset element */ public void addFileset(FileSet set) { filesets.addElement(set); } /** * A regular expression. * You can use this element to refer to a previously * defined regular expression datatype instance * @return the regular expression object to be configured as an element */ public RegularExpression createRegexp() { if (regex != null) { throw new BuildException("Only one regular expression is allowed."); } regex = new RegularExpression(); return regex; } /** * A substitution pattern. You can use this element to refer to a previously * defined substitution pattern datatype instance. * @return the substitution pattern object to be configured as an element */ public Substitution createSubstitution() { if (subs != null) { throw new BuildException("Only one substitution expression is " + "allowed"); } subs = new Substitution(); return subs; } /** * Invoke a regular expression (r) on a string (input) using * substitutions (s) for a matching regex. * * @param r a regular expression * @param s a Substitution * @param input the string to do the replacement on * @param options The options for the regular expression * @return the replacement result */ protected String doReplace(RegularExpression r, Substitution s, String input, int options) { String res = input; Regexp regexp = r.getRegexp(getProject()); if (regexp.matches(input, options)) { log("Found match; substituting", Project.MSG_DEBUG); res = regexp.substitute(input, s.getExpression(getProject()), options); } return res; } /** * Perform the replacement on a file * * @param f the file to perform the relacement on * @param options the regular expressions options * @exception IOException if an error occurs */ protected void doReplace(File f, int options) throws IOException { File temp = fileUtils.createTempFile("replace", ".txt", null); temp.deleteOnExit(); Reader r = null; Writer w = null; try { if (encoding == null) { r = new FileReader(f); w = new FileWriter(temp); } else { r = new InputStreamReader(new FileInputStream(f), encoding); w = new OutputStreamWriter(new FileOutputStream(temp), encoding); } BufferedReader br = new BufferedReader(r); BufferedWriter bw = new BufferedWriter(w); PrintWriter pw = new PrintWriter(bw); boolean changes = false; log("Replacing pattern '" + regex.getPattern(getProject()) + "' with '" + subs.getExpression(getProject()) + "' in '" + f.getPath() + "'" + (byline ? " by line" : "") + (flags.length() > 0 ? " with flags: '" + flags + "'" : "") + ".", Project.MSG_VERBOSE); if (byline) { StringBuffer linebuf = new StringBuffer(); String line = null; String res = null; int c; boolean hasCR = false; do { c = br.read(); if (c == '\r') { if (hasCR) { // second CR -> EOL + possibly empty line line = linebuf.toString(); res = doReplace(regex, subs, line, options); if (!res.equals(line)) { changes = true; } pw.print(res); pw.print('\r'); linebuf = new StringBuffer(); // hasCR is still true (for the second one) } else { // first CR in this line hasCR = true; } } else if (c == '\n') { // LF -> EOL line = linebuf.toString(); res = doReplace(regex, subs, line, options); if (!res.equals(line)) { changes = true; } pw.print(res); if (hasCR) { pw.print('\r'); hasCR = false; } pw.print('\n'); linebuf = new StringBuffer(); } else { // any other char if ((hasCR) || (c < 0)) { // Mac-style linebreak or EOF (or both) line = linebuf.toString(); res = doReplace(regex, subs, line, options); if (!res.equals(line)) { changes = true; } pw.print(res); if (hasCR) { pw.print('\r'); hasCR = false; } linebuf = new StringBuffer(); } if (c >= 0) { linebuf.append((char) c); } } } while (c >= 0); pw.flush(); } else { String buf = fileUtils.readFully(br); if (buf == null) { buf = ""; } String res = doReplace(regex, subs, buf, options); if (!res.equals(buf)) { changes = true; } pw.print(res); pw.flush(); } r.close(); r = null; w.close(); w = null; if (changes) { log("File has changed; saving the updated file", Project.MSG_VERBOSE); try { fileUtils.rename(temp, f); temp = null; } catch (IOException e) { throw new BuildException("Couldn't rename temporary file " + temp, getLocation()); } } else { log("No change made", Project.MSG_DEBUG); } } finally { try { if (r != null) { r.close(); } } catch (Exception e) { // ignore any secondary exceptions } try { if (w != null) { w.close(); } } catch (Exception e) { // ignore any secondary exceptions } if (temp != null) { temp.delete(); } } } /** * Execute the task * * @throws BuildException is there is a problem in the task execution. */ public void execute() throws BuildException { if (regex == null) { throw new BuildException("No expression to match."); } if (subs == null) { throw new BuildException("Nothing to replace expression with."); } if (file != null && filesets.size() > 0) { throw new BuildException("You cannot supply the 'file' attribute " + "and filesets at the same time."); } int options = 0; if (flags.indexOf('g') != -1) { options |= Regexp.REPLACE_ALL; } if (flags.indexOf('i') != -1) { options |= Regexp.MATCH_CASE_INSENSITIVE; } if (flags.indexOf('m') != -1) { options |= Regexp.MATCH_MULTILINE; } if (flags.indexOf('s') != -1) { options |= Regexp.MATCH_SINGLELINE; } if (file != null && file.exists()) { try { doReplace(file, options); } catch (IOException e) { log("An error occurred processing file: '" + file.getAbsolutePath() + "': " + e.toString(), Project.MSG_ERR); } } else if (file != null) { log("The following file is missing: '" + file.getAbsolutePath() + "'", Project.MSG_ERR); } int sz = filesets.size(); for (int i = 0; i < sz; i++) { FileSet fs = (FileSet) (filesets.elementAt(i)); DirectoryScanner ds = fs.getDirectoryScanner(getProject()); String[] files = ds.getIncludedFiles(); for (int j = 0; j < files.length; j++) { File f = new File(fs.getDir(getProject()), files[j]); if (f.exists()) { try { doReplace(f, options); } catch (Exception e) { log("An error occurred processing file: '" + f.getAbsolutePath() + "': " + e.toString(), Project.MSG_ERR); } } else { log("The following file is missing: '" + f.getAbsolutePath() + "'", Project.MSG_ERR); } } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy