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. + * + *

+ * The following attributes are interpreted: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AttributeValuesRequired
viewpathPath to the ClearCase view file or directory that the command will operate onNo
viewtagview-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
versionversion-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
depthCauses directory entries to be processed before the directory itself.No
nrecurseFor each directory version, considers the file and directory versions within it, but does not descend into its + * subdirectories.No
directoryFor each directory, considers only the directory itself, not the directory or file versions, or VOB symbolic + * links it catalogs.No
followCauses VOB symbolic links to be traversed.No
nzeroDoes 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
nbackDoes 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
whynotFor 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
visibleSuppresses the warning messages for versions that are not visible in the current view.No
logpname. 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
failonerrThrow 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); + } +}