QVCS-Enterprise Ant Task

Introduction

Since a Java-based command line tool could be very slow because it would require the loading of the JVM for each separate version control operation, we have chosen to supply command line like behavior for the QVCS-Enterprise product via a custom ant task.

The QVCS-Enterprise custom ant task allows the user of ant to:

  • Get the latest revisions of a directory tree, a single directory, or a single file from the QVCS-Enterprise Server.
  • Get a labeled set of revisions in a directory tree, a single directory, or a single file from the QVCS-Enterprise Server.
  • Apply a label to the files within a directory tree, a single directory, or a single file.
  • Check in your changes for an entire directory tree, a single directory, or a single file. Only files that you have changed will get checked in.
  • Check in your changes for an entire directory tree, a single directory, or a single file. Only files that you have changed will get checked in.
  • Check out all the files for an entire directory tree, a single directory, or just a single file.
  • Lock all the files for an entire directory tree, a single directory, or just a single file.
  • Unlock all the files that you have locked in a directory tree, in a single directory, or just a single file.

The QVCS-Enterprise custom ant task has been tested with ant version 1.7.0 and ant version 1.6.1. You can go to the Apache ant web site to download your copy of ant.

QVCS Custom Ant Task

The qvcs custom ant task is contained in the gui_out.jar file. It uses attributes that you define in your ant build.xml file to control the behavior that it will supply.

AttributeDescriptionRequiredDefault Value
operationThis can have the value of:
  • get
  • label
  • checkin
  • checkout
  • lock
  • unlock
If not specified, it defaults to "get". This attribute identifies the kind of operation that you want to perform.
Noget
userDirectoryThe local directory where you have installed the QVCS-Enterprise client. The gui_out.jar file should be located in this directory.YesNone
serverNameThis is the name of the QVCS-Enterprise server that manages the QVCS archives that you want to work with. There should be a corresponding server properties file located in the qvcsProjectProperties subdirectory. The server properties file name will look like: qvcs.servername.serverName.properties, where serverName is replaced with the value you define here.YesNone
projectNameThe name of the project on serverName that you wish to operate on.YesNone
viewNameThe name of the view within the project that you wish to operate on. If not defined, this defaults to the Trunk. Not all operations are supported on all possible view types. For example, a checkout operation will fail for a read-only view.NoTrunk
appendedPathThis is the name of the relative directory within the project that will serve as the root directory for the QVCS operation. If you want to operate over the entire project directory hierarchy, use a value of "". If the recurseFlag is true (the default value), the requested operation will apply to the selected directory and all view sub-directories that are beneath the directory identified by appendedPath.YesNone
userNameThe QVCS-Enterprise user name that you use to login to the server you identify via the serverName attribute.YesNone
passwordThe password for userName that you use to login to the serverName.YesNone
workfileLocationDefines the location of the workfiles for this operation. If the operation is a "get", "checkout", or "checkin" operation, then this attribute is required. Get, checkout and checkin operations should make sure to use the same value for the workfile location so that the ant task can compute a meaningful file status. If the operation is a "label", "lock", or "unlock" operation, then the attribute is not required and is ignored.MaybeNone
label
  • For "get", "checkout", and "lock" operations, this label attribute is optional. If defined, it identifies the revision that will be operated upon. For example, a "get" operation that defines the label attribute will become a 'get by label' type of get operation, where only those revisions associated with the provided label will be retrieved.
  • For "label" operations, the value of the label attribute identifies the label string that will be applied.
  • For "checkin" operations, the value of the label attribute identifies the label string that will applied to the new revision that is checked in.
  • For "unlock" operations, this attribute is ignored.
MaybeNone
duplicateLabelThis attribute is used for "label" operations only. It defines the existing label that should be duplicated. If an archive has a label that matches the duplicateLabel string, then the string value defined by the label attribute will get applied to the archive, and the new label defined by label attribute will point to exactly the same revision that the existing label defined by this duplicateLabel attribute points to. If this existing label defined by the duplicateLabel attribute is a floating label, then the label defined by the label attribute will point to the newest revision on the branch associated with the floating label. (This is usually the tip revision of the 'trunk').MaybeNone
checkInCommentThis attribute is used for the "checkin" operation. It defines the check in comment that will be used and is required for the "checkin" operation.MaybeNone
fileNameThis attribute is used for all operations. It defines the filename that the operation should be performed on. Set this attribute if you want your operation to be applied to just one file. The operation will be performed on any file that exactly matches this filename across all the directories that are included in the operation. In order to operate on just one file, you should make sure to set the recurseFlag to false, and use the appendedPath attribute to identify the specific directory that contains the file that you want to operate on. If you leave this attribute undefined, then the operation will be performed on all files. Note that the fileExtension attribute is evaluated before the fileName attribute. This means that you could specify a fileExtension and fileName combination that would result in no files being operated on. For example, if you specified a fileExtension of "java" and specified a fileName of "readme.txt", then no files would be operated on.No""
fileExtensionThis attribute is used for all operations. It defines the case insensitive file extension for the type of files the operation should be performed on. For example, to operate on just .java files, the value for fileExtension should be set to "java". The default value for the fileExtension attribute is "*" which matches all file types. To match files that have no file extension, use a value of "". To match files that end in the '.' character, use a value of ".".No"*"
duplicateLabelFlagThis flag is used for "label" operations only. It indicates whether an existing label should be duplicated. Possible values are "true" or "false". If this flag is "true", then the duplicateLabel attribute must be defined.Nofalse
floatingLabelFlagThis flag is used for "label" and "checkin" operations. It indicates whether the label being applied should be a 'floating' label. If this flag is "true", then the applied label will be set as a 'floating' label (a 'floating' label always is associated with the tip revision and is useful way to identify a set of files).Nofalse
overWriteFlagThis flag is used for "get" operations only. It indicates whether the get operation will overwrite any writable files. The default value is "false".Nofalse
recurseFlagThis flag is used for all operations. It indicates whether the operation will apply only to the directory defined by the appendedPath attribute, or if it should also apply to the entire directory tree beneath the directory identified by appendedPath.Notrue
reuseLabelFlagThis flag is used for "label" and "checkin" operations. It indicates whether an existing label can be reassigned to a different revision.Nofalse

Defining the qvcs custom ant task

In order for your ant build file to make use of the qvcs custom ant task, you must make it accessible to the ant utility. This is typically done by including a snippet of xml at the beginning of your build.xml file that looks like:

  <!-- =================================================================== -->
  <!-- Define the QVCS custom ant task                                     -->
  <!-- =================================================================== -->
  <taskdef name="qvcs" 
        classpath="${classpath};${basedir}/ant.jar;${basedir}/gui_out.jar"
        classname="com.qumasoft.qvcslib.QVCSAntTask"/>

The important items above are to define the location of the gui_out.jar file so that it is included in your classpath and to define the class of the QVCS ant task accurately. The ant documentation describes other strategies that you can use to make a custom ant task accessible to your instance of ant.

Some helper targets

In the Examples section below, we make use of several helper targets.


Here is a helper target that asks the user for their password. This is handy so you won't have to hard-code your password within your build.xml file.

  <!-- =================================================================== -->
  <!-- Ask user for their QVCS Password                                    -->
  <!-- =================================================================== -->
  <target name="getPassword">
        <input message="Please enter QVCS password:" 
           addproperty="qvcs.password"/>
  </target>

Here is a helper target that asks the user for the QVCS install directory. The QVCS-Enterprise install directory will contain the gui_out.jar file and it will have the qvcsProjectProperties subdirectory which contains any server definitions.

  <!-- =================================================================== -->
  <!-- Ask user for the location where QVCS-Enterprise is installed.       -->
  <!-- =================================================================== -->
  <target name="getInstallDir">
        <input message="Please enter the QVCS install directory:" 
           addproperty="qvcs.installDir"/>
  </target>

This helper task asks the user for the name of the QVCS-Enterprise server that they want to use. The name should be of an existing server.

  <!-- =================================================================== -->
  <!-- Ask user for the name of the QVCS-Enterprise server                 -->
  <!-- =================================================================== -->
  <target name="getServerName">
        <input message="Please enter the name of the QVCS-Enterprise server:" 
           addproperty="qvcs.serverName"/>
  </target>

This helper target asks the user for the label string to use for 'get by label' operations or for labeling operations.

  <!-- =================================================================== -->
  <!-- Ask user for a label string.                                        -->
  <!-- =================================================================== -->
  <target name="getLabel">
        <input message="Please enter QVCS label:" 
           addproperty="qvcs.label"/>
  </target>

This helper target asks the user for the name of the file to operate on.

  <!-- =================================================================== -->
  <!-- Ask user for a file name.                                           -->
  <!-- =================================================================== -->
  <target name="getFileName">
        <input message="Please enter the name of the file to work on:" 
           addproperty="qvcs.fileName"/>
  </target>

This helper target asks the user for a checkin comment.

  <!-- =================================================================== -->
  <!-- Ask user for checkin comment.                                       -->
  <!-- =================================================================== -->
  <target name="getCheckInComment">
        <input message="Please enter the checkin comment:" 
           addproperty="qvcs.checkInComment"/>
  </target>


Examples


Use the "get" operation to get all the files of a project:

Getting the latest revision of all the files for a project (overwriting any existing files) scan be accomplished using an xml snippet that looks like this:

  <!-- =================================================================== -->
  <!-- Get the latest revision for all project files                       -->
  <!-- =================================================================== -->
  <target name="GetTipRevisions"
          depends="getPassword,getInstallDir,getServerName"
          description="Get the latest files from the QVCS-Enterprise Server.">
        <qvcs userDirectory="${qvcs.installDir}"
              serverName="${qvcs.serverName}"
              userName="Your QVCS-Enterprise Username"
              password="${qvcs.password}"
              projectName="name of the project you want to work on"
              viewName="name of the view you want to work on"
              appendedPath=""
              workfileLocation="the local workfile directory"
              overWriteFlag="true"
              operation="get">
        </qvcs>

  </target>

Run ant using the GetTipRevisions target:

ant GetTipRevisions

will cause the following output to appear:

  GetTipRevisions:
       [qvcs] User directory: Your install directory
       [qvcs] Server name: server name
       [qvcs] User name: user name
       [qvcs] User password: ********
       [qvcs] Project name: project name
       [qvcs] View name: view name
       [qvcs] Appended path:
       [qvcs] Workfile location: workfile location
       [qvcs] Operation: get
       [qvcs] Label:
       [qvcs] Recurse flag: true
       [qvcs] File name:
       [qvcs] File extension: *
       [qvcs] OverWrite Flag: true or false
       [qvcs] Getting project list from server...
       [qvcs] Basedir: 'the ant base directory for this build file'
       [qvcs] Workfile canonical location: 'the workfile location canonical path'
       [qvcs] Getting directory list from server...
       [qvcs] Getting file list from server...
       [qvcs] Performing requested operation...

       ... numerous log messages ...
       
       [qvcs] Performed some count operations
       [qvcs] Logged off server

  BUILD SUCCESSFUL
  Total time: some number seconds


Use the "get" operation to get files by label:

The following example gets all the revisions of a project that are labeled with the provided label string. If an archive is not labeled, no revisions from that archive will be retrieved. This is a useful target for performing builds of past labeled products.

  <!-- =================================================================== -->
  <!-- Get by label for all project files                                  -->
  <!-- =================================================================== -->
  <target name="GetByLabel" 
          depends="getPassword,getLabel,getInstallDir,getServerName" 
          description="Get by label from the Production Server.">
      <qvcs userDirectory="${qvcs.installDir}"
            serverName="${qvcs.serverName}"
            userName="Your QVCS-Enterprise Username"
            password="${qvcs.password}"
            projectName="name of the project you want to work on"
            viewName="name of the view you want to work on"
            appendedPath=""
            operation="get"
            workfileLocation="the local workfile directory where results will go."
            overWriteFlag="true"
            label="${qvcs.label}">
      </qvcs>

  </target>


Use the "label" operation to label the files of a project:

The following example applies a label to the tip revisions of all the files in the project.

  <!-- =================================================================== -->
  <!-- Apply label to all project files                                    -->
  <!-- =================================================================== -->

  <target name="ApplyLabel" 
          depends="getPassword,getLabel,getInstallDir,getServerName" 
          description="Apply a label.">
      <qvcs userDirectory="${qvcs.installDir}"
            serverName="${qvcs.serverName}"
            userName="Your QVCS-Enterprise Username"
            password="${qvcs.password}"
            projectName="name of the project you want to work on"
            appendedPath=""
            workfileLocation=""
            operation="label"
            label="${qvcs.label}">
      </qvcs>
  </target>

Notice that for 'label' operations, you don't need to specify a meaningful value for the workfile location. For label operations, the workfile location is ignored.


Use the "label" operation to duplicate a label:

The following example duplicates a label. This is a useful thing to do as a prelude to creating a labeled release of your product if the label that you are duplicating is a floating label that identifies the set of files that compose the product.

  <!-- =================================================================== -->
  <!-- Duplicate a label                                                   -->
  <!-- =================================================================== -->
  <target name="ApplyLabel" 
          depends="getPassword,getLabel,getInstallDir,getServerName" 
          description="Duplicate a label.">
      <qvcs userDirectory="${qvcs.installDir}"
            serverName="${qvcs.serverName}"
            userName="Your QVCS-Enterprise Username"
            password="${qvcs.password}"
            projectName="name of the project you want to work on"
            appendedPath=""
            workfileLocation=""
            operation="label"
            reuseLabelFlag="true"
            duplicateLabelFlag="true"
            duplicateLabel="The existing label that you are duplicating"
            label="${qvcs.label}">
      </qvcs>
  </target>

Notice that the reuseLabelFlag is set to true. This means that if the label that you are applying already exists, then this label operation will move the current existing label so that the label will be associated with the revision currently associated with the label that is being duplicated. (When duplicating floating labels, QVCS always creates a non-floating label that points to the same revision that the floating label points to at the time that the duplicate label is applied).


Use the "checkin" operation to checkin all your changes in a project:

The following example checks in all your changes for an entire project directory tree.

  <!-- =================================================================== -->
  <!-- Checkin all your changes                                            -->
  <!-- =================================================================== -->
  <target name="CheckInAllChanges" 
          depends="getPassword,getInstallDir,getServerName" 
          description="Checkin all changes for a project.">
      <qvcs userDirectory="${qvcs.installDir}"
            serverName="${qvcs.serverName}"
            userName="Your QVCS-Enterprise Username"
            password="${qvcs.password}"
            projectName="name of the project you want to work on"
            viewName="Trunk"
            appendedPath=""
            workfileLocation="the local workfile directory"
            operation="checkin"
            checkInComment="Your checkin comment"
      </qvcs>
  </target>

The snippet above will check in all your changed files for the given project/view from the given workfile tree. Files that have a status of 'Your copy changed' will be checked in if you have checked the file out, or if the file does not require a lock. Files that are 'Different' or 'Merge required' will not be checked in. To make sure that you have a useful file status, you need to make sure that the workfile location you use for the checkin operation matches the workfile location you earlier used for a get and/or checkout operation. Files that you have locked that have a status of 'Current' will be unlocked.


Use the "checkin" operation to checkin all your changes in a project for files with a given file extension:

The following example checks in all your changes to .java files for an entire project directory tree.

  <!-- =================================================================== -->
  <!-- Checkin all your changes to .java files                             -->
  <!-- =================================================================== -->
  <target name="CheckInAllChanges" 
          depends="getPassword,getInstallDir,getServerName" 
          description="Checkin all changes for a project.">
      <qvcs userDirectory="${qvcs.installDir}"
            serverName="${qvcs.serverName}"
            userName="Your QVCS-Enterprise Username"
            password="${qvcs.password}"
            projectName="name of the project you want to work on"
            viewName="Trunk"
            appendedPath=""
            workfileLocation="the local workfile directory"
            operation="checkin"
            checkInComment="Your checkin comment"
            fileExtension="java"
      </qvcs>
  </target>

The snippet above will check in all your changed .java files for the given project/view from the given workfile tree. .java files that have a status of 'Your copy changed' will be checked in if you have checked the file out, or if the .java file does not require a lock. .java files that are 'Different' or 'Merge required' will not be checked in.


Use the "checkin" operation to checkin your changes to a single file in a single directory:

The following example checks in the changes you made to a single file in the root directory of project.

  <!-- =================================================================== -->
  <!-- Checkin all your changes to a specific file.                        -->
  <!-- =================================================================== -->
  <target name="CheckInFileChange" 
          depends="getPassword,getInstallDir,getServerName,getFileName,getCheckInComment" 
          description="Checkin changes for a single file.">
      <qvcs userDirectory="${qvcs.installDir}"
            serverName="${qvcs.serverName}"
            userName="Your QVCS-Enterprise Username"
            password="${qvcs.password}"
            projectName="name of the project you want to work on"
            viewName="Trunk"
            appendedPath=""
            workfileLocation="the local workfile directory"
            operation="checkin"
            checkInComment="${qvcs.checkInComment}"
            fileName="${qvcs.fileName}"
            recurseFlag="false"
      </qvcs>
  </target>

The snippet above will check in your changes to the given file. A checkin will occur only if the given file has a status of 'Your copy changed' and you have checked the file out, or if the file does not require a lock. If the file's status is 'Different' or 'Merge required' it will not be checked in.


Use the "checkout" operation to checkout all the files in a single directory:

The following example checks out all the files in the root directory of the trunk view of a project.

  <!-- =================================================================== -->
  <!-- Checkout all the files in the root directory of the trunk.          -->
  <!-- =================================================================== -->
  <target name="CheckOutRootDirectory" 
          depends="getPassword,getInstallDir,getServerName" 
          description="Checkout all files in root directory.">
      <qvcs userDirectory="${qvcs.installDir}"
            serverName="${qvcs.serverName}"
            userName="Your QVCS-Enterprise Username"
            password="${qvcs.password}"
            projectName="name of the project you want to work on"
            viewName="Trunk"
            appendedPath=""
            workfileLocation="the local workfile directory"
            operation="checkout"
            recurseFlag="false"
      </qvcs>
  </target>

The snippet above will check out all the files in the root directory of the trunk view of the given project.