com.michelin.cio.hudson.plugins.clearcaseucmbaseline.ClearToolUcmBaseline.java Source code

Java tutorial

Introduction

Here is the source code for com.michelin.cio.hudson.plugins.clearcaseucmbaseline.ClearToolUcmBaseline.java

Source

/*
 * The MIT License
 *
 * Copyright (c) 2010, Manufacture Franaise des Pneumatiques Michelin, Romain Seguy
 * Copyright (c) 2007-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Erik Ramfelt,
 *                          Henrik Lynggaard, Peter Liljenberg, Andrew Bayer
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.michelin.cio.hudson.plugins.clearcaseucmbaseline;

import hudson.FilePath;
import hudson.Util;
import hudson.plugins.clearcase.ClearToolExec;
import hudson.plugins.clearcase.ClearToolLauncher;
import hudson.plugins.clearcase.util.PathUtil;
import hudson.util.ArgumentListBuilder;
import hudson.util.VariableResolver;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;
import java.util.Random;
import org.apache.commons.lang.StringUtils;

/**
 * This class defines the cleartool command for use by
 * {@link ClearCaseUcmBaselineParameterValue#createBuildWrapper(hudson.model.AbstractBuild)}.
 * 
 * <p>While this class extends {@link ClearToolExec}, most of {@link ClearToolExec}'s
 * methods will throw an {@link UnsupportedOperationException} since only the methods
 * useful for {@link ClearCaseUcmBaselineParameterValue#createBuildWrapper(hudson.model.AbstractBuild)}
 * have been implemented.</p>
 *
 * @author Romain Seguy (http://davadoc.deviantart.com)
 */
public class ClearToolUcmBaseline extends ClearToolExec {

    /**
     * Used to cache components given the baseline they belong to (the key is
     * a baseline selector).
     */
    private transient Map<String, String> componentsCache = new Hashtable<String, String>();
    /**
     * Used to cache root dirs given the component they belong to (the key is
     * a component selector).
     */
    private transient Map<String, String> componentRootDirsCache = new Hashtable<String, String>();
    /**
     * Used to cache the dependent baselines given the baseline they depend on.
     */
    private transient Map<String, String[]> dependentBaselinesCache = new Hashtable<String, String[]>();

    public ClearToolUcmBaseline(VariableResolver variableResolver, ClearToolLauncher launcher) {
        super(variableResolver, launcher);
    }

    /**
     * Returns, for a given ClearCase UCM baseline, the ClearCase UCM component
     * this baseline refers to.
     *
     * <p>The ClearCase UCM components are cached for each instance of the class.</p>
     *
     * @see ftp://ftp.software.ibm.com/software/rational/docs/v2002/cc/cc_ref_1.pdf (%[component]p, page 392)
     */
    public String getComponentFromBaseline(String pvob, String baseline) throws IOException, InterruptedException {
        String baselineSelector = baseline + '@' + pvob;

        if (componentsCache.containsKey(baselineSelector)) {
            return componentsCache.get(baselineSelector);
        }

        // cleartool lsbl -fmt "%[component]p" <baseline>@<pvob>
        ArgumentListBuilder cmd = new ArgumentListBuilder();
        cmd.add("lsbl");
        cmd.add("-fmt");
        cmd.add("%[component]p");
        cmd.add(baselineSelector);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        launcher.run(cmd.toCommandArray(), null, baos, null);
        String cleartoolOutput = ClearCaseUcmBaselineUtils.processCleartoolOuput(baos);
        baos.close();

        // ensure no error has occured
        if (cleartoolOutput.contains("cleartool: Error")) {
            launcher.getListener().error("Failed to get component from the baseline " + baselineSelector + ".");
            throw new IOException(
                    "Failed to get the component from the baseline " + baselineSelector + ": " + cleartoolOutput);
        }

        // no error ==> it means the cleartool ouput just contains the component

        // caching
        componentsCache.put(baselineSelector, cleartoolOutput);

        return cleartoolOutput;
    }

    /**
     * Returns, for a given ClearCase UCM component, its root dir.
     *
     * <p>Note that in case the component is rootless, an empty string is
     * returned (cf. HUDSON-6398).</p>
     * <p>The root dirs are cached for each instance of the class.</p>
     *
     * @see ftp://ftp.software.ibm.com/software/rational/docs/v2002/cc/cc_ref_1.pdf (%[root_dir]p, page 392)
     */
    public String getComponentRootDir(String pvob, String component) throws IOException, InterruptedException {
        String componentSelector = component + '@' + pvob;

        if (componentRootDirsCache.containsKey(componentSelector)) {
            return componentRootDirsCache.get(componentSelector);
        }

        // cleartool lscomp -fmt "%[root_dir]p" <component>@<pvob>
        ArgumentListBuilder cmd = new ArgumentListBuilder();
        cmd.add("lscomp");
        cmd.add("-fmt");
        cmd.add("%[root_dir]p");
        cmd.add(componentSelector);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        launcher.run(cmd.toCommandArray(), null, baos, null);
        String cleartoolOutput = ClearCaseUcmBaselineUtils.processCleartoolOuput(baos);
        baos.close();

        // ensure no error has occured
        if (cleartoolOutput != null && cleartoolOutput.contains("cleartool: Error")) {
            launcher.getListener().error("Failed to get root dir of the component " + componentSelector + ".");
            throw new IOException(
                    "Failed to get the root dir of the component " + componentSelector + ": " + cleartoolOutput);
        }

        // no error ==> it means the cleartool ouput just contains the root dir
        // or an empty string if the component is rootless -- cf. HUDSON-6398

        // caching
        componentRootDirsCache.put(componentSelector, cleartoolOutput);

        return cleartoolOutput != null ? cleartoolOutput.trim() : StringUtils.EMPTY;
    }

    /**
     * Returns, for a given ClearCase UCM composite baseline, all the baselines
     * in the dependencies graph.
     *
     * @return An array of ClearCase UCM baseline selectors (it may be empty)
     *
     * @see ftp://ftp.software.ibm.com/software/rational/docs/v2002/cc/cc_ref_1.pdf (%[depends_on_closure]p, page 392)
     */
    public String[] getDependentBaselines(String pvob, String baseline) throws IOException, InterruptedException {
        String baselineSelector = baseline + '@' + pvob;

        if (dependentBaselinesCache.containsKey(baselineSelector)) {
            return dependentBaselinesCache.get(baselineSelector);
        }

        String[] dependentBaselines = null;

        ArgumentListBuilder cmd = new ArgumentListBuilder();
        cmd.clear();
        cmd.add("lsbl");
        cmd.add("-fmt");
        cmd.add("%[depends_on_closure]p");
        cmd.add(baselineSelector);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        launcher.run(cmd.toCommandArray(), null, baos, null);
        String cleartoolOutput = ClearCaseUcmBaselineUtils.processCleartoolOuput(baos);
        baos.close();

        // ensure no error has occured
        if (cleartoolOutput.contains("cleartool: Error")) {
            launcher.getListener()
                    .error("Failed to get the dependent baselines from the baseline " + baselineSelector + ".");
            throw new IOException("Failed to get the dependent baselines from the baseline " + baselineSelector
                    + ": " + cleartoolOutput);
        }

        if (cleartoolOutput.length() > 0) {
            dependentBaselines = cleartoolOutput.split(" ");
        } else {
            dependentBaselines = new String[0];
        }

        // caching
        dependentBaselinesCache.put(baselineSelector, dependentBaselines);

        return dependentBaselines;
    }

    @Override
    protected FilePath getRootViewPath(ClearToolLauncher launcher) {
        return launcher.getWorkspace();
    }

    public void update(String viewName, String loadRules) throws IOException, InterruptedException {
        unsupportedMethod(Thread.currentThread().getStackTrace()[0]);
    }

    public void rmview(String viewName) throws IOException, InterruptedException {
        // cleartool rmview -force <view name>
        ArgumentListBuilder cmd = new ArgumentListBuilder();
        cmd.add("rmview");
        cmd.add("-force");
        cmd.add(viewName);

        // run the cleartool command
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        launcher.run(cmd.toCommandArray(), null, baos, null);
        String cleartoolOutput = ClearCaseUcmBaselineUtils.processCleartoolOuput(baos);
        baos.close();

        // ensure no error has occured
        if (cleartoolOutput.contains("cleartool: Error")) {
            launcher.getListener().error("Failed to remove view " + viewName + ".");
            throw new IOException("Failed to remove view " + viewName + ": " + cleartoolOutput);
        }

        // manually delete the view folder if cleartool rmview didn't actually remove it
        FilePath viewFilePath = launcher.getWorkspace().child(viewName);
        if (viewFilePath.exists()) {
            launcher.getListener().getLogger()
                    .println("View folder was not actually removed by \"cleartool rmview\"; Removing it now...");
            viewFilePath.deleteRecursive();
        }
    }

    public void rmviewtag(String viewName) throws IOException, InterruptedException {
        unsupportedMethod(Thread.currentThread().getStackTrace()[0]);
    }

    public void mkview(String viewName, String streamSelector) throws IOException, InterruptedException {
        mkview(viewName, null, true, null);
    }

    public void mkview(String viewName, String mkviewOptionalParam, boolean snapshotView, String streamSelector)
            throws IOException, InterruptedException {
        // cleartool mkview -tag <tag> <view path> <optional parameters>
        ArgumentListBuilder cmd = new ArgumentListBuilder();
        cmd.add("mkview");
        if (snapshotView) {
            cmd.add("-snapshot");
        }
        cmd.add("-tag");
        cmd.add(viewName); // let's save user config stuff: we reuse the view name as the tag name

        // HUDSON-6409
        if (StringUtils.isNotBlank(mkviewOptionalParam)) {
            cmd.addTokenized(Util.replaceMacro(mkviewOptionalParam, variableResolver));
        }

        cmd.add(viewName);

        // run the cleartool command
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        launcher.run(cmd.toCommandArray(), null, baos, null);
        String cleartoolOutput = ClearCaseUcmBaselineUtils.processCleartoolOuput(baos);
        baos.close();

        // ensure no error has occured
        if (cleartoolOutput.contains("cleartool: Error")) {
            launcher.getListener().error("Failed to create view " + viewName + ".");
            throw new IOException("Failed to create view " + viewName + ": " + cleartoolOutput);
        }
    }

    // ClearCase plugin 1.1 upward compatibility
    public void mkview(String viewName, String streamSelector, String defaultStorageDir)
            throws IOException, InterruptedException {
        unsupportedMethod(Thread.currentThread().getStackTrace()[0]);
    }

    public void setcs(String viewName, String configSpec) throws IOException, InterruptedException {
        FilePath workspace = launcher.getWorkspace();
        FilePath configSpecFile = workspace.createTextTempFile("configspec", ".txt", configSpec);
        String configSpecLocation = ".." + File.separatorChar + configSpecFile.getName();
        configSpecLocation = PathUtil.convertPathForOS(configSpecLocation, launcher.getLauncher());

        // cleartool setcs <configspec>
        ArgumentListBuilder cmd = new ArgumentListBuilder();
        cmd.add("setcs");
        cmd.add("-tag");
        cmd.add(viewName);
        cmd.add(configSpecLocation);

        // run the cleartool command
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        launcher.run(cmd.toCommandArray(), null, baos, workspace.child(viewName));
        String cleartoolOutput = ClearCaseUcmBaselineUtils.processCleartoolOuput(baos);
        baos.close();

        configSpecFile.delete();

        // ensure no error has occured
        if (cleartoolOutput.contains("cleartool: Error")) {
            launcher.getListener().error("Failed to set the config spec of the view " + viewName + ".");
            throw new IOException("Failed to set the config spec of the view " + viewName + ": " + cleartoolOutput);
        }
    }

    public void startView(String viewTags) throws IOException, InterruptedException {
        unsupportedMethod(Thread.currentThread().getStackTrace()[0]);
    }

    public void syncronizeViewWithStream(String viewName, String stream) throws IOException, InterruptedException {
        unsupportedMethod(Thread.currentThread().getStackTrace()[0]);
    }

    // ClearCase plugin 1.2 upward compatibility
    public void update(String viewName, String[] loadRules) throws IOException, InterruptedException {
        unsupportedMethod(Thread.currentThread().getStackTrace()[0]);
    }

    /**
     * Always throws an {@link UnsupportedOperationException}.
     * 
     * @param ste a {@link StackTraceElement} from which the name of the method
     *            calling this one will be gathered (must NOT be {@code null}
     */
    private void unsupportedMethod(StackTraceElement ste) {
        throw new UnsupportedOperationException(ClearCaseUcmBaselineSCM.class.getName() + " does not support the "
                + ste.getMethodName() + " method.");
    }

}