Integrating
with Version Control Systems
Source-Navigator provides a
graphical user interface to version control systems. Cygnus Solutions has
performed product integrations with a number of popular version control
packages such as the GNU Revision Control System (RCS), Concurrent Versions
System (CVS), the Source Code Control System (SCCS), and Rational's ClearCase.
Source-Navigator's user interface
provides the user with a standard set of version control operations. The
software development kit (SDK) allows third parties to integrate version
control packages so that some or all of these operations can be performed
from within Source-Navigator. This chapter assumes a basic understanding
of the Tcl programming language and familiarity with the version control
system that is to be integrated with Source-Navigator.
Basics
The version control interface
in Source-Navigator assumes that there is a basic set of version control
operations in the context of source code comprehension:
-
obtaining different versions of a source file
from a repository or archive maintained by the version control system.
This operation will be referred to as a check-out.
-
examining the differences between the current
working version of a source file and another version held under version
control. This operation will be referred to as a diff.
-
making changes to the most current version of
a file and placing those changes under version control. This operation
will be referred to as a check-in.
-
deleting versions from the repository.
-
acquiring exclusive access to a particular version
of a file so that no other developer can make changes to that version.
This operation will be referred to as locking.
-
relinquishing exclusive access to a particular
version of a file so that other developers may make modifications. This
operation will be referred to as unlocking.
-
discarding any changes to the current working
version and reverting to the most recent version in the repository.
-
obtaining the history of a file from the version
control system. This includes:
-
descriptive text about the changes made for
each version.
-
a list of symbolic names for the versions associated
with a file. In GNU RCS, for example, these names are known as
tags.
Version Control Operations
Source-Navigator takes a universal
approach to interfacing with external version control systems: each operation
is performed by executing a particular command line and capturing the output
from that command.
For some operations, the output
of the command is significant and only information relevant to the user
must be extracted from the output. Examples of this include obtaining a
history of changes made to a file, obtaining the names of symbolic tags,
and obtaining all of the version numbers associated with a file. The Source-Navigator
SDK provides a mechanism based on Tcl regular expressions for extracting
the relevant text from command output.
The Configuration File
The Source-Navigator configuration
file,
.../share/etc/sn_prop.cfg , is read at start-up and can
be used to customize Source-Navigator. In particular, new version control
systems may be integrated from within this file. New systems are added
by calling a Tcl procedure called
sn_add_version_control_system.
The signature of this procedure
is:
sn_add_version_control_system
{ident args}
ident
is an internal identifier used by Source-Navigator. This should be a logical
derivation of the name of the version control system and consist only of
alphanumeric characters and start with an alphabetic character. Examples
are:
rcs
cvs
ccase3
args
is a variable number of arguments and may be any of the options described
in the
Options section,
followed by a suitable value. For example:
-checkout co
Options
For options that have simple
values, the possible values are outlined and the default is given. If this
default value is satisfactory, the option may be omitted from the call.
For options that specify
command lines, the usage of the command is shown. If the option is not
applicable to a particular command, omitting it from the call is permissible,
but may result in some version control operations being unavailable to
the user.
Using the
-checkout
example in
-checkout, the
checkout command line will be illustrated in the following notation:
${checkout} filename
At runtime, the command line
that is executed might be:
co main.c
args may be
any of the following options:
-checkin
This specifies
the command line to check a modified file back into the repository.
${checkin} filenameor:
${checkin} comment-text filenames or:
${checkin} comment-filename filenames
Which of these
command lines will be used depends on the value of
-checkin-comment-via.
-checkin-comment-via
This option specifies
how comments about changes made to a file must be passed to the
-checkin
command. The three possible values are:
|
The comment is issued
on the checkin command's standard input.
|
|
The command is placed
into a temporary file and the filename is passed on the command line prior
to the names of source files.
|
|
The comment is placed
on the command line prior to the filename(s).
|
This option specifies
the command line to check a file into the repository and to acquire a lock
once the check-in is complete. This is useful when you want to make successive
changes to a file.
{$checkin-exclusive} filenames
This option specifies
the command line to check out the latest version of a file from the repository.
${checkout} filenames
This option specifies
the command line to check out the latest version of a file from the repository
with exclusive access that prevents other developers from modifying the
file. Some version control systems require that a file be checked out exclusively
before a modified version of it may be checked in.
${checkout-exclusive} filenames
This option specifies
the command line to check out a particular version of a file from the repository.
${checkout-individual} version-num filenames
-checkout-individual-to-stdout
This option specifies
the command line to check out a particular version of a file from the repository
and echo the contents to the standard output.
${checkout-individual-to-stdout} version-num filenames
If this option
is set to
yes, then checkout operations will by default attempt
to acquire a lock to prevent other developers from making concurrent modifications.
This option determines whether the
with lock check button
is initially set in the
Checkout dialog box.
If this option
is set to
yes, then this version control system entry will be
the default for new projects. If this option is set to
yes for
more than one entry in the configuration file, then the entry which appears
last in the file will be the default.
This option specifies
the command line to delete a particular version of a file from the repository.
${delete-revision} version-num filename
This option specifies
the name of the command used to compare two files (or two versions of the
same file).
diff
This option specifies
any additional command line options to the
diff command to cause
it to perform case insensitive comparisons. For almost all implementations
of the traditional
diff command, this will be
-i.
-i
This option specifies
any additional command line options to the
diff command to cause
it to perform comparisons that are insensitive to whitespace. For almost
all implementations of the traditional
diff command, this will
be
-w.
-w
This option specifies
a command line to discard any modifications made to the working version
of a file and revert it to the current version in the repository.
${discard} filenames
This option specifies
a command line to retrieve the history of a file. Typically this includes
comments made by developers at each version of the file, the set of version
numbers for the file and the time and date of each change.
${history} filename
This option specifies
a pattern to extract the version history from the output of
${history}.
It should extract all the relevant information about all versions of a
file. See
Patterns for more
detailed information about possible values for this option.
None.
This option specifies
the command to retrieve the history for a particular version of a file.
${history-individual} version-num filename
-history-individual-pattern
This option specifies
a pattern to extract the version history from the output of
${history-individual}.
It should extract all the relevant information about the particular revision
of a file.
None.
This option specifies
a set of textual replacements to perform on text extracted by the patterns
${history-pattern}
and
${history-individual-pattern}. This allows text to be manipulated
so that it may be cosmetically improved before being shown in the
History
window.
See
Replacements
for details about possible values for this option.
None.
This option specifies
one or more directories to ignore when presenting directory trees to the
user. Such directories may include a repository subdirectory for each directory
maintained by the version control system. When specifying more than one
subdirectory, use the Tcl list notation. For example:
{foo bar}
None.
This option specifies
the command line to lock a file such that no other developer may make concurrent
modifications.
${lock} filename
This option specifies
the command line to lock a particular version of a file such that no other
developer may make concurrent modifications to that version of the file.
${lock-individual} version-num filename
This option specifies
a pattern to extract all of the available revision numbers from the output
of the
${history} command.
None.
This option specifies
a pattern to extract the names of a file's symbolic tags from the output
of the
${history} command.
None.
-symbolic-tags-replacements
This option specifies
a set of textual replacements to perform on text that is extracted by the
${symbolic-tags-pattern}
option. This allows text to be manipulated so that it may be cosmetically
improved before being shown in the
Symbolic tags window.
None.
This option specifies
a descriptive label that will be presented to the user in the project preferences
window. This option is useful for showing a mixed-case product name or
one that contains whitespace.
the ident parameter (in upper-case).
This option specifies
the command line needed to unlock a file so that other developers may make
concurrent modifications.
${unlock} filename
This specifies
the command line to unlock a particular version of a file so that other
developers may make concurrent modifications to that version of the file.
${unlock-individual} version-num filename
Patterns
Patterns are used to extract
text resulting from certain version control commands. It is necessary to
use patterns to filter relevant lines of text from the output.
A pattern is specified as
either:
A list of regular expression pairs specifying
where to start and stop extracting text. The two keywords start
and end are reserved and refer to the start and end of the body
of text respectively, or
An atomic regular expression specifying lines
that will be extracted if the regular expression matches any text in the
line.
Some examples of patterns
are:
Extract the names
of all the directories in
ls -l output:
^d
(an atomic regular expression)
Extract the names
of all the files and directories in
ls -al output, but exclude
the current and parent directories ("." and ".."):
{ {
" .. " end} } (a list of 1 regular expression pair)
More sophisticated
examples exist in the configuration example in Example.
Replacements
Replacements may be used to
modify or delete text that is extracted from the result of certain version
control commands.
Where replacements are mentioned
in the option descriptions above, legal values are a list of zero or more
pairs. A pair is defined to be a list of exactly two elements. The left-hand
side of the pair is a Tcl regular expression and the right-hand side is
a literal string to replace the text matched by the regular expression.
An example of a replacement
list is:
{ {"\t" " "} {"foo" "bar"} {"^-+$" ""} }
When applied to output from
a version control command, this would cause:
-
tabs to be replaced by spaces.
-
all occurrences of foo to be replaced
by bar .
-
separation lines consisting of hyphens to be
replaced by a blank line.
Scripts
Situations may arise in which
a version control system will seem incompatible with Source-Navigator's
approach to constructing command lines and examining the output of the
command.
In most cases, these issues
are overcome by writing shell scripts that provide a wrapper interface
that Source-Navigator works with, but internally issues commands that work
with the version control system.
Consider a version control
system that does not adhere to the convention of specifying the version
number of a file prior to the filename on the command line. Systems such
as RCS would expect a command line such as:
co -r1.5 main.c
But other systems might expect
a command line like:
foocs checkout main.c/1.5
This could be handled by writing
a small shell script that maps the command lines accordingly:
#!/bin/sh
foocs checkout $2/$1
You would then instruct Source-Navigator
to work via the shell script:
-checkout-individual "foocs-wrapper"
Shell scripts can also be
useful in situations where a particular operation requires more than one
command to be issued to the version control system.
Example
The following example is based
on the GNU RCS version control system, which many developers are familiar
with. Cygnus has integrated Source-Navigator with RCS and this configuration
example is taken directly from the
sn_prop.cfg configuration file.
# GNU Revision Control System (RCS)
sn_add_version_control_system rcs -default yes \
-checkin "ci" \
-checkin-comment-via stdin \
-checkin-exclusive "ci -l" \
-checkout "co -f" \
-checkout-exclusive "co -f -l" \
-checkout-individual "co -f -r" \
-checkout-individual-to-stdout "co -p" \
-checkout-with-lock yes \
-delete-revision "rcs -o" \
-discard "unco" \
-history "rlog" \
-history-pattern { {"^-----" "^====="} } \
-history-individual "rlog -r" \
-history-individual-pattern { {"^-----" "^====="} } \
-history-replacements { {"[ \t]+" " "} } \
-ignore-dirs RCS \
-lock "rcs -l" \
-lock-individual "rcs -l" \
-revision-number-pattern "^revision (\[0-9.\]+)" \
-symbolic-tags-pattern { {"^symbolic names" "^keyword"} } \
-symbolic-tags-replacements { {"\t" ""} } \
-unlock "rcs -u" \
-unlock-individual "rcs -u"