Configuring a CVS Server

In this third part of a four-part article series on software configuration management, you’ll learn how to set up and use a CVS server. We’ll also start looking at the patch program. This article is excerpted from chapter three of the book Cross-Platform Development in C++, written by Syd Logan (Addison-Wesley; ISBN: 032124642X).

Setting Up and Using CVS

For those of you who are interested, I describe the steps it takes to set up a CVS server on a Red Hat-based system. The steps I provide here are almost certainly going to be the same when executed on non-Red Hat systems, and may differ in certain ways on other UNIX-based systems, including Mac OS X. The work involved in getting a CVS server up and running is not terribly difficult, and can be done in a relatively short amount of time. You will need root access to the system upon which you are installing the server, and it will help to have a second system with a CVS client so that you can test the result.

That said, if doing system administration makes you nervous, or site policy disallows it, or you do not have root access, check with a local guru or your system administrator for help.

To start the process of getting a CVS server running, you need to download the source for CVS from the Internet, build it, and install it. I retrieved a nonstable version of CVS by downloading the file cvs-1.11.22. tar.gz from http://ftp.gnu.org/non-gnu/cvs/source/stable/1.1.22. You are probably best, however, grabbing the latest stable version you can find.

After you have unpacked the file, cd into the top-level directory (in my case, cvs-1.11.22), and enter the following to build and install the source:

$ ./configure
$ make
$ su
$ make install

Next, while still logged in as root, you need to do some work so that the CVS server daemon executes each time the system is rebooted. The first step is to check to see whether entries like the following are located in /etc/services:

cvspserver 2401/tcp # CVS client/server operations
cvspserver 2401/udp # CVS client/server operations

If these lines don’t exist, add them to /etc/services as shown. Next, you need to create a file named cvspserver in /etc/xinetd.d that contains the following:

service cvspserver
{
socket_type = stream
protocol = tcp
wait = no
user = root
passenv = PATH
server = /usr/bin/cvs
server_args = -f –allow-root=/usr/cvsroot pserver
}

Make sure the permissions of this file are -rw-r–r–, and that its group and owner are root. This is probably the default, but it doesn’t hurt to check.

If you are not yet running the desktop graphical user interface (GUI), fire it up, and from the Red Hat Start menu, select System Settings, Users and Groups to launch the Red Hat User Manager.

In the dialog that is displayed, click the Add Group button and add a group named cvsadmin. Next, click the Add User button, and add a user named cvsuser. You will be asked to provide a password; enter in something you can remember, and when you are done, exit the Red Hat User Manager.

Back in a terminal, and still as root, enter the following:

# cd /usr
# mkdir cvsroot
# chmod 775 cvsroot
# chown cvsuser cvsroot
# chgrp cvsadmin cvsroot

The preceding commands create the root directory for the CVS server. The path /usr/cvsroot corresponds to the value used in the server_args field of the service aggregate that was created earlier in /etc/xinetd.d. The following commands create a locks directory below cvsroot:

# cd cvsroot
# mkdir locks
# chown cvsuser locks
# chgrp cvsadmin locks

Now that the directory exists for the repository, it is time to create the repository. You can do this by executing the cvs init command, as follows:

# cvs -d /usr/cvsroot init

The -d argument specifies the location of the repository.

Now that the repository has been created, change to your home directory (for example, /home/syd), and execute the following command, which will check out the CVSROOT module from the repository that was just created:

# cvs -d /usr/cvsroot checkout CVSROOT
cvs checkout: Updating CVSROOT
U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/editinfo
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
U CVSROOT/rcsinfo
U CVSROOT/taginfo
U CVSROOT/verifymsg

Next, cd into the CVSROOT directory that was created by the preceding command, and open up the file named config using your favorite editor. Make the contents of this file consistent with the following:

# Set this to "no" if pserver shouldn’t check system
# users/passwords.
SystemAuth=no

# Put CVS lock files in this directory rather than
# directly in the repository. #LockDir=/var/lock/cvs

# Set ‘TopLevelAdmin’ to ‘yes’ to create a CVS
# directory at the top level of the new working
# directory when using the ‘cvs checkout’ command.
TopLevelAdmin=yes

# Set ‘LogHistory’ to ‘all’ or ‘TOFEWGCMAR’ to log all
# transactions to the history file, or a subset as
# needed (ie ‘TMAR’ logs all write operations)
#LogHistory=TOFEWGCMAR

# Set ‘RereadLogAfterVerify’ to ‘always’ (the default)
# to allow the verifymsg script to change the log
# message. Set it to ‘stat’ to force CVS to verify
# that the file has changed before reading it. This can
# take up to an extra second per directory being
# committed, so it is not recommended for large
# repositories. Set it to ‘never’ (the previous CVS
# behavior) to prevent verifymsg scripts from changing
# the log message. #RereadLogAfterVerify=always

After you have made changes to the config file, check it into CVS as follows:

# cvs commit
cvs commit: Examining .
Checking in config;
/usr/cvsroot/CVSROOT/config,v <– config new revision: 1.2; previous revision: 1.1 done
cvs commit: Rebuilding administrative file database

In the same directory, run the following command to create a password for each user for whom you want to grant access to the repository. Every time you add a new developer to the project, you need to update the passwd file as I am about to describe, and check the changes into the repository:

# htpasswd passwd syd
New password:
Re-type new password:
Adding password for user syd

Now, open the file passwd (which was just created). At the end of the password, append :cvsuser. The result should look something like this:

syd:B9TyxNZ11EKb6:cvsuser

Next, you must add the password file to the repository, and commit the result:

# cvs -d /usr/cvsroot add passwd
cvs add: scheduling file ‘passwd’ for addition
cvs add: use ‘cvs commit’ to add this file permanently
# cvs -d /usr/cvsroot commit
RCS file: /usr/cvsroot//CVSROOT/passwd,v done
Checking in passwd;
/usr/cvsroot//CVSROOT/passwd,v <– passwd initial revision: 1.1
done
cvs commit: Rebuilding administrative file database

This should result in two files in /usr/cvsroot/CVSROOT, one named passwd,v and the other named passwd. If there is not a file named passwd in /usr/cvsroot/CVSROOT (this could happen because of a bug in CVS), return to the checked-out version of CVSROOT (for example, the one in your home directory), edit the file named checkoutlist, and add a line to the end of the file that contains the text passwd. Then, doing a cvs commit on the checkoutlist file will cause the passwd file in /usr/cvsroot/CVSROOT to appear.

Now all that is left is to make the modules. Each directory you create under /usr/cvsroot is, logically, a project that is maintained in the repository. You can organize the hierarchy as you see fit. Here, I create a project named client:

# cd /usr/cvsroot
# mkdir client
# chown cvsuser client
# chgrp cvsadmin client

Now that we have created the repository, added a project, and set up some users, we can start the CVS server daemon by kicking xinetd:

# /etc/init.d/xinetd restart
Stopping xinetd: [ OK ]
Starting xinetd: [ OK ]

To ensure that the CVS server is running, run the following command:

# netstat -a | grep cvs

If you see output like the following, everything is in order, and you can use the repository:

tcp 0 0 *:cvspserver *:* LISTEN

To test out the new server and repository, find another machine, open up a shell (or a GUI CVS client if you prefer), and then check out the project named client. In the following example, I am using a command-line CVS client, and the server is located on my local network at the IP address 192.168.1.102:

$ cvs -d :pserver:syd@192.168.1.102:/usr/cvsroot login
(Logging in to syd@192.168.1.102)
CVS password:
$ cvs -d :pserver:syd@192.168.1.102:/usr/cvsroot co
client
cvs server: Updating client

There now should be a directory named client in the current directory. If you cd into the client directory, you should see the following contents:

$ cd client
$ ls
CVS

At this point, you can add files and directories to the project with cvs add, and commit them to the repository using cvs commit.

{mospagebreak title=Item 14: Use Patch}

The patch program is considered by some to be the prime enabler behind the success of open source software. To quote Eric Raymond, “The patch program did more than any other single tool to enable collaborative development over the Internet—a method that would revitalize UNIX after 1990” (The Art of UNIX Programming, Addison-Wesley, 2003). Of course, it is hard to imagine patch taking all the credit; after all, what would development be without vi(1)? But still, there is a ring of truth in what he says.

In the open source community, at any given moment, on any given project, there are dozens, if not hundreds of developers, all working on some derivation of what is in currently on the tip (or branch) of some source code repository. All of them are working relatively blind to the changes that their counterparts are making to the same body of source code.

An Example

Integrating (and evaluating) the changes made to a shared body of source code in such an environment can be difficult and error prone without a tool like patch. To see how, consider a team of three developers (A, B, and C) all working from the tip of the repository. Developer B is the team lead, and his job is to perform code reviews for Developer A and C, and integrate their changes into the source tree once an acceptable code review has been obtained. He also does development on the same body of source code, because he owns the overall architecture.

Let’s say that Developer A finishes his work and is in need of a code review. To obtain the code review, Developer B needs to communicate his changes to Developer B. I’ve seen this done a few different ways over the years:

  1. Developer A copies and pastes the changes made to the source file(s) into a text file, and sends the result to Developer B. In addition, Developer A adds comments to the text file to describe what the changes are, and where in the original source file the changes were made (or Developer A e-mails this information separately to Developer B). This is perhaps the worst method of all for conducting a code review, for two reasons:

    1. Developer A may make a mistake and not copy and paste all the changes that were made, or miss entire source files that have modification. The omission of a single line of change can greatly affect the ability of a code reviewer to accurately perform his task. Worse yet, if the code reviewer is responsible for integrating the changes into the repository and changes were missed, the process will surely lead to bugs.
    2. Even if all changes are copied and pasted by Developer A, there is a chance that context will be lost or incorrectly communicated. One way to counter this problem would be for Developer A to include extra lines above and below the code that actually changed, but this is a better job for a tool like cvs diff, which can generate a patch file that contains the needed lines of context.
  2. Developer A sends to Developer B copies of all the source files that were changed. This is better than sending a series of hand-constructed diffs, because Developer B can now take the source files and create a patch that correctly captures the changes made by Developer A, along with the context of those changes. If Developer A sends source files that are not being modified by Developer B, Developer B can simply use the diff program (not cvs diff or svn diff) to generate a patch file relative to his current working tree. If Developer A, however, sends changes that do affect files modified by Developer B, Developer B can either diff against his working tree to see the changes in the context of work he is performing, or Developer B can pull a new tree somewhere and generate a patch file from it. The actual method used is usually best determined by the code reviewer. The downsides of this method are as follows:

    1. It is error prone. (Developer A might forget to include source files that contain change.)
    2. It places a burden on the code reviewer to generate a patch file. The last thing you want to do on a large project is make more work for the code reviewer. Usually, a code reviewer is generally always struggling to keep up with not only his own development task, but with all the code review requests that are pouring in. Anything you can do to make his job easier will generally be appreciative (and may result in the code reviewer giving your requests a higher priority).
  3. Developer A generates a patch file using cvn or svn diff, and sends it to the code reviewer. This is the best method because

    1. The changes are relative to Developer A’s source tree.
    2. cvs diff won’t miss any changes that were made, assuming that cvs diff is run at a high-enough level of the source tree. (There is one exception: new source files that have not been added to the repository, along with forgetting to pass the -N argument to cvs diff when creating a patch file [this is not a problem with svn diff, which automatically includes new source files in its diff output.])

After the code reviewer (Developer B) receives the patch from Developer A, he or she has a few options:

  1. Simply look at the patch file, performing the code review based on its contents alone. Most of the time, this is what I do, especially if the patch file is a unified diff (as it should always be), and if the changes do not intersect any that I am making.
  2. Apply the patch file to his local tree, build the result, and then perhaps test it. This can be helpful if Developer B would like to step through an execution of the code in a debugger, or to see that the patch builds correctly and without warnings. If Developer A has made changes to some of the source files that were modified by Developer B, Developer B can either
    1. Pull a new tree and apply the patch to it so that his or her changes are not affected.
    2. Use cvs diff to generate a patch file that contains his own changes, and then attempt to apply the changes from Developer A into his source tree. This allows Developer B not only to see the changes made by Developer A, but also to see them in the context of the changes that he is making. When the code review has been completed, Developer B can continue working on his changes, and check both his and Developer B’s changes in at a later time, or Developer B can have Developer A check in the changes, and then do a cvs or svn update to get in sync.

The patch program is the tool used by a code reviewer to apply changes specified in a patch file to a local copy of the repository. In essence, if both you and I have a copy of the same source tree, you can use cvs diff to generate a patch file containing changes you have made to your copy of the sources, and then I can use the patch program, along with your patch file, to apply those changes to my copy of the sources. The patch program tries very hard to do its job accurately, even if the copy of the sources the patch is being applied to have been changed in some unrelated way. The type of diff contained in the patch file affects the accuracy attained by the patch program; patch is generally more successful if it is fed a set of context diffs rather than normal diffs. The cvs diff -u3 syntax (unified diff with three lines of context) is enough to generate a patch file that gives a good result. (SVN by default generates unified diffs with three lines of context.)

Please check back for the conclusion to this article.

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye