diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java new file mode 100644 index 00000000..d088096a --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java @@ -0,0 +1,533 @@ +/* + * 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.optional; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; + +import org.apache.tools.ant.BuildException; +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.Resource; +import org.apache.tools.ant.types.ResourceCollection; +import org.apache.tools.ant.types.Substitution; +import org.apache.tools.ant.types.resources.FileProvider; +import org.apache.tools.ant.types.resources.Union; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.regexp.Regexp; +import org.apache.tools.ant.util.regexp.RegexpUtil; + +/** + * 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 <code>ant.regexp.regexpimpl</code> + * will be the classname of the implementation that will be used (the default + * is <code>org.apache.tools.ant.util.regexp.JakartaOroRegexp</code> and + * requires the Jakarta Oro Package). + * + * <pre> + * Available implementations: + * + * org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp (default) + * Uses Java's built-in regular expression package + * + * org.apache.tools.ant.util.regexp.JakartaOroRegexp + * Requires the jakarta-oro package + * + * org.apache.tools.ant.util.regexp.JakartaRegexpRegexp + * Requires the jakarta-regexp 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" /> + * + * </pre> + * + */ +public class ReplaceRegExp extends Task { + + private File file; + private String flags; + private boolean byline; + private Union resources; + private RegularExpression regex; + private Substitution subs; + + private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + + private boolean preserveLastModified = false; + + /** + * Encoding to assume for the files + */ + private String encoding = null; + + /** Default Constructor */ + public ReplaceRegExp() { + super(); + this.file = null; + 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. + * <ul> + * <li>g : Global replacement. Replace all occurrences found + * <li>i : Case Insensitive. Do not consider case in the match + * <li>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. + * <li> 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. + *</ul> + * @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 <i>false</i>. + * + * @param byline the byline attribute as a string + * @deprecated since 1.6.x. + * Use setByLine(boolean). + */ + @Deprecated + 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 <i>false</i>. + * + * @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) { + addConfigured(set); + } + + /** + * Support arbitrary file system based resource collections. + * + * @since Ant 1.8.0 + */ + public void addConfigured(ResourceCollection rc) { + if (!rc.isFilesystemOnly()) { + throw new BuildException("only filesystem resources are supported"); + } + if (resources == null) { + resources = new Union(); + } + resources.add(rc); + } + + /** + * 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; + } + + /** + * Whether the file timestamp shall be preserved even if the file + * is modified. + * + * @since Ant 1.8.0 + */ + public void setPreserveLastModified(boolean b) { + preserveLastModified = b; + } + + /** + * 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 replacement on + * @param options the regular expressions options + * @exception IOException if an error occurs + */ + protected void doReplace(File f, int options) + throws IOException { + File temp = FILE_UTILS.createTempFile("replace", ".txt", null, true, true); + try { + boolean changes = false; + + InputStream is = new FileInputStream(f); + try { + Reader r = encoding != null ? new InputStreamReader(is, encoding) : new InputStreamReader(is); + OutputStream os = new FileOutputStream(temp); + try { + Writer w = encoding != null ? new OutputStreamWriter(os, encoding) : new OutputStreamWriter(os); + + 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) { + r = new BufferedReader(r); + w = new BufferedWriter(w); + + StringBuffer linebuf = new StringBuffer(); + int c; + boolean hasCR = false; + + do { + c = r.read(); + + if (c == '\r') { + if (hasCR) { + // second CR -> EOL + possibly empty line + changes |= replaceAndWrite(linebuf.toString(), + w, options); + w.write('\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 + changes |= replaceAndWrite(linebuf.toString(), + w, options); + if (hasCR) { + w.write('\r'); + hasCR = false; + } + w.write('\n'); + + linebuf = new StringBuffer(); + } else { // any other char + if ((hasCR) || (c < 0)) { + // Mac-style linebreak or EOF (or both) + changes |= replaceAndWrite(linebuf.toString(), + w, options); + if (hasCR) { + w.write('\r'); + hasCR = false; + } + + linebuf = new StringBuffer(); + } + + if (c >= 0) { + linebuf.append((char) c); + } + } + } while (c >= 0); + + } else { + changes = multilineReplace(r, w, options); + } + + r.close(); + w.close(); + + } finally { + os.close(); + } + } finally { + is.close(); + } + if (changes) { + log("File has changed; saving the updated file", Project.MSG_VERBOSE); + try { + long origLastModified = f.lastModified(); + FILE_UTILS.rename(temp, f); + if (preserveLastModified) { + FILE_UTILS.setFileLastModified(f, origLastModified); + } + temp = null; + } catch (IOException e) { + throw new BuildException("Couldn't rename temporary file " + + temp, e, getLocation()); + } + } else { + log("No change made", Project.MSG_DEBUG); + } + } finally { + if (temp != null) { + temp.delete(); + } + } + } + + + /** + * Execute the task + * + * @throws BuildException is there is a problem in the task execution. + */ + @Override + 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 && resources != null) { + throw new BuildException("You cannot supply the 'file' attribute " + + "and resource collections at the same " + + "time."); + } + + int options = RegexpUtil.asOptions(flags); + + 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); + } + + if (resources != null) { + for (Resource r : resources) { + FileProvider fp = + r.as(FileProvider.class); + File f = fp.getFile(); + + 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); + } + } + } + } + + private boolean multilineReplace(Reader r, Writer w, int options) + throws IOException { + return replaceAndWrite(FileUtils.safeReadFully(r), w, options); + } + + private boolean replaceAndWrite(String s, Writer w, int options) + throws IOException { + String res = doReplace(regex, subs, s, options); + w.write(res); + return !res.equals(s); + } +} + + |