Fortunately, there are several steps that will take care of many of these problems and make your life, and the lives of your developers much happier:
There are several ways of handling this problem. If you use ClearStart, you can have ClearStart automatically create the views under a defined $viewdir. If you don't use ClearStart, you can write your own "mkview" function in either Bourne Shell, Kornshell, BASH, or Z-Shell:
This new "mkview" command is easier to use than the standard ClearCase one which requires the "-tag" flag, and the name of the directory where you want to store the view. Therefore, users are more likely to use the easier to use "mkview" instead of "cleartool mkview" command.
mkview() { if [ "" != "$2" -o "" = "$1" ] then echo "Usage: mkview <view_name>" echo " where <view_name> is the name of your view" exit 2 fi cleartool -tag mkview $1 $viewdir/${1}.vws }
If you use C-shell or Turbo-C shell, you will have to define the "mkview" command as a shell script.
ClearStart also changes the way most sites use views. In most sites, users only have one or two views which they constantly edit to see the correct version of the elements stored under ClearCase. This leads to view corruptions, and problems with view private files from one task suddenly showing up in another task.
Under ClearStart, the user will have one view for each separate task they perform. Private view files stay only with the task that created them. Users no longer edit their views, causing incorrect ConfigSpecs to be defined.
Since the SCM controls the views, the SCM can use the views to enforce policy decisions. Suddenly, making SCM policy is quicker and easier, there are fewer problems to handle in ClearCase, and users have an easier time using ClearCase in their jobs.
ClearStart is available from the ClearCase Rational Customer Support Website (http://clearcase.rational.com). You must have a "user password" and "user account" in order to access this Website. However, this is nothing more than your ClearCase license host's user id, and the ClearCase license code. Go to the user Contribution Area and take a look at Software Package T0026.
This is a typical ConfigSpec defined for a programmer doing development work. The branch /main/davidw is the branch where all development is taking place. The base view for development is release INT-REL-1.3.44 which is probably an internal release of the last release that has been approved for development. The programmer is using INT-REL-1.3.44 instead of /main/LATEST in order to have a stable base for development. This is a typical configspec that developers will use.
element * CHECKEDOUT element * /main/davidw/LATEST element * INT-REL-1.3.44 -mkbranch davidw
The programmer would simply put their branch's name where [:BRANCH:] occurs, and substitute their base release for [:BASE_RELEASE:]. This is the heart of the ClearStart template. ClearStart will take this template, and plug in these values for the programmer. The only question is how does ClearStart know which values to use.
element * CHECKEDOUT element * /main/[:BRANCH:]/LATEST element * [:BASE_RELEASE] -mkbranch [:BRANCH:]
This directive is #ClearStart_Subst:. After the directive, you set the value of the variable with an equal sign. Very similar to the way you would do it in Bourne shell, except, instead of using a dollar sign like Bourne shell, ClearStart uses a brace/colon pairing:
In order to match our original ConfigSpec, we could have done the following:
#ClearStart_Subst: variable = [:value:] #ClearStart variable=$value #Unix Shell
#ClearStart_Subst: BRANCH = davidw #ClearStart_Subst: BASE_RELEASE = INT-REL-1.3.44 element * CHECKEDOUT element * /main/[:MR:]/LATEST element * [:RELEASE:] -mkbranch [:MR:]
So, all we have to do is write a simple shell script (or Perl script) that allows a user to input the MR number, and then we echo this MR Number back out to STDOUT. Here's a simple program called getBranch:
#ClearStart_Subst: BRANCH = `getBranch` #ClearStart BRANCH=`getBranch` #Unix Bourne Shell $BRANCH = `getBranch`; #Perl
Notice that the output of the "echo" statement was redirect from standard output to standard error. Otherwise, ClearStart (just like Unix or Perl) would assume the prompt is part of the program's output. Basically, this program just prompts the user for the name of the branch, then echos it into STDOUT.
#! /bin/sh # Name: getBranch # Purpose: Ask what is the branch name to use # echo "What is the name of the branch you wish to use">&2 read branch echo "$branch"
In Kornshell, you use the -u2 tells the print (or echo) statement to print to STDERR instead of STDOUT:
Here's another way in Kornshell:
#! /bin/ksh # Name: getBranch # Purpose: Ask what is the branch name to use # print -u2 "What is the name of the branch you wish to use" read branch print "$branch"
The read var?prompt command in Kornshell is nice because it prints the prompt onto STDERR for you.
#! /bin/ksh # Name: getBranch # Purpose: Ask which Branch to use # read branch?"What is the name of the branch you wish to use? " print "$mr"
And now for you Perl fans:
Notice again I could not print my prompt to STDOUT, so I redirected it to STDERR. Of course, the getBranch program is a bit too simple. None of the versions of this program verifies whether I am allowed to use the branch, or whether the branch actually exists. Here is a nice Kornshell version that uses the "select" statement:
#! /usr/atria/bin/Perl # Name: getBranch # Purpose: Ask which branch to use # print STDERR "What is the name of the branch you wish to use? " chop($mr =); print "$mr\n"
Not perfect. Some of the Kornshell variables aren't defined (what's $id? what's $cleartool? Actually, I have them defined in my ClearCase User Environment), but it does give you a basic idea of a typical shell script.
#! /bin/ksh # Name: getBranch # Find the name of the development branch PS3="Which development Sandbox would you like to use: " select branch from "task1 task2 task3" do [ "" != "$branch" ] && break done # # Modify Branch Name by prepending User's ID # branch="${id}_${branch}" # # Now see if branch exists. If it doesn't create the branch # if $cleartool desc brtype:$branch@$AdminVOB > /dev/null 2>&1 then : #Branch Exists else $cleartool mkbrtype -nc brtype:$branch@$AdminVOB > /dev/null 2>&1 if [ $? -ne 0 ] then print -u2 "ERROR: Couldn't make branch $branch!!" exit 2 fi fi # # Branch selected, now print it out # print "$branch"
Notice how nicely the Kornshell's select statement works. Select takes the list of parameters given (in this case "task1, "task2", "task3") and presents them as a menu. The select statement can also do error checking (in this case, simply verifying that a valid option was selected by seeing if the select variable got a value). The best part of it all is that the select statement does all of its outputing onto STDERR. It is as if Kornshell's select statement was made for ClearStart.
One more thing you might notice about this script. If the branch selected doesn't exist, the script automatically creates the branch type.
The following is a Kornshell version of the "getRelease" shell script to get the base release number. Here, I generate the list of Releases by getting a listing of labels that begin with "INT_REL". Releases that I don't want users to use as a baseline can be locked with the -obsolete flag so they don't show up in an "cleartool lstype" command.
For the error checking aspect, I use Kornshell's "select" statement. The "select" statement is very similar to a "for" statement in syntax, but builds a little menu of the items in the list instead of looping though them. You then select the item from the menu.
The Kornshell "select" statement then verifies the choice, and best of all, it does all this without printing a thing to STDOUT. I normally will program in Perl, but the Kronshell "select" statement seems almost designed with ClearStart in mind. Many of my shell scripts for ClearStart use the same structure as the script below. Create a listing of valid entries, set up a "select" statement, then print the entry picked from the select statement:
Again, this ConfigSpec is a duplicate of the one before. Except, intead of using constants to define my variable values ("davidw" and "RINT-REL-1.3.4") I use the results of the shell scripts above:
# /bin/ksh # Name: getRelease # Purpose: Ask which Release to use # # # Define Constants # prefix="INT_REL" #Prefix of the ClearCase Label Used AdminVOB="$CCENV_ADMINVOB" #Administration VOB # # Get a List of All Possible Release Labels # releaseList="$(cleartool lstype -fmt "%n\n" -kind lbtype \ -invob $AdminVOB | grep "^${prefix}")" if [ "" = "$releaseList" ] then print -u2 "ERROR: View cannot be set: No Releases Avalable" exit 2 fi # # Have User Select Release from Release List # PS3=" Base View on Release Number: " print -u2 "\n" select release in $releaseList do [ "" != "$release" ] && break done # # Output Release Label Selected for ClearStart # print "$release"
So, now we have a ClearStart template that can be used. The shell scripts "getRelease" and "getBranch" are placed in a directory that is in the user's $PATH. When a user runs ClearStart, ClearStart will now put this template onto the ClearStart menu. Or does it?
#ClearStart_Subst: RELEASE = `getRelease` #ClearStart_Subst: BRANCH = `getBranch` element * CHECKEDOUT element * /main/[:BRANCH:]/LATEST element * [:RELEASE:] -mkbranch [:BRANCH:]
Now, this Template ConfigSpec can be used in ClearStart. It has a View Description of the template in the #ClearStart_Desc: directive (needed by all ClearStart Templates), and it has instructions on how to build the actual view from the template. However, there are still a couple of problems. When this Template gets displayed in the ClearStart menu, the user builds a view. Next time this user starts ClearStart, this view should also appear in the ClearStart menu so the user can reselect it instead of rebuilding it.
#ClearStart_Desc: Standard Development View #ClearStart_Subst: RELEASE = `getRelease` #ClearStart_Subst: BRANCH = `getBranch` element * CHECKEDOUT element * /main/[:BRANCH:]/LATEST element * [:RELEASE:] -mkbranch [:BRANCH:]
In order to do this, we simply add another "ClearStart_Desc:" directive to describe the view once it is built. That way, the template has one menu description while the view has another one.
Now we have two #ClearStart_Desc: directives. The top line will be displayed before the view is created. The second one on line #4 will be used when the view is actually created. Notice that [:BRANCH:] and [:RELEASE:] variables are used to help with the description. Now the question is how does ClearStart know which description to use.
#ClearStart_Desc: Standard Development View #ClearStart_Subst: RELEASE = `getRelease` #ClearStart_Subst: BRANCH = `getBranch` #ClearStart_Desc: Branch [:BRANCH:] Dev View based on [:RELEASE:] element * CHECKEDOUT element * /main/[:BRANCH:]/LATEST element * [:RELEASE:] -mkbranch [:BRANCH:]
ClearStart always uses the first #ClearStart_Desc: directive. In order to use the other ClearStart_Desc: directive, we will have to cut out the original ClearStart_Desc: when the view is created. ClearStart provides another directive called #ClearStart_Begin_Templeate: to handle this problem. When the actual view is created from the template, the actual view's ConfigSpec starts right after the #ClearStart_Begin_Template: line. All we have to do is place this line right before the second #ClearStart_Desc: directive:
Now, when the user runs ClearStart, they get a menu showing all created views for that user and all templates that user could use to build other views. One of the items on the menu is called "Standard Development View". The user chooses that selection, and (via the getRelease and getBranch shell scripts) is then asked for the branch and the release that view will be based upon.
#ClearStart_Desc: Standard Development View #ClearStart_Subst: RELEASE = `getRelease` #ClearStart_Subst: BRANCH = `getBranch` #ClearStart_Begin_Template: #ClearStart_Desc: Branch [:BRANCH:] Dev View based on [:RELEASE:] element * CHECKEDOUT element * /main/[:BRANCH:]/LATEST element * [:RELEASE:] -mkbranch [:BRANCH:]
When the user finishes answering these questions, a new view is created, and that view is set. When the user wishes to use that same view over, the user selects "Branch davidw-task1" Dev View based on INT-REL-1.3.44" from the menu, and uses that view.
One final problem remains. What is the ACTUAL name for this view? ClearCase views all have a view tag, but so far we have glossed over the discussion of where ClearStart views get their names. ClearStart Templates are stored under the $CLEARSTART_HOME directory. I usually make this the clearstart directory in my ClearCase Administrative user's HOME directory. The template is a text file with a name. For example, we will call template this "std_dev", and store it in $CCENV_HOME/clearstart/config/std_dev.
The views themselves take the template's name, and prefix the user id. This allows different users to have different views. For example, the name of the created view from "std_dev" would be "davidw__std_dev" for this user. This way, each user could have their own view tag:
This works out well for templates that do not use variable substitution. For example, I might have a standard "Default View":
tom__std_dev dick__std_dev harry__std_dev davidw__std_dev
Unfortunately, it is possible for a single user to have multiple views based upon this one template. In order to get around this problem, ClearStart appends to the template's name some information that would make this view unique for this user. For example, since this user specified the branch name and the release, these could be appended to the template's name:
#ClearStart_Desc: Default View element * CHECKEDOUT element * /main/LATEST
Yes, these view names get very long, but remember that you are selecting them from a menu via a description, and not via the view's actual name. Under ClearStart, you will never be typing something like this:
davidw__std_dev__davidw-task1_INT-REL-1.3.44 davidw__std_dev__davidw-task1_INT-REL-1.4.01 davidw__std_dev__davidw-task2_INT-REL-1.3.44 davidw__std_dev__davidw-task3_INT-REL-1.3.44
The last thing we need to do is to tell the template what to call our view when the template is completed. To do this, ClearStart uses a special ClearStart directive called NAME. Whatever the value of Name, it will be appended to the template's name. Therefore, it is important for you to verify that your NAME variable will insure unique view names. According to our naming scheme, the NAME variable will be [:BRANCH:]-[:RELEASE:]. It could have very easily been [:RELEASE:]-[:BRANCH:] too. Now our view template looks like this:$cleartool setview davidw__std_dev__davidw-task3_INT-REL-1.3.44
This is a completed ClearStart view template. If you used the "env" and "environment" files from this site, you could place this template under $CCENV_HOME/clearstart/config, plus the two shell scripts getRelease and getBranch under $CCENV_HOME/bin and play around with with this template. You could also use this template for other types of development views. Here is a favorite of mine:
#ClearStart_Desc: Standard Development View #ClearStart_Subst: RELEASE = `getRelease` #ClearStart_Subst: BRANCH = `getBranch` #ClearStart_Subst: NAME = [:BRANCH:]-[:RELEASE:] #ClearStart_Begin_Template: #ClearStart_Desc: Branch [:BRANCH:] Dev View based on [:RELEASE:] element * CHECKEDOUT element * /main/[:BRANCH:]/LATEST element * [:RELEASE:] -mkbranch [:BRANCH:]
Here, I am using the Unix date program to produce a date in the form of dd-mmm-yyyy. This means, when a view is created, I use the date the view was created to create a stable time based view for development work. Testing templates are much simpler:
#ClearStart_Desc: Standard Development View #ClearStart_Subst: DATE = `date "+%m-%h-19%y"` #ClearStart_Subst: BRANCH = `getBranch` #ClearStart_Subst: NAME = [:BRANCH:]-[:DATE:] #ClearStart_Begin_Template: #ClearStart_Desc: Branch [:BRANCH:] Dev View as of [:DATE:] element * CHECKEDOUT element * /main/[:BRANCH:]/LATEST time [:DATE:] element * /main/{STATUS=="APPROVED"} -mkbranch [:BRANCH:]
Sometimes, because some testers are not very technical, I will simply create a ClearStart Template without any variables. That way, the tester can select the view from the ClearStart menu without having to answer any questions:
#ClearStart_Desc: Testing View #ClearStart_Subst: RELEASE = `getRelease` #ClearStart_Subst: NAME = [:RELEASE:] #ClearStart_Begin_Template: #ClearStart_Desc: Testing Release [:RELEASE:] element * [:RELEASE:] -nocheckout
#ClearStart_Desc: Testing Internal Release 3.1.44 element * INT_REL_3.1.44
The first TMode is a ClearStart directive stating the "TMODE" of the view. Whether this is a MSDOS view or an Unix view. Normally, I make this 'unix' by default, but in mixed environments, you probably want to set $OSSYS to represent the text mode of your view. I also set up a directory where I store all views so that views will be stored outside of the user's HOME directory. This is set in my "env" file.
#ClearStart_TMode: "$CCENV_OSSYS" #ClearStart_ViewStore: "$CCENV_VIEWDIR"
Another thing I will add to all templates is the "#ClearStart_Obsolete:" directive. This is set to "0" which means that the template isn't obsolete. However, this makes it easy for a user to "Obsolete" their views by simply changing this from "0" to "1". A simple shell script could do this. Basically, an obsolete view won't normally show up in a ClearStart menu so ClearStart menus are not full of views that the user no longer uses. So my ClearStart "Standard Development Template" might looks something like this:
#ClearStart_Desc: Standard Development View #ClearStart_Obsolete: 0 #ClearStart_Subst: RELEASE = `getRelease` #ClearStart_Subst: BRANCH = `getBranch` #ClearStart_Subst: NAME = [:BRANCH:]-[:RELEASE:] #ClearStart_Begin_Template: #ClearStart_Desc: Branch [:BRANCH:] Dev View based on [:RELEASE:] element * CHECKEDOUT element * /main/[:BRANCH:]/LATEST element * [:RELEASE:] -mkbranch [:BRANCH:]
Also remember that ClearStart sorts it's menu by the View Template file name. You might want to keep this in mind when you name your view templates. Try to keep the more used ones earlier in the alphabet so they show up on top. Also name your views in such a way that all the views that are similar are together in the menu. For example, release views are together and programming views are together.