Package net.sourceforge.cruisecontrol.sourcecontrols

Source Code of net.sourceforge.cruisecontrol.sourcecontrols.SnapshotCM$SourcePath

/********************************************************************************
* CruiseControl, a Continuous Integration Toolkit
* Copyright (c) 2004, ThoughtWorks, Inc.
* 651 W Washington Ave. Suite 600
* Chicago, IL 60661 USA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*     + Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*
*     + 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.
*
*     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 REGENTS OR
* 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.
********************************************************************************/
package net.sourceforge.cruisecontrol.sourcecontrols;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;

import net.sourceforge.cruisecontrol.CruiseControlException;
import net.sourceforge.cruisecontrol.Modification;
import net.sourceforge.cruisecontrol.SourceControl;
import net.sourceforge.cruisecontrol.util.StreamPumper;
import net.sourceforge.cruisecontrol.util.ValidationHelper;

import org.apache.log4j.Logger;

/**
*  Retrieves change history from SnapshotCM source control using whist command.
*
@author patrick.conant@hp.com
*/

public class SnapshotCM implements SourceControl {
    /**  Date format required by commands passed to SnapshotCM */
    static final SimpleDateFormat IN_DATE_FORMAT = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss");

    /**  Date format returned in the output of SnapshotCM commands. */
    static final SimpleDateFormat OUT_DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

    private static final MessageFormat EXECUTABLE = new MessageFormat("whist -RA -c{0} \"{1}\"");

    private static final String FILE_HEADER = "=============================================================";

    private static final String REVISION_HEADER = "----------------------------";

    private static final String CHANGE_DELETE = "Delete";

    /** enable logging for this class */
    private static final Logger LOG = Logger.getLogger(SnapshotCM.class);

    private Hashtable props = new Hashtable();

    private String property;

    private String propertyOnDelete;

    /**
     *  List of source path values provided either with sourcePath="...",
     *  sourcePaths="...;...", or nested <sourcePath path="..."> elements.
     */
    private List sourcePaths = new ArrayList();

    /**
     *  From SourceControl interface.
     */
    public void setProperty(String property) {
        this.property = property;
    }

    /**
     *  From SourceControl interface.
     */
    public void setPropertyOnDelete(String propertyOnDelete) {
        this.propertyOnDelete = propertyOnDelete;
    }

    public Hashtable getProperties() {
        return this.props;
    }

    public void setSourcePaths(String sourcePaths) {
        StringTokenizer st = new StringTokenizer(sourcePaths, ";");
        while (st.hasMoreTokens()) {
            setSourcePath(st.nextToken());
        }
    }

    public void setSourcePath(String sourcePath) {
        this.sourcePaths.add(new SourcePath(sourcePath));
    }

    public SourcePath createSourcePath() {
        SourcePath sourcePath = new SourcePath();
        this.sourcePaths.add(sourcePath);
        return sourcePath;
    }

    /**
     *  From SourceControl interface.
     */
    public void validate() throws CruiseControlException {
        ValidationHelper.assertFalse(this.sourcePaths.isEmpty(),
            "'sourcePaths' or 'sourcePath' attribute, or nested sourcepath element(s)"
            + " is a required attribute for SnapshotCM.");
    }

    /**
     *  Returns an {@link java.util.List List} of {@link Modification}
     *  detailing all the changes between now and the last build.
     *
     *  @param  lastBuild the last build time
     *  @param  now time now, or time to check, NOT USED
     *  @return  the list of modifications, an empty (not null) list if no
     *      modifications.
     */
    public List getModifications(Date lastBuild, Date now) {
        // Return value
        List modificationList = new ArrayList();

        //Command parameters
        String[] parameters = new String[2];
        parameters[0] = IN_DATE_FORMAT.format(lastBuild);

        for (Iterator i = this.sourcePaths.iterator(); i.hasNext(); ) {
            parameters[1] = ((SourcePath) i.next()).getPath();

            String command = EXECUTABLE.format(parameters);
            LOG.info("Running command: " + command);
            try {
                Process p = Runtime.getRuntime().exec(command);

                StreamPumper errorPumper = new StreamPumper(p.getErrorStream());
                new Thread(errorPumper).start();

                InputStream input = p.getInputStream();
                modificationList.addAll(parseStream(input));

                p.getInputStream().close();
                p.getOutputStream().close();
                p.getErrorStream().close();
            } catch (Exception e) {
                LOG.error("Error in executing the SnapshotCM command : ", e);
            }
        }

        if (!modificationList.isEmpty() && property != null) {
            props.put(property, "true");
        }

        return modificationList;
    }

    /**
     *  Parses the input stream to construct the modifications list.
     *  Parser splits the returned string into seperate sections
     *  based on the token string FILE_HEADER.  Each file in the list
     *  is passed to the parseEntry method in order to pull out the
     *  user & file names and modification dates.
     *
     *  Package-private to make it available to the unit test.
     *
     *  @param  input the stream to parse
     *  @return  a list of modification elements
     *  @exception  IOException
     */
    List parseStream(InputStream input) throws IOException {
        List modifications = new ArrayList();
        BufferedReader reader = new BufferedReader(new InputStreamReader(input));

        StringBuffer sb = new StringBuffer();

        String line;
        while ((line = reader.readLine()) != null) {
            if (line.equals(FILE_HEADER)) {
                List fileMods = parseEntry(sb.toString());
                modifications.addAll(fileMods);
                sb = new StringBuffer();
            } else {
                sb.append(line);
                sb.append('\n');
            }
        }
        List fileMods = parseEntry(sb.toString());
        modifications.addAll(fileMods);
        return modifications;
    }


    /**
     *  Parses a single line from the reader. Each entry looks like this:
     *
     *
     *  File: /src/Backend/CEUI/tomcat/build.xml
     *  Snapshot: /RSTDevelopment/A.03.50/Develop
     *  Current revision: 46
     *  I/O mode: text
     *  Keyword expansion: keyword and value
     *  Permissions: r--r--r--
     *  ----------------------------
     *  Revision: 46 (current)   Derivation:    45 --> (46)
     *  Date: 2004/01/06 17:00:38 -0700;  Size:    39459 bytes
     *  Author: pacon (Patrick Conant)
     *  Snapshot: /RSTDevelopment/A.03.50/Develop
     *  Used in: /RSTDevelopment/A.03.50/Develop
     *  Change: Content
     *  Removed -D param from SnapshotCM wco and wci commands.
     *  ----------------------------
     *  Revision: 45             Derivation:    44 --> (45) --> 46
     *  Date: 2004/01/06 13:10:31 -0700;  Size:    39468 bytes
     *  Author: pacon (Patrick Conant)
     *  Snapshot: /RSTDevelopment/A.03.50/Develop
     *  Change: Content
     *  Checked in via UltraEdit
     *
     *  There may be one or more revision entries.
     *
     *  @param  entry the entry to parse.
     *  @return an array of modification elements corresponding to the given
     *          entry.
     */
    private List parseEntry(String entry) {
        List modifications = new ArrayList();

        StringTokenizer st = new StringTokenizer(entry, "\n");
        /*
         *  We should get at least 13 lines if there has been a modification.
         */
        if (st.countTokens() < 13) {
            return modifications;
        }

        /*
         *  Read the header, which is the first 6 lines.
         */
        String line = st.nextToken();
        String entryname = line.substring(6);
        String fileName;
        String folderName;
        int sep = entryname.lastIndexOf("/");
        if (sep == -1) {
            sep = entryname.lastIndexOf("\\");
        }
        if (sep > -1) {
            folderName = entryname.substring(0, sep);
            fileName = entryname.substring(sep + 1);
        } else {
            folderName = "";
            fileName = entryname;
        }

        // ignore next 5 lines.
        while (!(st.nextToken()).equals(REVISION_HEADER)) {
            ; //ignore all lines until we get to the next revision.
        }

        /*
         *  Now read in each modification.
         */
        Modification mod = new Modification("snapshotcm");
        mod.createModifiedFile(fileName, folderName);

        while (st.hasMoreTokens()) {
            line = st.nextToken();
            if (line.equals(REVISION_HEADER) || !st.hasMoreTokens()) {
                if (!line.trim().equals("") && !line.equals(REVISION_HEADER)) {
                    //consider this part of the comment.
                    mod.comment += line;
                }

                //Save the modification
                modifications.add(mod);
                mod = new Modification("snapshotcm");
                mod.createModifiedFile(fileName, folderName);
            } else if (line.startsWith("Revision: ")) {  //e.g. Revision: 46 (current)   Derivation:    45 --> (46)
                int nextSpaceDelimiterIndex = line.indexOf(" ", 10);
                int endIndex = nextSpaceDelimiterIndex > -1 ? nextSpaceDelimiterIndex : line.length();
                mod.revision = line.substring(10, endIndex);
            } else if (line.startsWith("Date: ")) {  //e.g. Date: 2004/01/06 17:00:38 -0700;  Size:    39459 bytes
                try {
                    mod.modifiedTime = OUT_DATE_FORMAT.parse(line.substring(6, line.indexOf("-") - 1));
                } catch (ParseException pe) {
                    LOG.warn("Unable to parse date " + line.substring(6, line.indexOf("-") - 1));
                    mod.modifiedTime = new Date(0);
                }
            } else if (line.startsWith("Author: ")) {  //e.g. Author: pacon (Patrick Conant)
                mod.userName = line.substring(8).trim();
                if (mod.userName.indexOf(" ") > -1) {
                    mod.userName = mod.userName.substring(0, mod.userName.indexOf(" "));
                }
            } else if (line.startsWith("Change: ")) {  //e.g. Change: Content
                mod.type = line.substring(8).trim();
                if (mod.type.equals(CHANGE_DELETE) && propertyOnDelete != null) {
                    props.put(propertyOnDelete, "true");
                }
            } else if (line.startsWith("Snapshot: ")) {
                //ignore
            } else if (line.startsWith("Used in: ") || line.startsWith("         /")) {
                //e.g.  Used in: /aaaa/cccc/bbbb/ccccdddd
                //               /aaaa/cccc/bbbb/

                //ignore
            } else if (!line.trim().equals("")) {
                //consider this part of the comment.
                mod.comment += line;
            }
        }

        return modifications;
    }

    public static class SourcePath {
        private String path;

        public SourcePath() {
        }

        public SourcePath(String path) {
            this.path = path;
        }

        public void setPath(String path) {
            this.path = path;
        }

        public String getPath() {
            return this.path;
        }
    }
}
TOP

Related Classes of net.sourceforge.cruisecontrol.sourcecontrols.SnapshotCM$SourcePath

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.