Using the ClearCase Automation Library with C#






4.52/5 (14 votes)
This article describes how to use the powerful ClearCase Automation Library with C#.
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.
/// <summary>
/// Get the Current Clearcase Region
/// </summary>
/// <param name="region">Current Region name (ref)</param>
/// <returns>true if successful, else false</returns>
public static bool GetCurrentRegion(ref string region)
{
bool regionFound = false;
try
{
// For 32 Bit OS, the Region value is stored at:
// HKEY_LOCAL_MACHINE\SOFTWARE\Atria\ClearCase\CurrentVersion
// For 64 Bit OS, the Region value is stored at:
// HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Atria\ClearCase\CurrentVersion
// We are not sure if the current OS is 32/64 bit, so check at both locations.
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;
}
}
/// <summary>
/// Get all the Clearcase Regions
/// </summary>
/// <returns>List consisting of all the Clearcase Regions</returns>
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.
/// <summary>
/// Get all the views available for this Clearcase Region
/// </summary>
/// <returns>List of View names</returns>
public static List<string> GetAllViews()
{
try
{
string region = string.Empty;
// Get the list of Views for the current Clearcase Region
if (GetCurrentRegion(ref region))
{
return GetAllViews(region);
}
// if Region is not found write to EventLog and throw an ArgumentNullException
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;
}
}
/// <summary>
/// Get all the views available for this Clearcase Region
/// </summary>
/// <param name="views_ref">List of Views (ref)</param>
public static void GetAllViews(ref List<ClearCase.CCView> views_ref)
{
try
{
string region = string.Empty;
// Get the list of Views for the current Clearcase Region
if (GetCurrentRegion(ref region))
{
GetAllViews(region, ref views_ref);
}
// if Region is not found write to EventLog and throw an ArgumentNullException
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;
}
}
/// <summary>
/// Get all the view available for the given Clearcase Region
/// </summary>
/// <param name="region_in">Clearcase Region</param>
/// <returns>List of View names</returns>
public static List<string> GetAllViews(string region_in)
{
try
{
// Check if BaseDrive property is set
if (String.IsNullOrEmpty(BaseDrive))
throw new ArgumentNullException("BaseDrive",
"BaseDrive is not set!");
string currView = string.Empty;
if (ccApp != null)
{
// Get the list of Views for the given Clearcase Region
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;
}
}
/// <summary>
/// Get all the view available for the given Clearcase Region
/// </summary>
/// <param name="region_in">Clearcase Region</param>
/// <param name="views_ref">List of Views (ref)</param>
public static void GetAllViews(string region_in, ref List<ClearCase.CCView> views_ref)
{
try
{
// Check if BaseDrive property is set
if (String.IsNullOrEmpty(BaseDrive))
throw new ArgumentNullException("BaseDrive",
"BaseDrive is not set!");
string currView = string.Empty;
if (ccApp != null)
{
// Get the list of Views for the given Clearcase Region
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.
/// <summary>
/// Get all the VOBs for the current Region
/// </summary>
/// <exception cref="ArgumentNullException">
/// Raised if Current Region is not found.</exception>
/// <returns>List of VOBs</returns>
public static List<string> GetAllVOBs()
{
try
{
string region = string.Empty;
// Get the list of VOBs for the current Region
if (GetCurrentRegion(ref region))
{
return GetAllVOBs(region);
}
// if Region is not found write
// to EventLog and throw an ArgumentNullException
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;
}
}
/// <summary>
/// Get all the VOBs for the current Region
/// </summary>
/// <param name="vobs_ref">List of VOBs (ref)</param>
/// <exception cref="ArgumentNullException">
/// Raised if Current Region is not found.</exception>
public static void GetAllVOBs(ref List<ClearCase.CCVOB> vobs_ref)
{
try
{
string region = string.Empty;
// Get the list of VOBs for the current Region
if (GetCurrentRegion(ref region))
{
GetAllVOBs(region, ref vobs_ref);
}
// if Region is not found write to EventLog
// and throw an ArgumentNullException
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;
}
}
/// <summary>
/// Get the list of VOBs for the given Region
/// </summary>
/// <param name="region_in">Clearcase Region</param>
/// <returns>List of VOBs</returns>
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;
}
}
/// <summary>
/// Get List of VOBs for the given Clearcase Region
/// </summary>
/// <param name="region_in">Clearcase Region</param>
/// <param name="vobs_ref">List of VOBs (ref)</param>
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.
/// <summary>
/// Get the config spec for the current view
/// </summary>
/// <returns>List constisting of the Config spec</returns>
public static List<string> GetConfigSpec()
{
try
{
return GetConfigSpec(GetCurrentView());
}
catch (Exception e)
{
throw e;
}
}
/// <summary>
/// Get the config spec for the given view
/// </summary>
/// <param name="view_in">View name</param>
/// <returns>List constisting of the Config spec</returns>
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.
/// <summary>
/// Set the Config Spec for the current view.
/// </summary>
/// <param name="configSpec">List consisting of the Config Spec</param>
public static void SetConfigSpec(List<string> configSpec)
{
try
{
if (configSpec == null)
return;
SetConfigSpec(configSpec, GetCurrentView());
}
catch (Exception e)
{
throw e;
}
}
/// <summary>
/// Set the Config Spec for the given view.
/// </summary>
/// <param name="configSpec">List consisting of the Config Spec</param>
/// <param name="view_in">View name</param>
/// <returns>true if config spec was set successfully, else false</returns>
public static bool SetConfigSpec(List<string> configSpec, string view_in)
{
try
{
if (configSpec == null)
return false;
if (ccApp != null)
{
// Join the array into a single string
StringBuilder sb = new StringBuilder();
foreach (string s in configSpec)
{
sb.Append(s);
sb.Append("\n");
}
// Remove the last "\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 thisCreateLabelType
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 validCCTypeConstraint
values. It can bePerElement
,PerBranch
,PerVersion
, orNone
. - 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 ifGlobal
istrue
);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).
/// <summary>
/// Create a label with the given label comments in the given VOB.
/// </summary>
/// <param name="label_in">Label Name</param>
/// <param name="comments_in">Label Comments</param>
/// <param name="vob_path">VOB path where the label has to be created</param>
/// <returns></returns>
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)
{
//Get the VOB
ClearCase.CCVOB vob = ccApp.get_VOB(vob_path);
if ((vob != null) && (vob.IsMounted))
{
// Create the label
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.
/// <summary>
/// Search for Labels containing the given token
/// </summary>
/// <param name="token">Token</param>
/// <param name="vob_path">VOB where to search for labels</param>
/// <returns></returns>
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)
{
//Get the VOB
ClearCase.CCVOB vob = ccApp.get_VOB(vob_path);
if ((vob != null) && (vob.IsMounted))
{
// Create the label
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.
/// <summary>
/// Get the list of Checked out files in the given VOB
/// </summary>
/// <param name="vob_path">VOB path</param>
/// <returns></returns>
public static List<ClearCase.CCCheckedOutFile> GetCheckOuts(string vob_path)
{
try
{
if (string.IsNullOrEmpty(vob_path))
return null;
if (ccApp != null)
{
//Get the VOB
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:
// To find the checked out files in the VOB VOB1 for the current view
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.