Package net.sourceforge.cruisecontrol.sourcecontrols

Source Code of net.sourceforge.cruisecontrol.sourcecontrols.ClearCase

/********************************************************************************
* CruiseControl, a Continuous Integration Toolkit
* Copyright (c) 2001, 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 net.sourceforge.cruisecontrol.CruiseControlException;
import net.sourceforge.cruisecontrol.SourceControl;
import net.sourceforge.cruisecontrol.util.ValidationHelper;
import net.sourceforge.cruisecontrol.util.StreamPumper;

import org.apache.log4j.Logger;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;

/**
*  This class implements the SourceControlElement methods for a Clear Case
*  repository.
*
* @author Thomas Leseney
* @author <a href="mailto:jcyip@thoughtworks.com">Jason Yip</a>
* @author Eric Lefevre
* @author Ralf Krakowski
*/
public class ClearCase implements SourceControl {

    private static final Logger LOG = Logger.getLogger(ClearCase.class);

    private Hashtable properties = new Hashtable();

    private String property;

    /**  The path of the clear case view */
    private String viewPath;

    /**  The branch to check for modifications */
    private String branch;
    private boolean recursive = true;

    /**  Date format required by commands passed to Clear Case */
    static final SimpleDateFormat IN_DATE_FORMAT =
            new SimpleDateFormat("dd-MMMM-yyyy.HH:mm:ss");

    /**  Date format returned in the output of Clear Case commands. */
    static final SimpleDateFormat OUT_DATE_FORMAT =
            new SimpleDateFormat("yyyyMMdd.HHmmss");

    /**
     *  Unlikely combination of characters to separate fields in a ClearCase query
     */
    static final String DELIMITER = "#~#";

    /**
     *  Even more unlikely combination of characters to indicate end of one line in query.
     * Carriage return (\n) can be used in comments and so is not available to us.
     */
    static final String END_OF_STRING_DELIMITER = "@#@#@#@#@#@#@#@#@#@#@#@";

    /**
     * Sets the local working copy to use when making queries.
     *
     *@param  path
     */
    public void setViewpath(String path) {
        //_viewPath = getAntTask().getProject().resolveFile(path).getAbsolutePath();
        viewPath = new File(path).getAbsolutePath();
    }

    /**
     * Sets the branch that we're concerned about checking files into.
     *
     *@param  branch
     */
    public void setBranch(String branch) {
        this.branch = branch;
    }

    /**
     * Set whether to check against sub-folders in the view path
     */
    public void setRecursive(boolean recursive) {
        this.recursive = recursive;
    }

    public void setProperty(String property) {
        this.property = property;
    }

    public Hashtable getProperties() {
        return properties;
    }

    public void validate() throws CruiseControlException {
        ValidationHelper.assertIsSet(branch, "branch", this.getClass());
        ValidationHelper.assertIsSet(viewPath, "viewpath", this.getClass());
    }

    /**
     *  Returns an {@link java.util.List List} of {@link ClearCaseModification}
     *  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) {
        String lastBuildDate = IN_DATE_FORMAT.format(lastBuild);
        String nowDate = IN_DATE_FORMAT.format(now);
        properties.put("clearcaselastbuild", lastBuildDate);
        properties.put("clearcasenow", nowDate);

        /*
         * let's try a different clearcase command--this one just takes
             * waaaaaaaay too long.
         * String command = "cleartool find " + _viewPath +
         * " -type f -exec \"cleartool lshistory" +
         * " -since " + lastBuildDate;
         * if(_branch != null)
         * command += " -branch " + _branch;
         * command += " -nco" + // exclude check out events
         * " -fmt \\\" %u;%Nd;%n;%o \\n \\\" \\\"%CLEARCASE_XPN%\\\" \"";
         */
        String command = "cleartool lshistory";

        if (branch != null) {
            command += " -branch " + branch;
        }

        if (recursive) {
            command += " -r ";
        }

        command += " -nco -since " + lastBuildDate;
        command += " -fmt %u"
                + DELIMITER
                + "%Nd"
                + DELIMITER
                + "%En"
                + DELIMITER
                + "%Vn"
                + DELIMITER
                + "%o"
                + DELIMITER
                + "!%l"
                + DELIMITER
                + "!%a"
                + DELIMITER
                + "%Nc"
                + END_OF_STRING_DELIMITER
                + "\\n";

        File root = new File(viewPath);

        LOG.info("ClearCase: getting modifications for " + viewPath);

        LOG.debug("Command to execute : " + command);
        List modifications = null;
        try {
            Process p = Runtime.getRuntime().exec(command, null, root);

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

            InputStream input = p.getInputStream();
            modifications = parseStream(input);

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

        if (modifications == null) {
            modifications = new ArrayList();
        }

        return modifications;
    }

    /**
     *  Parses the input stream to construct the modifications list.
     * 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 {
        ArrayList modifications = new ArrayList();
        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        String ls = System.getProperty("line.separator");

        String line;
        String lines = "";

        while ((line = reader.readLine()) != null) {
            if (!lines.equals("")) {
                lines += ls;
            }
            lines += line;
            ClearCaseModification mod = null;
            if (lines.indexOf(END_OF_STRING_DELIMITER) > -1) {
                mod = parseEntry(lines.substring(0, lines.indexOf(END_OF_STRING_DELIMITER)));
                lines = "";
            }
            if (mod != null) {
                modifications.add(mod);
            }
        }
        return modifications;
    }

    /**
     *  Parses a single line from the reader. Each line contains a signe revision
     *  with the format : <br>
     *  username#~#date_of_revision#~#element_name#~#operation_type#~#comments  <br>
     *
     *
     *@param  line the line to parse
     *@return  a modification element corresponding to the given line
     */
    private ClearCaseModification parseEntry(String line) {
        LOG.debug("parsing entry: " + line);
        String[] tokens = tokeniseEntry(line);
        if (tokens == null) {
            return null;
        }
        String username = tokens[0].trim();

        String timeStamp = tokens[1].trim();
        String elementName = tokens[2].trim();
        String version = tokens[3].trim();
        String operationType = tokens[4].trim();

        String labelList = tokens[5].substring(1).trim();
        Vector labels = extractLabelsList(labelList);

        String attributeList = tokens[6].substring(1).trim();
        Hashtable attributes = extractAttributesMap(attributeList);

        String comment = tokens[7].trim();

        // A branch event shouldn't trigger a build
        if (operationType.equals("mkbranch") || operationType.equals("rmbranch")) {
            return null;
        }

        ClearCaseModification mod = new ClearCaseModification();

        mod.userName = username;
        mod.revision = version;

        String folderName, fileName;
        int sep = elementName.lastIndexOf(File.separator);
        if (sep > -1) {
            folderName = elementName.substring(0, sep);
            fileName = elementName.substring(sep + 1);
        } else {
            folderName = null;
            fileName = elementName;
        }
        ClearCaseModification.ModifiedFile modfile = mod.createModifiedFile(fileName, folderName);

        try {
            mod.modifiedTime = OUT_DATE_FORMAT.parse(timeStamp);
        } catch (ParseException e) {
            mod.modifiedTime = null;
        }

        modfile.action = operationType;
        modfile.revision = version;

        mod.type = "clearcase";
        mod.labels = labels;
        mod.attributes = attributes;

        mod.comment = comment;

        if (property != null) {
            properties.put(property, "true");
        }

        // TODO: check if operation type is a delete

        return mod;
    }

    private String[] tokeniseEntry(String line) {
        int maxTokens = 8;
        int minTokens = maxTokens - 1; // comment may be absent.
        String[] tokens  = new String[maxTokens];
        Arrays.fill(tokens, "");
        int tokenIndex = 0;
        for (int oldIndex = 0, index = line.indexOf(DELIMITER, 0); true;
             oldIndex = index + DELIMITER.length(), index = line.indexOf(DELIMITER, oldIndex), tokenIndex++) {
            if (tokenIndex > maxTokens) {
                LOG.debug("Too many tokens; skipping entry");
                return null;
            }
            if (index == -1) {
                tokens[tokenIndex] = line.substring(oldIndex);
                break;
            } else {
                tokens[tokenIndex] = line.substring(oldIndex, index);
            }
        }
        if (tokenIndex < minTokens) {
            LOG.debug("Not enough tokens; skipping entry");
            return null;
        }
        return tokens;
    }

    /**
     * @param attributeList
     * @return
     */
    private Hashtable extractAttributesMap(String attributeList) {
        Hashtable attributes = null;
        if (attributeList.length() > 0) {
            attributes = new Hashtable();
            StringTokenizer attrST = new StringTokenizer(attributeList, "(), ");
            while (attrST.hasMoreTokens()) {
                String attr = attrST.nextToken();
                int idx = attr.indexOf('=');
                if (idx > 0) {
                    String attrName = attr.substring(0, idx);
                    String attrValue = attr.substring(idx + 1);
                    if (attrValue.startsWith("\"")) {
                        attrValue = attrValue.substring(1, attrValue.length() - 1);
                    }
                    attributes.put(attrName, attrValue);
                }
            }
        }
        return attributes;
    }

    /**
     * @param labelList
     * @return
     */
    private Vector extractLabelsList(String labelList) {
        Vector labels = null;
        if (labelList.length() > 0) {
            labels = new Vector();
            StringTokenizer labelST = new StringTokenizer(labelList, "(), ");
            while (labelST.hasMoreTokens()) {
                labels.add(labelST.nextToken().trim());
            }
        }
        return labels;
    }
}
TOP

Related Classes of net.sourceforge.cruisecontrol.sourcecontrols.ClearCase

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.