Bug 42462 - Contributing optional task for ClearCase findmerge
Summary: Contributing optional task for ClearCase findmerge
Status: NEW
Alias: None
Product: Ant
Classification: Unclassified
Component: Optional SCM tasks (show other bugs)
Version: unspecified
Hardware: All All
: P2 enhancement with 3 votes (vote)
Target Milestone: 1.8.0
Assignee: Ant Notifications List
URL:
Keywords: PatchAvailable
Depends on:
Blocks:
 
Reported: 2007-05-20 08:02 UTC by Fabio Gavilondo
Modified: 2008-03-18 19:23 UTC (History)
0 users



Attachments
svn patch for org.apache.tools.ant.taskdefs.optional.clearcase.CCFindmerge (12.38 KB, patch)
2007-05-20 08:05 UTC, Fabio Gavilondo
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Fabio Gavilondo 2007-05-20 08:02:59 UTC
The ClearCase optional tasks
(http://ant.apache.org/manual/OptionalTasks/clearcase.html) don't offer support
for merge operations.

I have written a 'CCFindmerge' task that inherits from
org.apache.tools.ant.taskdefs.optional.clearcase.ClearCase, pretty much in the
same vain as the other cc tasks.

Performing a 'findmerge' from your Ant build file is quite useful in situations
where a view/branch needs to be up-to-date with another view/branch ( e.g. the
mainline) before the build can proceed. If a merge is necessary, this command
will fail the build (i.e. throw a BuildException).

I thought that maybe other Ant/ClearCase users out there could use this task
too, so I would like to contribute CCFindmerge to the Apache Ant codebase. I
have done a svn diff. Please find the patch below.

Regards and many thanks for your continuing support of Ant.

Index:
/ant-trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCFindmerge.java
===================================================================
---
/ant-trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCFindmerge.java
(revision 0)
+++
/ant-trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCFindmerge.java
(revision 0)
@@ -0,0 +1,384 @@
+/*
+ * Copyright  2000-2004 The Apache Software Foundation
+ *
+ *  Licensed 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.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs a ClearCase findmerge.
+ * 
+ * The command will not actually merge anything, just fail the build if a merge
is necessary. This check is quite useful
+ * in situations where a view/branch needs to be up-to-date with another
view/branch (e.g. main) before running build
+ * can be run.
+ * 
+ * <p>
+ * The following attributes are interpreted:
+ * 
+ * <table border="1">
+ * <tr>
+ * <th>Attribute</th>
+ * <th>Values</th>
+ * <th>Required</th>
+ * </tr>
+ * <tr>
+ * <td>viewpath</td>
+ * <td>Path to the ClearCase view file or directory that the command will
operate on</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>viewtag</td>
+ * <td>view-tag. Compare the version selected by your view with the version
selected by the view specified by view-tag.
+ * view-tag may not specify a snapshot view. A version of the same element is
always used, even if the version has a
+ * different name in the other view.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>version</td>
+ * <td>version-selector. Compare with the version specified by the
version-selector. A version selector involving a
+ * branch type, for example /main/LATEST or .../branch1/LATEST, is optimized
for selecting the set of versions to
+ * consider and performs better than other types of queries. If the branch
exists only on a relatively small number of
+ * versions in the VOB, this option performs much better than other types of
queries.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>latest</td>
+ * <td>(Consider only versions that are currently checked out.) Compare with
the most recent version on the branch from
+ * which your version was checked out. This option is useful with versions for
which you have unreserved checkouts: if
+ * one or more new versions have been checked in by other users, you must merge
the most recent one into your
+ * checked-out version before you can perform a checkin.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>depth</td>
+ * <td>Causes directory entries to be processed before the directory itself.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>nrecurse</td>
+ * <td>For each directory version, considers the file and directory versions
within it, but does not descend into its
+ * subdirectories.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>directory</td>
+ * <td>For each directory, considers only the directory itself, not the
directory or file versions, or VOB symbolic
+ * links it catalogs.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>follow</td>
+ * <td>Causes VOB symbolic links to be traversed.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>nzero</td>
+ * <td>Does not perform a merge if the from-contributor is version 0 on its
branch. This gives you the opportunity to
+ * delete the empty branch, and then perform a merge from the version at which
the branch was created.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>nback</td>
+ * <td>Does not perform the merge in the case described earlier. It may be
appropriate to simulate the merge by moving
+ * the version label down to the from-version. Note, however, that this
alternative leaves the version without a
+ * subbranch, which may or may not be desirable.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>whynot</td>
+ * <td>For each version that does not require a merge, displays a message
explaining the reason. This is especially
+ * useful when you are merging between views whose namespaces differ
significantly.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>visible</td>
+ * <td>Suppresses the warning messages for versions that are not visible in the
current view.</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <tr>
+ * <td>log</td>
+ * <td>pname. Creates pname as the merge log file, instead of selecting a name
automatically. To suppress creation of a
+ * merge log file, use –log /dev/null (UNIX) or –log NUL (Windows)</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>failonerr</td>
+ * <td>Throw an exception if the command fails. Default is true.</td>
+ * <td>No</td>
+ * </tr>
+ * </table>
+ * 
+ * @author Fabio Gavilondo
+ */
+public class CCFindmerge extends ClearCase {
+    public static final String COMMAND_FINDMERGE = "findmerge";
+
+    private static final String FLAG_VIEWTAG = "-ftag";
+
+    private static final String FLAG_VERSION = "-fversion";
+
+    private static final String FLAG_LATEST = "-flatest";
+
+    private static final String FLAG_DEPTH = "-depth";
+
+    private static final String FLAG_NRECURSE = "-nrecurse";
+
+    private static final String FLAG_DIRECTORY = "-directory";
+
+    private static final String FLAG_FOLLOW = "-follow";
+
+    private static final String FLAG_VISIBLE = "-visible";
+
+    private static final String FLAG_NZERO = "-nzero";
+
+    private static final String FLAG_NBACK = "-nback";
+
+    private static final String FLAG_WHYNOT = "-whynot";
+
+    private static final String FLAG_LOG = "-log";
+
+    private static final String FLAG_PRINT = "-print";
+
+    private String viewtag = null;
+
+    private String version = null;
+
+    private boolean latest = false;
+
+    private boolean depth = false;
+
+    private boolean nrecurse = false;
+
+    private boolean directory = false;
+
+    private boolean follow = false;
+
+    private boolean visible = false;
+
+    private boolean nzero = false;
+
+    private boolean nback = false;
+
+    private boolean whynot = false;
+
+    private String log = null;
+
+    public boolean getDepth() {
+        return depth;
+    }
+
+    public void setDepth(boolean depth) {
+        this.depth = depth;
+    }
+
+    public boolean getDirectory() {
+        return directory;
+    }
+
+    public void setDirectory(boolean directory) {
+        this.directory = directory;
+    }
+
+    public boolean getFollow() {
+        return follow;
+    }
+
+    public void setFollow(boolean follow) {
+        this.follow = follow;
+    }
+
+    public boolean getLatest() {
+        return latest;
+    }
+
+    public void setLatest(boolean latest) {
+        this.latest = latest;
+    }
+
+    public String getLog() {
+        return log;
+    }
+
+    public void setLog(String log) {
+        this.log = log;
+    }
+
+    public boolean getNback() {
+        return nback;
+    }
+
+    public void setNback(boolean nback) {
+        this.nback = nback;
+    }
+
+    public boolean getNrecurse() {
+        return nrecurse;
+    }
+
+    public void setNrecurse(boolean nrecurse) {
+        this.nrecurse = nrecurse;
+    }
+
+    public boolean getNzero() {
+        return nzero;
+    }
+
+    public void setNzero(boolean nzero) {
+        this.nzero = nzero;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getViewtag() {
+        return viewtag;
+    }
+
+    public void setViewtag(String viewtag) {
+        this.viewtag = viewtag;
+    }
+
+    public boolean getVisible() {
+        return visible;
+    }
+
+    public void setVisible(boolean visible) {
+        this.visible = visible;
+    }
+
+    public boolean getWhynot() {
+        return whynot;
+    }
+
+    public void setWhynot(boolean whynot) {
+        this.whynot = whynot;
+    }
+
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_FINDMERGE);
+
+        // Check the command line options
+        checkOptions(commandLine);
+
+        // For debugging
+        getProject().log(commandLine.toString(), Project.MSG_DEBUG);
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: " +
getViewPathBasename(), Project.MSG_VERBOSE);
+        }
+
+        getProject().log("running command line: " + commandLine.toString(),
Project.MSG_VERBOSE);
+        String result = runS(commandLine);
+        getProject().log("findmerge result: " + result, Project.MSG_VERBOSE);
+
+        if (getFailOnErr() && isCleartoolErrorOutput(result)) {
+            String msg = "Failed executing: \"" + commandLine.toString() + "\".
Reason: " + result;
+            throw new BuildException(msg, getLocation());
+        }
+
+        if (result.contains("Needs Merge")) {
+            String msg = "Path: " + getViewPath() + " needs merge from " +
getMergeSourceDescription();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+    private boolean isCleartoolErrorOutput(String output) {
+        return output.contains("cleartool: Error:");
+    }
+
+    private String getMergeSourceDescription() {
+        if (getViewtag() != null) {
+            return "view " + getViewtag();
+        } else if (getVersion() != null) {
+            return "version " + getVersion();
+        } else {
+            return "latest from branch";
+        }
+    }
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        cmd.createArgument().setValue(getViewPath());
+
+        if (getViewtag() != null) {
+            createArgumentWithValue(cmd, FLAG_VIEWTAG, getViewtag());
+        } else if (getVersion() != null) {
+            createArgumentWithValue(cmd, FLAG_VERSION, getVersion());
+        } else if (getLatest()) {
+            cmd.createArgument().setValue(FLAG_LATEST);
+        }
+
+        if (getDepth()) {
+            cmd.createArgument().setValue(FLAG_DEPTH);
+        }
+        if (getNrecurse()) {
+            cmd.createArgument().setValue(FLAG_NRECURSE);
+        }
+        if (getDirectory()) {
+            cmd.createArgument().setValue(FLAG_DIRECTORY);
+        }
+        if (getFollow()) {
+            cmd.createArgument().setValue(FLAG_FOLLOW);
+        }
+        if (getVisible()) {
+            cmd.createArgument().setValue(FLAG_VISIBLE);
+        }
+        if (getNzero()) {
+            cmd.createArgument().setValue(FLAG_NZERO);
+        }
+        if (getNback()) {
+            cmd.createArgument().setValue(FLAG_NBACK);
+        }
+        if (getWhynot()) {
+            cmd.createArgument().setValue(FLAG_WHYNOT);
+        }
+
+        if (getLog() != null) {
+            createArgumentWithValue(cmd, FLAG_LOG, getLog());
+        }
+
+        cmd.createArgument().setValue(FLAG_PRINT);
+    }
+
+    private static void createArgumentWithValue(Commandline cmd, String
argument, String value) {
+        /*
+         * Had to make two separate commands here because if a space is
inserted between the flag and the value, it is
+         * treated as a Windows filename with a space and it is enclosed in
double quotes ("). This breaks clearcase.
+         */
+        cmd.createArgument().setValue(argument);
+        cmd.createArgument().setValue(value);
+    }
+}
Comment 1 Fabio Gavilondo 2007-05-20 08:05:40 UTC
Created attachment 20221 [details]
svn patch for org.apache.tools.ant.taskdefs.optional.clearcase.CCFindmerge