diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagDiff.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagDiff.java | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagDiff.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagDiff.java new file mode 100644 index 00000000..a90bcc01 --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagDiff.java @@ -0,0 +1,576 @@ +/* + * 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.cvslib; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.AbstractCvsTask; +import org.apache.tools.ant.util.CollectionUtils; +import org.apache.tools.ant.util.DOMElementWriter; +import org.apache.tools.ant.util.DOMUtils; +import org.apache.tools.ant.util.FileUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * Examines the output of cvs rdiff between two tags. + * + * It produces an XML output representing the list of changes. + * <PRE> + * <!-- Root element --> + * <!ELEMENT tagdiff ( entry+ ) > + * <!-- Start tag of the report --> + * <!ATTLIST tagdiff startTag NMTOKEN #IMPLIED > + * <!-- End tag of the report --> + * <!ATTLIST tagdiff endTag NMTOKEN #IMPLIED > + * <!-- Start date of the report --> + * <!ATTLIST tagdiff startDate NMTOKEN #IMPLIED > + * <!-- End date of the report --> + * <!ATTLIST tagdiff endDate NMTOKEN #IMPLIED > + * + * <!-- CVS tag entry --> + * <!ELEMENT entry ( file ) > + * <!-- File added, changed or removed --> + * <!ELEMENT file ( name, revision?, prevrevision? ) > + * <!-- Name of the file --> + * <!ELEMENT name ( #PCDATA ) > + * <!-- Revision number --> + * <!ELEMENT revision ( #PCDATA ) > + * <!-- Previous revision number --> + * <!ELEMENT prevrevision ( #PCDATA ) > + * </PRE> + * + * @since Ant 1.5 + * @ant.task name="cvstagdiff" + */ +public class CvsTagDiff extends AbstractCvsTask { + + /** + * Used to create the temp file for cvs log + */ + private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + + /** stateless helper for writing the XML document */ + private static final DOMElementWriter DOM_WRITER = new DOMElementWriter(); + + /** + * Token to identify the word file in the rdiff log + */ + static final String FILE_STRING = "File "; + /** + * Length of token to identify the word file in the rdiff log + */ + static final int FILE_STRING_LENGTH = FILE_STRING.length(); + /** + * Token to identify the word file in the rdiff log + */ + static final String TO_STRING = " to "; + /** + * Token to identify a new file in the rdiff log + */ + static final String FILE_IS_NEW = " is new;"; + /** + * Token to identify the revision + */ + static final String REVISION = "revision "; + + /** + * Token to identify a modified file in the rdiff log + */ + static final String FILE_HAS_CHANGED = " changed from revision "; + + /** + * Token to identify a removed file in the rdiff log + */ + static final String FILE_WAS_REMOVED = " is removed"; + + /** + * The cvs package/module to analyse + */ + private String mypackage; + + /** + * The earliest tag from which diffs are to be included in the report. + */ + private String mystartTag; + + /** + * The latest tag from which diffs are to be included in the report. + */ + private String myendTag; + + /** + * The earliest date from which diffs are to be included in the report. + */ + private String mystartDate; + + /** + * The latest date from which diffs are to be included in the report. + */ + private String myendDate; + + /** + * The file in which to write the diff report. + */ + private File mydestfile; + + /** + * Used to skip over removed files + */ + private boolean ignoreRemoved = false; + + /** + * temporary list of package names. + */ + private List packageNames = new ArrayList(); + + /** + * temporary list of "File:" + package name + "/" for all packages. + */ + private String[] packageNamePrefixes = null; + + /** + * temporary list of length values for prefixes. + */ + private int[] packageNamePrefixLengths = null; + + /** + * The package/module to analyze. + * @param p the name of the package to analyse + */ + @Override + public void setPackage(String p) { + mypackage = p; + } + + /** + * Set the start tag. + * + * @param s the start tag. + */ + public void setStartTag(String s) { + mystartTag = s; + } + + /** + * Set the start date. + * + * @param s the start date. + */ + public void setStartDate(String s) { + mystartDate = s; + } + + /** + * Set the end tag. + * + * @param s the end tag. + */ + public void setEndTag(String s) { + myendTag = s; + } + + /** + * Set the end date. + * + * @param s the end date. + */ + public void setEndDate(String s) { + myendDate = s; + } + + /** + * Set the output file for the diff. + * + * @param f the output file for the diff. + */ + public void setDestFile(File f) { + mydestfile = f; + } + + /** + * Set the ignore removed indicator. + * + * @param b the ignore removed indicator. + * + * @since Ant 1.8.0 + */ + public void setIgnoreRemoved(boolean b) { + ignoreRemoved = b; + } + + + /** + * Execute task. + * + * @exception BuildException if an error occurs + */ + @Override + public void execute() throws BuildException { + // validate the input parameters + validate(); + + // build the rdiff command + addCommandArgument("rdiff"); + addCommandArgument("-s"); + if (mystartTag != null) { + addCommandArgument("-r"); + addCommandArgument(mystartTag); + } else { + addCommandArgument("-D"); + addCommandArgument(mystartDate); + } + if (myendTag != null) { + addCommandArgument("-r"); + addCommandArgument(myendTag); + } else { + addCommandArgument("-D"); + addCommandArgument(myendDate); + } + + // force command not to be null + setCommand(""); + File tmpFile = null; + try { + handlePackageNames(); + + tmpFile = FILE_UTILS.createTempFile("cvstagdiff", ".log", null, + true, true); + setOutput(tmpFile); + + // run the cvs command + super.execute(); + + // parse the rdiff + CvsTagEntry[] entries = parseRDiff(tmpFile); + + // write the tag diff + writeTagDiff(entries); + + } finally { + packageNamePrefixes = null; + packageNamePrefixLengths = null; + packageNames.clear(); + if (tmpFile != null) { + tmpFile.delete(); + } + } + } + + /** + * Parse the tmpFile and return and array of CvsTagEntry to be + * written in the output. + * + * @param tmpFile the File containing the output of the cvs rdiff command + * @return the entries in the output + * @exception BuildException if an error occurs + */ + private CvsTagEntry[] parseRDiff(File tmpFile) throws BuildException { + // parse the output of the command + BufferedReader reader = null; + + try { + reader = new BufferedReader(new FileReader(tmpFile)); + + // entries are of the form: + //CVS 1.11 + // File module/filename is new; current revision 1.1 + //CVS 1.11.9 + // File module/filename is new; cvstag_2003_11_03_2 revision 1.1 + // or + // File module/filename changed from revision 1.4 to 1.6 + // or + // File module/filename is removed; not included in + // release tag SKINLF_12 + //CVS 1.11.9 + // File testantoine/antoine.bat is removed; TESTANTOINE_1 revision 1.1.1.1 + // + // get rid of 'File module/" + Vector entries = new Vector(); + + String line = reader.readLine(); + + while (null != line) { + line = removePackageName(line, packageNamePrefixes, + packageNamePrefixLengths); + if (line != null) { + // use || in a perl like fashion + boolean processed + = doFileIsNew(entries, line) + || doFileHasChanged(entries, line) + || doFileWasRemoved(entries, line); + } + line = reader.readLine(); + } + + CvsTagEntry[] array = new CvsTagEntry[entries.size()]; + entries.copyInto(array); + + return array; + } catch (IOException e) { + throw new BuildException("Error in parsing", e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + log(e.toString(), Project.MSG_ERR); + } + } + } + } + + private boolean doFileIsNew(Vector entries, String line) { + int index = line.indexOf(FILE_IS_NEW); + if (index == -1) { + return false; + } + // it is a new file + // set the revision but not the prevrevision + String filename = line.substring(0, index); + String rev = null; + int indexrev = line.indexOf(REVISION, index); + if (indexrev != -1) { + rev = line.substring(indexrev + REVISION.length()); + } + CvsTagEntry entry = new CvsTagEntry(filename, rev); + entries.addElement(entry); + log(entry.toString(), Project.MSG_VERBOSE); + return true; + } + + private boolean doFileHasChanged(Vector entries, String line) { + int index = line.indexOf(FILE_HAS_CHANGED); + if (index == -1) { + return false; + } + // it is a modified file + // set the revision and the prevrevision + String filename = line.substring(0, index); + int revSeparator = line.indexOf(" to ", index); + String prevRevision = + line.substring(index + FILE_HAS_CHANGED.length(), + revSeparator); + String revision = line.substring(revSeparator + TO_STRING.length()); + CvsTagEntry entry = new CvsTagEntry(filename, + revision, + prevRevision); + entries.addElement(entry); + log(entry.toString(), Project.MSG_VERBOSE); + return true; + } + + private boolean doFileWasRemoved(Vector entries, String line) { + if (ignoreRemoved) { + return false; + } + int index = line.indexOf(FILE_WAS_REMOVED); + if (index == -1) { + return false; + } + // it is a removed file + String filename = line.substring(0, index); + String rev = null; + int indexrev = line.indexOf(REVISION, index); + if (indexrev != -1) { + rev = line.substring(indexrev + REVISION.length()); + } + CvsTagEntry entry = new CvsTagEntry(filename, null, rev); + entries.addElement(entry); + log(entry.toString(), Project.MSG_VERBOSE); + return true; + } + + /** + * Write the rdiff log. + * + * @param entries a <code>CvsTagEntry[]</code> value + * @exception BuildException if an error occurs + */ + private void writeTagDiff(CvsTagEntry[] entries) throws BuildException { + FileOutputStream output = null; + try { + output = new FileOutputStream(mydestfile); + PrintWriter writer = new PrintWriter( + new OutputStreamWriter(output, "UTF-8")); + writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); + Document doc = DOMUtils.newDocument(); + Element root = doc.createElement("tagdiff"); + if (mystartTag != null) { + root.setAttribute("startTag", mystartTag); + } else { + root.setAttribute("startDate", mystartDate); + } + if (myendTag != null) { + root.setAttribute("endTag", myendTag); + } else { + root.setAttribute("endDate", myendDate); + } + + root.setAttribute("cvsroot", getCvsRoot()); + root.setAttribute("package", + CollectionUtils.flattenToString(packageNames)); + DOM_WRITER.openElement(root, writer, 0, "\t"); + writer.println(); + for (int i = 0, c = entries.length; i < c; i++) { + writeTagEntry(doc, writer, entries[i]); + } + DOM_WRITER.closeElement(root, writer, 0, "\t", true); + writer.flush(); + if (writer.checkError()) { + throw new IOException("Encountered an error writing tagdiff"); + } + writer.close(); + } catch (UnsupportedEncodingException uee) { + log(uee.toString(), Project.MSG_ERR); + } catch (IOException ioe) { + throw new BuildException(ioe.toString(), ioe); + } finally { + if (null != output) { + try { + output.close(); + } catch (IOException ioe) { + log(ioe.toString(), Project.MSG_ERR); + } + } + } + } + + /** + * Write a single entry to the given writer. + * + * @param doc Document used to create elements. + * @param writer a <code>PrintWriter</code> value + * @param entry a <code>CvsTagEntry</code> value + */ + private void writeTagEntry(Document doc, PrintWriter writer, + CvsTagEntry entry) + throws IOException { + Element ent = doc.createElement("entry"); + Element f = DOMUtils.createChildElement(ent, "file"); + DOMUtils.appendCDATAElement(f, "name", entry.getFile()); + if (entry.getRevision() != null) { + DOMUtils.appendTextElement(f, "revision", entry.getRevision()); + } + if (entry.getPreviousRevision() != null) { + DOMUtils.appendTextElement(f, "prevrevision", + entry.getPreviousRevision()); + } + DOM_WRITER.write(ent, writer, 1, "\t"); + } + + /** + * Validate the parameters specified for task. + * + * @exception BuildException if a parameter is not correctly set + */ + private void validate() throws BuildException { + if (null == mypackage && getModules().size() == 0) { + throw new BuildException("Package/module must be set."); + } + + if (null == mydestfile) { + throw new BuildException("Destfile must be set."); + } + + if (null == mystartTag && null == mystartDate) { + throw new BuildException("Start tag or start date must be set."); + } + + if (null != mystartTag && null != mystartDate) { + throw new BuildException("Only one of start tag and start date " + + "must be set."); + } + + if (null == myendTag && null == myendDate) { + throw new BuildException("End tag or end date must be set."); + } + + if (null != myendTag && null != myendDate) { + throw new BuildException("Only one of end tag and end date must " + + "be set."); + } + } + + /** + * collects package names from the package attribute and nested + * module elements. + */ + private void handlePackageNames() { + if (mypackage != null) { + // support multiple packages + StringTokenizer myTokenizer = new StringTokenizer(mypackage); + while (myTokenizer.hasMoreTokens()) { + String pack = myTokenizer.nextToken(); + packageNames.add(pack); + addCommandArgument(pack); + } + } + for (Iterator iter = getModules().iterator(); iter.hasNext();) { + AbstractCvsTask.Module m = (AbstractCvsTask.Module) iter.next(); + packageNames.add(m.getName()); + // will be added to command line in super.execute() + } + packageNamePrefixes = new String[packageNames.size()]; + packageNamePrefixLengths = new int[packageNames.size()]; + for (int i = 0; i < packageNamePrefixes.length; i++) { + packageNamePrefixes[i] = FILE_STRING + packageNames.get(i) + "/"; + packageNamePrefixLengths[i] = packageNamePrefixes[i].length(); + } + } + + + /** + * removes a "File: module/" prefix if present. + * + * @return null if the line was shorter than expected. + */ + private static String removePackageName(String line, + String[] packagePrefixes, + int[] prefixLengths) { + if (line.length() < FILE_STRING_LENGTH) { + return null; + } + boolean matched = false; + for (int i = 0; i < packagePrefixes.length; i++) { + if (line.startsWith(packagePrefixes[i])) { + matched = true; + line = line.substring(prefixLengths[i]); + break; + } + } + if (!matched) { + line = line.substring(FILE_STRING_LENGTH); + } + return line; + } +} |