Introduction
IBM Rational ClearCase is a powerful version control system used worldwide. It also provides a set of COM APIs which can be used to harness its powerful features. These APIs constitute a library called the ClearCase Automation Library (CAL).
Purpose
In my company, we need to perform several ClearCase queries daily. I wanted to automate these queries and provide them in an easy to use manner. I searched for ways to use CAL with C#. My quest led me here. So, I was left with no other option than to use CAL's COM APIs. .NET allows you to call COM code using a proxy called Runtime Callable Wrapper.
My first step in the automation process was to build a library which would help me communicate with the ClearCase COM APIs. The result of this effort was the ClearcaseHelper
class.
Prerequisites
You need to have the following installed:
- Rational ClearCase 6.0 or later.
- .NET 2.0 or later.
- Visual Studio 2005/2008.
Create a C# Project
Create a C# Console Application in Visual Studio (I am using VS2008).
Add a Reference to the ClearCase Automation Library (CAL)
Right click on the References folder in the Solution Browser. Select Add Reference.

Select the COM tab. Scroll to ClearCase Automation Library (5.0 or 6.0 depending on your ClearCase version). I have ClearCase 7.1 installed, so ClearCase Automation Library 6.0 is listed. Click OK.

Now, in the References folder, ClearCase will be listed.

Now, your project is ready to use the features of CAL.
Using the CAL
At the highest level, CAL is divided into various objects. Some CAL objects are representations of the underlying ClearCase data; for example, the CCCheckedOutFile
object represents a checked out file. Other CAL objects are control objects, which do not directly represent the underlying ClearCase data, but manage it. For example, the CCCheckedOutFiles
collection class manages a collection of CCCheckedOutFile
objects, the CCCheckedOutFileQuery
object lets you build up a query for finding checked-out files, and the TriggerTypeBuilder
object lets you construct parameters for creating a trigger type object. The two main components of the CAL which we will be using extensively are:
ClearCase.Application
ClearCase.ClearTool
The Application
object provides most of the CAL API. Most applications using CAL will start there. The ClearTool
object contains just one method, CmdExec
, which is invoked to execute a ClearTool subcommand string. The ClearTool
object is provided to ensure that any capabilities in ClearTool not covered by the Application
object are accessible programmatically. ClearCase.Application
and ClearCase.ClearTool
are the only two objects in CAL that are externally creatable (and are consequently the only two objects that do not have the "CC" naming prefix).
So, we will maintain instances of these two classes in our application.
ClearcaseHelper

In the attached source code, I have provided a class called ClearcaseHelper
which consists of several methods which are wrappers for various commonly used ClearCase features and APIs. Before using the APIs, you need to set its BaseDrive
property. Its value should be set as the name of the network drive where your view is mounted (example, O:).
Here is the list of APIs available in ClearcaseHelper
:
Get all ClearCase Regions
The current ClearCase Region name is stored in the Registry at HKEY_LOCAL_MACHINE\SOFTWARE\Atria\ClearCase\CurrentVersion\Region (for 32 bit OS) and at HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Atria\ClearCase\CurrentVersion\Region (for 64 bit OS). In order to get all the Region names, ClearTool needs to be invoked with the arguments lsregion -s.
public static bool GetCurrentRegion(ref string region)
{
bool regionFound = false;
try
{
RegistryKey theKey = Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\Atria\ClearCase\CurrentVersion\Region");
if (theKey == null)
theKey = Registry.LocalMachine.OpenSubKey(
@"\SOFTWARE\Wow6432Node\Atria\ClearCase\CurrentVersion");
if (theKey != null)
{
region = theKey.GetValue("Region") as string;
if (!string.IsNullOrEmpty(region))
regionFound = true;
}
return regionFound;
}
catch (Exception e)
{
EventLog.WriteEntry("CCAutomation",
"Exception during ClearcaseHelper.GetCurrentRegion()\n" +
e.ToString(), EventLogEntryType.Error);
throw e;
}
}
public static List<string> GetAllRegions()
{
try
{
if (ct != null)
{
string regions = ct.CmdExec("lsregion -s");
return new List<string>(regions.Split(new string[] { "\r\n" },
StringSplitOptions.RemoveEmptyEntries));
}
return null;
}
catch (Exception e)
{
EventLog.WriteEntry("CCAutomation",
"Exception during ClearcaseHelper.GetAllRegions()\n" +
e.ToString(), EventLogEntryType.Error);
throw e;
}
}
Get all Views
In order to get all the views, ClearCase.Application
's get_Views
method needs to be called. The arguments required are the Region name and a boolean value to indicate whether the method should fail in case it encounters any error while querying for the views. This method returns ClearCase.CCViews
which is a collection of ClearCase.CCView
s. The TagName
property of ClearCase.CCView
gives the name of the view.
public static List<string> GetAllViews()
{
try
{
string region = string.Empty;
if (GetCurrentRegion(ref region))
{
return GetAllViews(region);
}
EventLog.WriteEntry("CCAutomation",
"Error during ClearcaseHelper.GetAllViews()\nNo Clearcase Region found!",
EventLogEntryType.Error);
throw new ArgumentNullException("Region",
"Clearcase Region not Found!");
}
catch (Exception e)
{
throw e;
}
}
public static void GetAllViews(ref List<ClearCase.CCView> views_ref)
{
try
{
string region = string.Empty;
if (GetCurrentRegion(ref region))
{
GetAllViews(region, ref views_ref);
}
EventLog.WriteEntry("CCAutomation",
"Error during ClearcaseHelper.GetAllViews()\nNo Clearcase Region found!",
EventLogEntryType.Error);
throw new ArgumentNullException("Region",
"Clearcase Region not Found!");
}
catch (Exception e)
{
throw e;
}
}
public static List<string> GetAllViews(string region_in)
{
try
{
if (String.IsNullOrEmpty(BaseDrive))
throw new ArgumentNullException("BaseDrive",
"BaseDrive is not set!");
string currView = string.Empty;
if (ccApp != null)
{
ClearCase.CCViews views = ccApp.get_Views(false, region_in);
List<string> viewList = new List<string>();
foreach (ClearCase.CCView view in views)
{
viewList.Add(view.TagName);
}
return viewList;
}
return null;
}
catch (Exception e)
{
EventLog.WriteEntry("CCAutomation",
"Exception during ClearcaseHelper.GetAllViews()\n" +
e.ToString(), EventLogEntryType.Error);
throw e;
}
}
public static void GetAllViews(string region_in, ref List<ClearCase.CCView> views_ref)
{
try
{
if (String.IsNullOrEmpty(BaseDrive))
throw new ArgumentNullException("BaseDrive",
"BaseDrive is not set!");
string currView = string.Empty;
if (ccApp != null)
{
ClearCase.CCViews views = ccApp.get_Views(false, region_in);
views_ref = new List<ClearCase.CCView>();
foreach (ClearCase.CCView view in views)
{
views_ref.Add(view);
}
}
}
catch (Exception e)
{
EventLog.WriteEntry("CCAutomation",
"Exception during ClearcaseHelper.GetAllViews()\n" +
e.ToString(), EventLogEntryType.Error);
throw e;
}
}
Get all the Versioned Objects (VOBs) in a Given View
To get all the Versioned Objects (VOBs), ClearCase.Application
's get_VOBs
method needs to be called. The arguments required are the Region name and a boolean value to indicate whether the method should fail in case it encounters any error while querying for the views. This method returns ClearCase.CCVOBs
which is a collection of ClearCase.CCVOB
s. The TagName
property of ClearCase.CCVOB
gives the name of the VOB.
public static List<string> GetAllVOBs()
{
try
{
string region = string.Empty;
if (GetCurrentRegion(ref region))
{
return GetAllVOBs(region);
}
EventLog.WriteEntry("CCAutomation",
"Error during ClearcaseHelper.GetAllVOBs()\n" +
"No Clearcase Region found!", EventLogEntryType.Error);
throw new ArgumentNullException("Region",
"Clearcase Region not Found!");
}
catch (Exception e)
{
throw e;
}
}
public static void GetAllVOBs(ref List<ClearCase.CCVOB> vobs_ref)
{
try
{
string region = string.Empty;
if (GetCurrentRegion(ref region))
{
GetAllVOBs(region, ref vobs_ref);
}
EventLog.WriteEntry("CCAutomation",
"Error during ClearcaseHelper.GetAllVOBs()\n" +
"No Clearcase Region found!", EventLogEntryType.Error);
throw new ArgumentNullException("Region",
"Clearcase Region not Found!");
}
catch (Exception e)
{
throw e;
}
}
public static List<string> GetAllVOBs(string region_in)
{
try
{
if (String.IsNullOrEmpty(region_in))
return null;
if (ccApp != null)
{
ClearCase.CCVOBs vobs = ccApp.get_VOBs(false, region_in);
List<string> vobList = new List<string>();
foreach (ClearCase.CCVOB vob in vobs)
{
vobList.Add(vob.TagName);
}
return vobList;
}
return null;
}
catch (Exception e)
{
EventLog.WriteEntry("CCAutomation",
"Exception during ClearcaseHelper.GetAllVOBs()\n" +
e.ToString(), EventLogEntryType.Error);
throw e;
}
}
public static void GetAllVOBs(string region_in, ref List<ClearCase.CCVOB> vobs_ref)
{
try
{
if (String.IsNullOrEmpty(region_in))
return;
if (ccApp != null)
{
ClearCase.CCVOBs vobs = ccApp.get_VOBs(false, region_in);
vobs_ref = new List<ClearCase.CCVOB>();
foreach (ClearCase.CCVOB vob in vobs)
{
vobs_ref.Add(vob);
}
}
}
catch (Exception e)
{
EventLog.WriteEntry("CCAutomation",
"Exception during ClearcaseHelper.GetAllVOBs()\n" +
e.ToString(), EventLogEntryType.Error);
throw e;
}
}
Get the Config Spec of a View
The ConfigSpec
property of ClearCase.CCView
gives the config spec of the View as a single string. Each ClearCase rule within the config spec is separated by the "\n" token.
public static List<string> GetConfigSpec()
{
try
{
return GetConfigSpec(GetCurrentView());
}
catch (Exception e)
{
throw e;
}
}
public static List<string> GetConfigSpec(string view_in)
{
try
{
if ((ccApp != null) && (!String.IsNullOrEmpty(view_in)))
{
ClearCase.CCView view = ccApp.get_View(view_in);
if (view != null)
{
string cfgSpec = view.ConfigSpec;
return new List<string>(cfgSpec.Split(new string[] { "\n" },
StringSplitOptions.None));
}
}
return null;
}
catch (Exception e)
{
EventLog.WriteEntry("CCAutomation",
"Exception during ClearcaseHelper.GetConfigSpec()\n" +
e.ToString(), EventLogEntryType.Error);
throw e;
}
}
Set the Config Spec of a View
The ConfigSpec
property of ClearCase.CCView
can also be used to set the config spec of a view.
public static void SetConfigSpec(List<string> configSpec)
{
try
{
if (configSpec == null)
return;
SetConfigSpec(configSpec, GetCurrentView());
}
catch (Exception e)
{
throw e;
}
}
public static bool SetConfigSpec(List<string> configSpec, string view_in)
{
try
{
if (configSpec == null)
return false;
if (ccApp != null)
{
StringBuilder sb = new StringBuilder();
foreach (string s in configSpec)
{
sb.Append(s);
sb.Append("\n");
}
sb.Remove(sb.Length - 1, 1);
string cs = sb.ToString();
ClearCase.CCView view = ccApp.get_View(view_in);
if (view != null)
{
view.ConfigSpec = cs;
return true;
}
}
return false;
}
catch (Exception e)
{
EventLog.WriteEntry("CCAutomation",
"Exception during ClearcaseHelper.SetConfigSpec()\n" +
e.ToString(), EventLogEntryType.Error);
throw e;
}
}
Create a Label
To create a label for a specific VOB, we need to invoke the CreateLabelType
method of ClearCase.CCVOB
. The following parameters are required:
- Name:
string
: Name of the new label type. - Comment:
string
: A comment to associate with the history record for this CreateLabelType
operation. - Shared:
bool
: true
if label type can be shared across all replicas in a VOB family; false
if label type can be mastered only by one replica. - Constraint:
ClearCase.CCTypeConstraint
: Restriction for the label type. Must be one of the valid CCTypeConstraint
values. It can be PerElement
, PerBranch
, PerVersion
, or None
. - Global:
bool
: true
to make this label type global to all client VOBs of this administrative VOB; false
to make this label type an ordinary type for use only within this VOB. - Acquire:
bool
: true
to convert existing ordinary types that would be eclipsed by this operation into local copies of this global label type (only allowed if Global
is true
); false
to fail if any existing types would be eclipsed (An eclipsed type is one that has the same name as the global type in its administrative VOB).
public static bool CreateLabel(string label_in, string comments_in, string vob_path)
{
try
{
bool result = false;
if (string.IsNullOrEmpty(label_in))
return false;
if (ccApp != null)
{
ClearCase.CCVOB vob = ccApp.get_VOB(vob_path);
if ((vob != null) && (vob.IsMounted))
{
ClearCase.CCLabelType label =
vob.CreateLabelType(label_in, comments_in, true,
ClearCase.CCTypeConstraint.ccConstraint_PerBranch,
false, false);
if (label != null)
result = true;
}
}
return result;
}
catch (Exception e)
{
EventLog.WriteEntry("CCAutomation",
"Exception during ClearcaseHelper.CreateLabel()\n" +
e.ToString(), EventLogEntryType.Error);
throw e;
}
}
ClearcaseHelper
also provides a few APIs which will help you perform queries, like:
Search for a Label Given a Search Token
The get_LabelTypes
method of ClearCase.CCVOB
returns ClearCase.CCLabelTypes
which is a collection of ClearCase.CCLabelType
s. The Name
property of ClearCase.CCLabelType
can be used to check if the given token is present in the label name. You can also use ClearCase.CCLabelType
properties to obtain further information such as the name of the creator, the date of creation, etc.
public static List<ClearCase.CCLabelType>
SearchLabelsBasedOnToken(string token, string vob_path)
{
try
{
if ((string.IsNullOrEmpty(token)) ||
(string.IsNullOrEmpty(vob_path)))
return null;
if (ccApp != null)
{
ClearCase.CCVOB vob = ccApp.get_VOB(vob_path);
if ((vob != null) && (vob.IsMounted))
{
ClearCase.CCLabelTypes labels =
vob.get_LabelTypes(true, true);
List<ClearCase.CCLabelType> result =
new List<ClearCase.CCLabelType>();
foreach (ClearCase.CCLabelType label in labels)
{
if (label.Name.IndexOf(token) != -1)
{
result.Add(label);
}
}
return result;
}
}
return null;
}
catch (Exception e)
{
EventLog.WriteEntry("CCAutomation",
"Exception during ClearcaseHelper.SearchLabelsBasedOnToken()\n" +
e.ToString(), EventLogEntryType.Error);
throw e;
}
}
Search for Checkouts in a Given VOB
In order to query for the checked-out files in a VOB, first you need to create a ClearCase.CCCheckedOutFileQuery
by calling the CreateCheckedOutFileQuery
method of the ClearCase Application. You can modify the properties of the ClearCase.CCCheckedOutFileQuery
created; like for example, you can specify the list of VOBs to search for (by modifying the PathArray
property). Once you have set all the required properties, you need to call the Apply
method. This will return ClearCase.CCCheckedOutFiles
, which is a collection of ClearCase.CCCheckedOutFile
s. You can use ClearCase.CCCheckedOutFile
properties to obtain further information such as the details of the user who checked out the file, the view in which this file is checked out etc.
public static List<ClearCase.CCCheckedOutFile> GetCheckOuts(string vob_path)
{
try
{
if (string.IsNullOrEmpty(vob_path))
return null;
if (ccApp != null)
{
ClearCase.CCVOB vob = ccApp.get_VOB(vob_path);
ClearCase.CCCheckedOutFileQuery coQuery = ccApp.CreateCheckedOutFileQuery();
object[] arr = new object[] { vob_path };
coQuery.PathArray = arr;
coQuery.PathSelects = ClearCase.CCPath_Selection.ccSelection_AllInVOB;
ClearCase.CCCheckedOutFiles coFiles = coQuery.Apply();
List<ClearCase.CCCheckedOutFile> files = new List<ClearCase.CCCheckedOutFile>();
foreach (ClearCase.CCCheckedOutFile file in coFiles)
files.Add(file);
return files;
}
return null;
}
catch (Exception e)
{
EventLog.WriteEntry("CCAutomation",
"Exception during ClearcaseHelper.SearchLabelsBasedOnDateRange()\n" +
e.ToString(), EventLogEntryType.Error);
throw e;
}
}
You can use these methods in your application or even extend them. There are various other ClearCase features for which you can write your own wrappers, like, for example:
- Create a Branch
- Create a VOB
- Get details of a ClearCase Element
Using the ClearcaseHelper in Your Code
Consider the following scenario. You have a ClearCase View named my_clearcase_view and you have mapped it to the network drive O: and mounted all the VOBs. Add the ClearcaseHelper
class to your project, and in your code, add the following code to get the list of files that are checked out in a particular VOB, say VOB1:
ClearcaseHelper.BaseDrive = "O:";
List<ClearCase.CCCheckedOutFile> checkouts =
ClearcaseHelper.GetCheckOuts(@"O:\VOB1");
string currentView = ClearcaseHelper.GetCurrentView();
foreach (ClearCase.CCCheckedOutFile file in files)
{
if (file.ByView.TagName == currentView)
Console.WriteLine("{0}\t", file.Path);
}
Note
IBM, Rational, and ClearCase are copyrighted trademarks of IBM Corporation.
References
ClearCase Automation Library (CAL) documentation.