Previous section   Next section

7.3 Running Scripts

In the repository's CVSROOT directory, there are several scripting files that allow you to run scripts while a project is being committed, tagged, updated, or modified in other ways. The scripts called from scripting files are often used to interact with other programs or to enforce standards.

Example 7-6 shows a commitinfo scripting file that runs a layout-testing program called indent-tester on the wizzard project files. CVS calls scripts in commitinfo before files are committed.

Example 7-6. Sample commitinfo file
^wizzard/src\(/\|$\) /var/lib/cvs/CVSROOT/indent-tester -gnu

When a project file is committed, CVS searches the commitinfo file for rules that match the project file's path; if CVS finds a rule, it runs the script given in that rule. The rule in Example 7-6 matches all files in the src directory (and its subdirectories) of the wizzard project and tells CVS to run the indent-tester script on those files. Later in this chapter, Example 7-8 shows the indent-tester script that can be used to enforce indentation standards for a project.

CVS processes the scripting files separately for each directory that is affected by a command, and it calls the script in the scripting file once for each directory it matches. If you run cvs commit wizzard, CVS checks commitinfo for patterns that match wizzard and runs the script once for the files in the wizzard directory, then does the same for each subdirectory, checking for patterns that match wizzard/doc and processing its files, followed by wizzard/lib and wizzard/src.

7.3.1 Working with Scripting Files

The scripting files are all stored in your repository's CVSROOT directory. The purpose of each file is described in the section of this chapter named for that file. Most of these files use a common syntax.

Some files don't use the common syntax. In such cases, the syntax is described in the same section as the file.

The common syntax is rule-based, one line per rule, and each rule consists of a pattern to be matched and an action to be taken. When CVS reads a scripting file, it tries to match the pattern to project files. If the pattern matches, CVS runs the action. The action is usually a pathname to a script and parameters for that script. The common syntax is described in the next section.

To edit any of the scripting files, check out the file with the following command:

cvs -d repository_path checkout CVSROOT/filename

Edit the file with any text editor; then commit the file with cvs commit. CVS stores these files in the CVSROOT directory in plain-text and RCS formats and updates both types of files every time a file is committed.

You can also store the scripts you call from these files in your repository's CVSROOT directory or a subdirectory of CVSROOT. Add such scripts to the checkoutlist file in CVSROOT, so they are automatically exported to the CVSROOT directory when they're committed. The checkoutlist file is described in Chapter 6.

It is tempting to store scripts called by the scripting files in the project or module they are called for. Resist this temptation, as CVS then tries to call such a script when the script is itself being committed. Also be aware that if you store scripts in a project or module, they'll be stored on the repository machine in RCS format only; scripts can't be run from that format.

Do not attempt to interact with the user from scripts called from the scripting files. Some remote-access methods do not support such interaction at all, and other methods can be affected by having unexpected data go through their socket. Users other than the one involved in the interaction may also be left waiting on the first user until the interaction is complete.

If any script contains a CVS command, be aware that the command that calls the script will not finish until the script does. You may find that some directories have been locked by the original command, which can't finish and release them until the script is finished, but the script can't finish because the second command can't run until those same locks are released. This situation can be prevented by having your script call any CVS commands in the background or by simply calling the script in the background.

Scripts called from all files except the modules file are run on the computer that hosts the repository. Two of the modules scripts run on the sandbox computer; the others run on the repository computer.

If you do not provide a full path for a script, CVS searches the user's PATH environment variable. To prevent the wrong script from being called, I recommend using the full path in all scripting files.

Your repository administrator may limit your access to the scripting files for security reasons. Work with the repository administrator; you are asking for permission to run arbitrary scripts, so try to address her concerns.

7.3.2 Common Syntax

Most of the scripting files in CVSROOT -- including commitinfo, loginfo, editinfo, rcsinfo, and verifymsg � share a common syntax. The modules file does not use the common syntax.

Each line of a file using the common syntax should contain the following items:

name_pattern action

name_pattern should match a directory in the repository, and this pattern applies to all files in that directory. The pattern used is a regular expression, described in Chapter 11. The directory path that is tested against the pattern is the relative path, starting at the repository root directory.

action is a command-line template or the address of a script, plus any parameters required for that script or template. For most files, the script or the command must expect to read from the standard input (stdin). When CVS runs actions from some of the scripting files, it appends parameters to all actions run from those files. These parameters are often a list of the paths to the project files and metadata for copies of the project files that CVS has matched the rule to.

Lines in scripting files that start with the hash symbol (#) are comments, which CVS ignores.

When CVS processes a scripting file, it searches the scripting file from top to bottom and runs the action on the first line with a directory name pattern that matches the directory that contains the project file it is trying to match. CVS runs the script on the first matching rule and ignores other rules that match. In addition, if there are any ALL rules, CVS runs the scripts associated with them.

There are two special patterns, ALL and DEFAULT. A script designated with the ALL pattern is used on files in any directory, even if another line anywhere in the file matches the directory pattern. A script designated with the DEFAULT pattern is used if no other patterns (excluding ALL) match.

The actions in scripting files can use any of the variables CVS recognizes and expands. Chapter 6 explains variable expansion in administrative and scripting files.

7.3.3 The modules File

The modules file is used to define CVS modules. While a project is defined by the project root directory and contains all files and subdirectories, a module can be an arbitrary set of directories and files. Once a module is defined, the files and directories it describes can be checked out into a sandbox by either the module name or the name of the repository directory (or directories) it represents.

The modules file can also specify scripts to run when CVS acts on a file within a module.

Each module definition needs to be on a line of its own. When adding directories to module definitions, use relative paths from the repository root directory.

Example 7-7 shows a modules file. The lines in the file are explained in the following sections on module definition.

Example 7-7. CVSROOT/modules
# wizzard project. Project lead: jenn. Module type: regular.
wiz -s development wizzard
   
# singer project. Project lead: doppel. Module type: alias.
singer -a music/descant !chorus/tenor !chorus/bass chorus
   
# wizsinger project. Project lead: doppel. Module type: regular
wizsinger -i /var/lib/cvs/CVSROOT/export &wiz &singer
   
#wizmake project: retrieves just the Makefile from wizzard. 
wizmake wizzard Makefile
   
# wizhandheld project: retrieves just the handheld.c file.
wiztest wizzard/src handheld.c
7.3.3.1 Alias modules

An alias module can be used to group files and directories into a single module, regardless of where they are stored in the repository tree. The syntax for an alias module definition is:

module-name -a path [path...]

The path may be an existing module, a pathname to a file, or a directory path, and there may be any number of paths. If the path leads to a directory, the directory and all subdirectories and files are included in the module.

If you wish to exclude a subdirectory in an alias module, use an exclamation mark (!) in front of the directory name.

Alias modules cannot have options, nor can you specify scripts to run for them. If you need to use options or scripts, you can define an alias module as part of a regular module, or you can simply use a regular module instead.

Alias modules are easier to use than regular modules (described in the next section). You define alias modules with a space-separated list of all the items you want in the module, while regular modules have a more complicated syntax. You can also add multiple directories, files, and modules in an alias module; a regular module allows only one directory.

The singer project in Example 7-7 defines an alias module that includes all files and directories in the chorus directory, except those under the subdirectories tenor and bass. This project also includes the descant file from the music directory.

When you use an alias module's name in any CVS command, CVS treats the module name as if the list of items in the path were used instead. When you use an alias module in the checkout command, CVS creates a separate sandbox for each item in the path.

7.3.3.2 Regular modules

A regular module is used to define options for a project. It can also be used to define subsets of a project or to group modules together. If you have a particularly complex project, you may need to define your project with a combination of alias and regular modules.

Using alias modules in a complex definition allows you to add multiple directories with one alias, and the regular module allows you to define options to use when calling that module.

The syntax to define a regular module is:

module-name [options] [directory [filename|subdir...]] [&module...]

The directory should be a path relative to the repository root directory. If filenames or subdirectory names are included, they should refer to files or subdirectories in the directory. The module definition then applies only to those files or subdirectories. Note that you need a space between the directory and the files within the directory, and you can define only one directory within a regular module.

You can include an existing module in a regular module by prefixing the existing module name with an ampersand (&) and listing it in the regular module definition. The existing module can be an alias or a regular module. If it is not defined in the modules file, it must be a directory path relative to the repository's root directory. This rule is illustrated in the wizsinger module definition in Example 7-7, which includes two existing modules. The sequence of the module definitions doesn't matter; you can include a module in an earlier line than the module's own definition.

7.3.3.3 Module options and scripts

Most of the options for a regular module define scripts to run immediately after a CVS command on the files in the module. Here is the full list of options:

-d directory_name

Use directory_name rather than the module name as the name of the sandbox root directory.

-e script

Run the specified script whenever the module is exported. This script is given the module name as an argument.

-i script

Run the specified script whenever the module is committed. This script is given the full pathname of the relevant repository directory as an argument.

This option may be removed in CVS 1.11.6 and later, for security reasons.

-o script

Run the specified script whenever the module is checked out. This script is given the module name as an argument.

-s status

Provide a status for the module. This has no meaning internal to CVS, but when the command cvs checkout -s runs, the display output is sorted in ascending order by status. You can use the status string for anything; examples include the name of the person responsible for the module or whether the module is in active development.

CVS allocates an 11-character space for the status string when it is displayed, but the string is not truncated if it is longer than 11 characters.

-t script

Run the specified script whenever rtag is used on the module. This script does not run when tag is used. The taginfo file is a better way to run a script when files are tagged. This script is given two arguments: the module name and the name of the tag.

-u script

Run the specified script whenever the module is updated. This script is given the full pathname of the affected repository directory as an argument.

This option may be removed in CVS 1.11.6 and later, for security reasons.

The scripts designated in the modules file run after their respective processes have been completed.

If the repository is not on the same computer as the client, CVS stores the scripts for the -i and -u options in the Checkin.prog and Update.prog files in the CVS subdirectories in the sandbox. These scripts will run on the client computer. All other scripts called from the modules file run on the repository server computer.

The behavior of Checkin.prog and Update.prog will change in CVS 1.11.6 for security reasons. Check the documentation with your version of CVS for details.

The sandbox copies of the Checkin.prog and Update.prog files are not changed when the modules file or the repository computer's copies of the scripts are changed. If you change a module definition or the commit or update scripts for your project, you will need to have your users release and recreate their sandboxes.

7.3.4 The commitinfo File

The commitinfo file is processed before a file is committed and is usually used to enforce project standards for file format or content. It runs very early in the commit, during the tests to determine which files have changed.

commitinfo uses the syntax described in the Section 7.3.2 earlier in this chapter, with one rule per line and each rule consisting of the following elements:

name_pattern action

If a name_pattern matches the name and path of the directory or module parameter to cvs commit, CVS calls the action and appends as parameters the full path of the repository and the filenames of all files to be committed.

If you run cvs commit from a sandbox directory without specifying a project, CVS tries to match the repository path that corresponds to your current sandbox directory with a rule in commitinfo. If you run cvs commit with a file or directory parameter, CVS tries to match the repository path that corresponds to that parameter.

CVS makes a set of normal-format files from the data it receives from the CVS client and stores them in a temporary directory to allow the action to read a normal file rather than an RCS file. If CVS is running in client/server mode, the script or command in the action runs on the repository computer in a directory that is a copy of the sandbox directory being committed. If this script returns a nonzero value, the commit does not proceed. The script cannot change the file that is being checked; so, while you can use a layout-testing program, you cannot successfully use one that modifies the layout.

Example 7-8 shows an indentation tester that can be used with the commitinfo file in Example 7-6. Note that this tester assumes that all files it is called for can be tested validly with indent.

Example 7-8. Indentation tester
INDENTOPTS=$1
shift
while test "$1" != ""
  do
  FILENAME=$1
  TMPFILE="$TMP/id.$$"
  cat $FILENAME | indent $INDENTOPTS > $TMPFILE
  diff $FILENAME $TMPFILE 2>/dev/null >/dev/null
  if [ $? -ne 0 ]; then
    return 1
  shift
  done
return 0

7.3.5 The loginfo File

The loginfo file is processed after files have been committed to the repository. loginfo uses the syntax described in Section 7.3.2 of this chapter, with one rule per line and each rule consisting of the following elements:

name_pattern action

If a name_pattern matches the name and path of the directory parameter to cvs commit, CVS calls the action and passes it the log message from the commit on the standard input. CVS also passes the repository path being committed to, followed by an expanded format string. The action can consist of a script, a shell command, or a group of shell commands that will run as one command. If the repository is not on the same computer as the client, the script or command in the action runs on the repository computer.

The format string is stored in the loginfo file, and it controls the information that CVS passes to the script or command. The string consists of a %, followed by a space, a single variable, or a set of variables enclosed in braces ({ }). These are the variables:

s

Expands to the name of the current file being processed.

V

Expands to the file's revision number prior to the commit.

v

Expands to the file's revision number after the commit.

When CVS process the format string, the output is in the form:

"variable_expansion [variable_expansion...]"

The output includes a variable expansion for each file that was committed. The variable expansion is a comma-separated set of strings, such that %{sV} could be expanded to a string like main.c,1.3. Dollar signs ($), backticks (`), backslashes (\), and quotation marks (") in the repository path or filename are escaped with backslashes.

If you run cvs commit from a sandbox directory, CVS tries to match the repository path that corresponds to your current sandbox directory with a rule in loginfo. If you run cvs commit with a file or directory parameter, CVS tries to match the repository path that corresponds to that parameter.

The loginfo file is usually used to control where (aside from the repository) the log information from cvs commit is sent. It can also be used to trigger actions, such as notifying all developers of changes, maintaining a file that logs a record of changes, or exporting the changed files to a file server.

Example 7-9 shows a loginfo file that emails the log message for every change to the user cvsadmin. This file also runs the changelog script that is stored in CVSROOT for every file that is committed to the wizzard project. The line for the teppic project demonstrates a way to call an export script in the background.

Example 7-9. A loginfo file
^wizzard\(/\|$\) /var/lib/cvs/CVSROOT/changelog %{sv}
^teppic\(/\|$\) /var/lib/cvs/CVSROOT/export &
ALL mail -s "CVS commit" cvsadmin

7.3.6 The rcsinfo File

The rcsinfo file is processed before a file is committed. It uses the syntax described in Section 7.3.2 of this chapter. The action in each rule of an rcsinfo file should not be a path to a script; it should be a path to a template file that will be displayed when CVS asks the user for a log message during a cvs commit operation.

If you run cvs commit from a sandbox directory, CVS tries to match the repository path that corresponds to your current sandbox directory with a rule in rcsinfo. If you run cvs commit with a file, directory, or module parameter, CVS tries to match the repository path that corresponds to that parameter. The DEFAULT and ALL rules described in Section 7.3.2 are honored.

If CVS finds a match, it displays the contents of the template file when it opens an editor to receive a log message. If there is a matching rule and an ALL rule in rcsinfo, CVS displays the contents of the file each rule refers to (that is, it displays the contents of two files). Subject to any editing you do when you commit, the contents of the template file (or files) are stored as part of the log message.

If you use -m message or -f file as options to cvs commit, the rcsinfo file is ignored.

If CVS is running in client/server mode, it stores a copy of the template file in the Template file in the CVS subdirectory of the sandbox when the sandbox is checked out. This file is not updated with other sandbox files, so if the rcsinfo file or the templates it refers to are changed, your users should release and recreate their sandboxes.

7.3.7 The taginfo File

The taginfo file is processed before a file is tagged using either the tag or the rtag commands. taginfo uses the syntax described in Section 7.3.2 of this chapter, with one rule per line and each rule consisting of the following elements:

name_pattern action

If a name_pattern matches the name and path of the directory or module parameter to cvs tag or cvs rtag, CVS calls the script or command in the action and appends a parameter string. The parameter string has the following format:

tagname operation repository_path file_revision_pair [file_revision_pair...]

The parameters are provided to enable the script you specify in the action to check that the tag name meets standards, interact with other programs, or log tag operations.

The file_revision_pair is a space-separated pair of filename and revision number, and there is a pair for each file to be tagged.

The operations CVS provides are add, mov, and del. The mov operation is provided when tag or rtag is called with the tag-moving option -F, and del is provided when tag or rtag are called with the tag-deletion option -d. The add operation is provided when a new tag is added.

If CVS is running in client/server mode, the script given in the action runs on the repository computer. If the script exits with a nonzero exit status, the tag or rtag operation does not proceed.

The taginfo file is often used to enforce tag-name standards in a project. Example 7-10 shows the first part of a parser that returns 1 if a tag name doesn't fit the project's standards and 0 if it does.

Example 7-10. Parsing tag names
$TAGNAME=$ARGV[0];
$OPERATION=$ARGV[1];
$REP_PATH=$ARGV[2];
%FILE_REV=splice(@ARGV,3);
   
@tagfields=split('-',$TAGNAME)
if (!is_in(('prealpha','alpha','beta','stable'),$tagfields[1])) {
     return 1;
}
.
.
.
return 0;.

7.3.8 The verifymsg File

The verifymsg file is processed before a file is committed and after you enter the cvs commit log message, either in the editor that CVS opens or by using the -m message or -F file options to cvs commit.

verifymsg uses the syntax described in Section 7.3.2 of this chapter, with one rule per line and each rule consisting of the following elements:

name_pattern action

If a name_pattern matches the name and path of the directory or module parameter to cvs commit, CVS calls the action and passes it the path to a temporary file containing the cvs commit log message, and a copy of the log message on standard input (stdin). If the repository is not on the same computer as the client, the script given in the action runs on the repository computer. If the script returns a nonzero value, the commit does not proceed.

The verifymsg file is usually used to enforce project standards for commit log messages, and the script often either checks or modifies the log message you enter when you commit files

The script can modify the log message, and the RereadLogAfterVerify option in the config file in the repository's CVSROOT directory determines whether the original or the modified log message is used. (If the log message is reread, CVS reads it from the temporary file.) See Chapter 6 for information on the config file.

The ALL keyword is not supported for use in the verifymsg file.


  Previous section   Next section
Top