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.
+ *
+ *
+ *
+ * Attribute |
+ * Values |
+ * Required |
+ *
+ *
+ * viewpath |
+ * Path to the ClearCase view file or directory that the command will operate on |
+ * No |
+ *
+ *
+ * viewtag |
+ * 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. |
+ * No |
+ *
+ *
+ * version |
+ * 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. |
+ * No |
+ *
+ *
+ * latest |
+ * (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. |
+ * No |
+ *
+ *
+ * depth |
+ * Causes directory entries to be processed before the directory itself. |
+ * No |
+ *
+ *
+ * nrecurse |
+ * For each directory version, considers the file and directory versions within it, but does not descend into its
+ * subdirectories. |
+ * No |
+ *
+ *
+ * directory |
+ * For each directory, considers only the directory itself, not the directory or file versions, or VOB symbolic
+ * links it catalogs. |
+ * No |
+ *
+ *
+ * follow |
+ * Causes VOB symbolic links to be traversed. |
+ * No |
+ *
+ *
+ * nzero |
+ * 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. |
+ * No |
+ *
+ *
+ * nback |
+ * 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. |
+ * No |
+ *
+ *
+ * whynot |
+ * 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. |
+ * No |
+ *
+ *
+ * visible |
+ * Suppresses the warning messages for versions that are not visible in the current view. |
+ * No |
+ *
+ *
+ *
+ * log |
+ * 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) |
+ * No |
+ *
+ *
+ * failonerr |
+ * Throw an exception if the command fails. Default is true. |
+ * No |
+ *
+ *
+ *
+ * @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);
+ }
+}