[comp.sources.unix] v22i013: Concurrent RCS version system, release 3.0, Part01/02

rsalz@uunet.uu.net (Rich Salz) (05/04/90)

Submitted-by: Dick Grune <dick@cs.vu.nl>
Posting-number: Volume 22, Issue 13
Archive-name: cvs3.0/part01

[ This is the basis for Brian Berliner's CVS presented at the last Usenix,
  to appear tomorrow.  --r$  ]

CVS, published last in comp.sources.unix in "Volume 6 (Ends mid-July, 1986)",
has evolved a bit, under user demand, hopefully without succumbing to
creeping featurism. This is Release 3 (the previous published one was
probably Release 1, acc. to present nomenclature).

CVS is a front end for RCS, supporting the concurrent and independent
use of an RCS directory by several people.  See manual page cvs.1.

This set of shell scripts assumes the presence of the RCS programs
rcs, ci, co, rcsmerge and rlog (by Walter Tichy).


				Kind regards,
					Dick Grune
					Vrije Universiteit
					de Boelelaan 1081
					1081 HV  Amsterdam
					the Netherlands
					dick@cs.vu.nl

----------------------------------------------------------------
: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'READ_ME'
sed 's/^X//' > 'READ_ME' << '+ END-OF-FILE ''READ_ME'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: READ_ME,v 3.2 89/09/26 15:33:30 dick Exp $
X
XThis is Release 3, 890925.
X
XCVS is a front end for RCS, supporting the concurrent and independent
Xuse of an RCS directory by several people.  See manual page cvs.1.
X
XThis set of shell scripts assumes the presence of the RCS programs
Xrcs, ci, co, rcsmerge and rlog (by Walter Tichy).
X
XTo install, examine the Makefile and give suitable values to:
X
XCVSBIN	the directory for the commands themselves	eg. /usr/local/bin
XCVSLIB	idem for the auxiliaries			eg. /usr/lib/local/cvs
XCVSMAN	idem for the manual page cvs.1			eg. /usr/man/man1
XRCSBIN	the directory that holds the RCS programs	eg. /usr/bin
X
XThen call     make install
X
XBe sure you can write/create:
X	in $(CVSBIN): AE CM CV DF GC HR LS NR RC RM RV UV  REP LAR LAU LCK
X	in $(CVSLIB): anything
X	in $(CVSMAN): cvs.1
X
XHistorian:
X	Unlike the previous releases this release keeps a configuration history
X	file. To construct such a file retroactively a 'historian' has been
X	added. See manual page historian.1. Install by calling
X		make install.hist
X	Be sure you can write/create:
X		in $(CVSBIN): historian hist1 hist2 coALL
X		in $(CVSMAN): historian.1
X
XChanges from release 880312 (configuration 1.93, should have been Release 2):
X	features a series of commands to handle sets of repositories
X	keeps a configuration history file
X	release numbers can be set for a (set of) repositories
X
XChanges from release 860518 (configuration 1.61, should have been Release 1):
X	preserves inodes when updating and committing
X	DF has a better idea of what has changed
X	maintains CVS.adm/Files containing all file names
X	environment variables $RCSBIN and $CVSPATH, to access binaries
X	Changed the name of the attic directory from .old to Attic.
X
X
X					Dick Grune
X					Vrije Universiteit
X					de Boelelaan 1081
X					1081 HV  Amsterdam
X					the Netherlands
X					dick@cs.vu.nl
+ END-OF-FILE READ_ME
chmod 'u=rw,g=r,o=r' 'READ_ME'
set `wc -c 'READ_ME'`
count=$1
case $count in
1973)	:;;
*)	echo 'Bad character count in ''READ_ME' >&2
		echo 'Count should be 1973' >&2
esac
echo Extracting 'Makefile'
sed 's/^X//' > 'Makefile' << '+ END-OF-FILE ''Makefile'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: Makefile,v 3.2 89/09/28 17:42:41 dick Exp $
X
XCVSBIN =	/home/top/dick/bin#	# where to install the CVS programs
XCVSLIB =	/home/top/dick/lib/cvs#	# where to install the CVS auxiliaries
XCVSMAN =	/home/top/dick/man#	# where to install the CVS manual
XRCSBIN =	/usr/local/bin#		# where the RCS binaries reside
X
XINF =	READ_ME Makefile Install cvs.1 historian.1
XPRG =	AE CM CV DF GC HR LS NR RC RM RV UV  REP LAR LAU LCK
XAUX =	BE.aux CA.aux CC.aux CI.aux CS.aux EF.aux FN.aux HN.aux LR.aux MF.aux \
X	ND.aux NR.aux OP.aux RG.aux SC.aux SL.aux VN.aux VT.aux WL.aux
XHIST =	historian hist1 hist2 coALL
X
Xwhat:
X	@echo "Call is: make [ install | install.hist | .distr | shar | clean ]"
X
Xinstall:	install.files $(CVSMAN)/cvs.1
X
Xinstall.files:
X	for F in $(PRG); do ./Install $$F $(CVSBIN) $(CVSLIB) $(RCSBIN); done
X	for F in $(AUX); do ./Install $$F $(CVSLIB) $(CVSLIB) $(RCSBIN); done
X
Xinstall.hist:
X	for F in $(HIST); do ./Install $$F $(CVSBIN) $(CVSLIB) $(RCSBIN); done
X	cp historian.1 $(CVSMAN)/historian.1
X
X$(CVSMAN)/cvs.1:	cvs.1
X	cp cvs.1 $(CVSMAN)/cvs.1
X
X# create a (composite) shar file shar[12]
Xshar:	shar1 shar2
XSHAR1 =	$(INF) $(AUX) $(HIST)
XSHAR2 =	$(PRG)
X
Xshar1:	$(SHAR1) Makefile
X	shar $(SHAR1) >shar1
X
Xshar2:	$(SHAR2) Makefile
X	shar $(SHAR2) >shar2
X
X.distr:	Makefile
X	echo $(SHAR1) $(SHAR2) | tr ' ' '\012' >.distr
X
Xclean:
X	rm -f shar[12] .distr
X
+ END-OF-FILE Makefile
chmod 'u=rw,g=r,o=r' 'Makefile'
set `wc -c 'Makefile'`
count=$1
case $count in
1469)	:;;
*)	echo 'Bad character count in ''Makefile' >&2
		echo 'Count should be 1469' >&2
esac
echo Extracting 'cvs.1'
sed 's/^X//' > 'cvs.1' << '+ END-OF-FILE ''cvs.1'
X.\"	This file is part of the Concurrent Versions System CVS.
X.\"	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X.\"	$Header: cvs.1,v 3.3 89/10/06 12:58:22 dick Exp $
X.TH CVS 1 89/09/25 "Vrije Universiteit"
X.SH NAME
Xcvs \- concurrent-versions system
X.SH SYNOPSIS
X.B CV
Xrepository-name
X.br
X.B UV
X[
X.B \-n
X] [ filename ... ]
X.br
X.B CM
X[
X.B \-n
X] 'log-message' [ filename ... ]
X.br
X.B AE
X[ \-... ] filename ...
X.br
X.B RM
Xfilename ...
X.br
X.B LS
X[ filename ... ]
X.br
X.B DF
X[ \-... ] [ filename ... ]
X.br
X.B GC
X.br
X.B HR
X[ repository-name ]
X.br
X.B NR
Xrelease-number repository-name
X.br
X.B RC
X[
X.B \-i
X] [ repository-name ]
X.br
X.B RV
Xrepository-name configuration-identifier
X.sp
X.B REP
X[
X.B \-n
X] CVS-command ...
X.br
X.B LAR
Xdirectory
X.br
X.B LAU
X.sp
X.B LCK
X[
X.B on
X|
X.B off
X]
X.SH DESCRIPTION
X.I CVS
Xsupports the concurrent use of independent versions of an RCS directory or a
Xset of RCS directories, and as such acts as a front end for RCS.  The user is
Xnot required to know RCS commands or ever give them.  The original files of a
Xproject reside in one or more RCS directories, called
X.IR repositories ,
Xand are handled by the above commands only.  The casual user uses
X.I UV
Xand
X.I CM
Xand may use
X.IR CV ,
X.IR DF
Xand
X.IR LS ;
Xthe other commands are for maintenance only.
X.PP
XEach participant in the project has his own private copy of the
Xfiles; such a copy is called a
X.IR configuration .
XEach participant can work on his copy at his convenience since it
Xis totally his; the command
X.I UV
X(Update Version)
Xwill merge updates to the repository into his files without
Xdisturbing his own modifications; he can merge his own modifications back
Xinto the repository with the command
X.I CM
X(commit).  Concurrency conflicts, which turn out to be rare anyway, are
Xalmost always detected.  The repository is protected by multi-reader
Xsingle-writer locks.  There is a simple facility for sets of user
Xdirectories and repositories; see below.
X.PP
X.B "Commands"
X.br
X.B CV
X(Create Version) creates a version of the configuration described by a
Xrepository.  This configuration is owned totally by the user and is actually
Xan independent copy, to be dealt with as seen fit.  Once
X.I CV
Xhas been called
Xin a given directory, it never needs to be called again.  The
Xuser can keep up-to-date by calling
X.I UV
Xwhen he feels like it;
Xthis will supply him with a merge of his own modifications
Xand the changes made by others in the repository.  See
X.I UV
Xfor details.
X.PP
XWhen the user is satisfied with his own modifications, the
Xpresent configuration can be committed by
X.I CM
X(ComMit); this keeps the present configuration in tact.
X.PP
XThe call is
X.br
X	CV
X.I repository-name
X.br
Xwith preferably the full path name of the repository.
X.I CV
Xwill then make the initial copy (at RCS speed).  Files in the
Xworking directory with names that also occur in the repository are
Xsupposed to derive already from the RCS files.
X.PP
X.I CV
Xcreates a directory
X.IR ./CVS.adm ,
Xin which
X.I CVS
Xkeeps its
Xadministration, in a number of files. Only the file
X.I ./CVS.adm/Repository
Xis of importance to the user, since it contains
Xthe name of the repository.  This file is a normal file and can be
Xedited by the user, if necessary (when the repository is moved, e.g.).
X.PP
X.B UV
X(Update Version) updates the configuration in the present directory with
Xrespect to the repository.  The present configuration must have been created
Xby
X.I CV.
XThe call is
X.br
X	UV
X.br
Xfor a general update, or
X.br
X	UV
X.I file ...
X.br
Xfor a partial update.
X.PP
XModified or new RCS files are checked out.
XModified user files are reported on standard output
Xas
X.I "M\ user_file."
XIf both the
XRCS file and the user file have been modified, the user file
Xis replaced by the result of
X.I rcsmerge.
XIf this throws up irreconcilable differences, the file is reported as
X.I "C\ user_file,"
Xand as
X.I "M\ user_file"
Xotherwise.
XFiles added but not yet committed are reported as
X.I "A\ user_file."
XFiles removed but not yet decommitted are reported as
X.I "R\ user_file."
X.PP
X.I UV
Xallows a
X.B \-n
Xoption, which restricts the actions to reporting only.
X.PP
X.B CM
X(ComMit) commits the present configuration to the repository,
X.I after
Xhaving done a test on conflicts.  The call is
X.br
X	CM
X.I log-message
X.br
Xfor a general commit, and
X.br
X	CM
X.I "log-message file ..."
X.br
Xfor a (dangerous!) partial commit.  The
X.I log-message
Xis obligatory, and will be passed to RCS to be stored in the affected
Xrepository files.
X.PP
X.I CM
Xallows a
X.B \-n
Xoption, which restricts the actions to reporting only.
X.PP
X.B AE
X(Add Entries) adds new entries to the present configuration; for each file it
Xasks for a description, in RCS fashion.
XThe entries will be added to the repository upon the next call of
X.I CM.
XThe user files must already exist.
X.I AE
Xon a file removed with
X.I RM
Xwill resurrect the file, unless its removal has already been committed.
XAny options to
X.I AE
Xwill be passed on to
X.I rcs \-i
X(see RCS manual).
X.PP
X.B RM
X(ReMove) marks the entries as removed on purpose from the present
Xconfiguration.  The RCS files will be actually removed from the repository
Xupon the next call of
X.I CM;
Xthey will be moved to a directory
X.I Attic
Xin the repository.
X.PP
X.B LS
Xprints three lines of information for each of its arguments,
Xone for the user file (line 1), one for the newest RCS file
X(line 3) and one for the RCS file both derive from (line 2).
XLike the Unix
X.I ls,
Xit will treat all files if no arguments are given.
X.PP
X.B DF
Xdoes a nice form of diff(1) on each of its arguments and the
XRCS file that argument derives from.
XIf there are options, these are passed to diff(1) and the diff
Xformat is adhered to; otherwise a more readable format is produced.
XStandard diff(1) format can also be forced by a single \-.
XIf there are no file names,
X.I DF
Xtreats the files that have been modified since the last call to
X.I CM.
XIf the option is
X.B \-n,
Xdiff(1) will not be called, but the list of modified files will be displayed
Xinstead.
X.PP
X.B GC
X(Garbage Collection) collects garbage, dust & dead wood.  Should be called
Xafter crashes while a
X.IR CVS -program
Xwas running, and other mishaps.
XIt is up to the user to remove (or not!) the files
X.I GC
Xcomplains about.
X.PP
X.B HR
X(Highest Release number) writes the highest release number of any RCS file in
Xthe repository to standard output. If no argument is given, the command
Xapplies to the repository of which the working directory derives. The "release
Xnumber" is the first part of the RCS revision number.
X.PP
X.B NR
X(New Release number) sets the (highest) release number of a repository to the
Xnumber which is its first argument. The repository should have been locked by
X.I "LCK on"
Xalready. The number must be higher than the present release number.
X.PP
X.B "Examining and restoring previous versions"
X.br
X.I CVS
Xkeeps a history of the versions of the configurations that have been
Xcommitted to the repository.
X.PP
X.B RC
X(Retrieve Configuration history) displays the configuration identifier,
Xdate and log message of each version.  A configuration is represented by a
X.IR "configuration identifier" ,
Xwhich is basically the version number of a record describing the contents of
Xthe configuration.  This configuration identifier can be presented to
X.I RV,
Xwhich will restore the identified configuration; this process
Xrequires the repository again (or still) to be present, though not
Xnecessarily with the same path name.
X.br
X	RC \-i
X.br
Xwill print the configuration identifier of the present configuration.
X.I RC
Xcan be given the name of a repository as a parameter, and will then work on
Xthat repository.
X.PP
XOlder versions of CVS (before Release 3) did not keep this configuration
Xhistory; it can be reconstructed for old repositories by using the program
X.I historian ;
Xsee historian(1).
X.PP
X.B RV
X(Restore Version) restores a version of the configuration, given the
Xrepository name and a configuration identifier.  The call is
X.br
X	RV
X.I "repository-name configuration-identifier"
X.br
XThe repository has to exist; the files will be reconstructed with the correct
Xrevision number, even if they were removed by
X.I RM
Xand
X.I CM
Xin the meantime.
X.PP
XFor backward compatibility,
X.I RV
Xwill still be able to work from SV-records, as created by the late program
XSV. The SV-record will be read from standard input by the call
X.B RV
X.I "repository-name"
X.B \-
X.PP
XIf the configuration identifier is kept of the distribution sent to a client,
Xthe following scenario is useful when the client sends in some
Xcorrections.  In an empty directory, call
X.I "RV conf-idf"
Xto reconstruct the client's files.  Apply his corrections.  Call
X.I UV
Xto integrate them with your own innovations.  Call
X.I DF
Xand test, to see if they still make sense.  If satisfied, call
X.I CM
Xand remove the directory.
X.PP
X.B "Sets of directories"
X.br
XProjects are often not confined to a single repository, nor to a single user
Xdirectory, and having CVS commands that work on sets of both would be useful.
XThere is, however, no generally accepted tree structure for RCS directories
Xwith subdirectories, so the user is required to specify their structure and the
Xrelated user directory structure. This information, which includes a list of
Xdirectories or repositories, is fed (on standard input)
Xto
X.B REP
X(for Repeat) which is given the CVS command to be repeated as its first
Xargument. A second reason for this factorized approach is that CVS commands on
Xsets of repositories can take hours, may come to an abnormal end, and may have
Xto be restarted somewhere in the middle. The latter can be achieved by
Xsupplying the remainder of the input list to a second call of
X.I REP.
X.PP
X.I REP
Xis not naive about the command under its control and knows that different
Xcommands require different arguments; depending on its command
X.I REP
Xitself will require different input and further arguments. Several types of
Xcalls can be distinguished.
X.LP
X	<UserDir-list REP UV
X.br
X	<UserDir-list REP CM 'message'
X.br
X	<UserDir-list REP LS
X.br
X	<UserDir-list REP DF
X.br
X	<UserDir-list REP GC
X.br
XThe commands require a list of user directory names as input, and will
Xperform the named command in all these directories.
X.LP
X	<Repository-list REP RC [ \-i ]
X.br
X	<Repository-list REP HR
X.br
X	<Repository-list REP NR release-number
X.br
XThe commands require a list of repository names as input.
X.I "REP RC"
Xgives a formatted report of the configuration histories and
X.I "REP RC \-i"
Xproduces output of the form
X.br
X	<repository-name> <configuration-identifier>
X.br
Xwhich can serve as a basis for input to a later call of
X.IR "REP RV" .
X.I "REP HR"
Xgives the over-all highest release number in the repository tree.
X.I "REP NR release-number"
Xsets the over-all highest release number in the repository tree to
X.I release-number.
X.LP
X	<Repository-UserDir-list REP CV
X.br
XThe command requires a list of repository-name/user-directory-name pairs
X(separated by a space) as input, and will create the described versions,
Xcreating user directories if necessary. 
X.LP
X	<Repository-UserDir-ConfIdf-list REP RV
X.br
XThe command requires a list of
Xrepository-name/user-directory-name/configuration-identifier triplets
X(separated by spaces) as input, and will restore the described versions,
Xcreating user directories if necessary.
X.PP
XThe CVS commands
X.I AE
Xand
X.I RM
Xcannot be repeated.
X.I REP
Xitself can have a
X.B \-n
Xoption, which causes it to print its commands rather than execute them.
X.PP
XThe input to
X.I REP
Xcan be obtained in various ways. The user (project manager) can keep files that
Xembody the proper interrelationships; if the relations are irregular, that may
Xbe the only way. UserDir lists can be generated by
X.B LAU
X(List All User directories), which lists all user directories under CVS that
Xare subdirectories of the working directory, according to the criterion that
Xa user directory under CVS contains a directory
X.IR CVS.adm .
XConsequently,
X.br
X	LAU | REP UV
X.br
Xwill do an update on the working directory and all its CVS subdirectories.
XRepository-lists can be generated by a call of
X.B LAR
X(List All Repositories).
X.I "LAR directory"
Xlists all repositories that are subdirectories of
X.IR directory ,
Xaccording to the criterion that a repository contains RCS files and that it
Xis not named
X.I Attic
Xor
X.IR Admin .
XConsequently,
X.br
X	LAR <top-repository> | REP HR
X.br
Xwill display the over-all highest release number in the whole repository tree.
XMore complex input lists (for
X.I CV
Xand
X.IR RV )
Xwill have to be constructed by additional means. If the user tree is to have
Xthe same form as the repository tree, the following
X.IR sed (I)
Xcommand may be useful:
X.DS
X.cw
Xsed '
X	s/.*/&|&/
X	s|'"$RCSPREFIX"'|'"$USERPREFIX"'|
X	s/\e(.*\e)|\e(.*\e)/\e2\ \e1/
X\&'
X.ft 0
X.DE
Xwhich converts, e.g.
X.br
X	/home/x8/RCS/part3/module5
X.br
Xinto
X.br
X	/home/x8/RCS/part3/module5 /usr/x8/part3/module5
X.br
Xwith the setting RCSPREFIX=/home/x8/RCS and USERPREFIX=/usr/x8, thus creating
Xinput to
X.IR "REP CV" .
X.PP
X.B LCK
Xcan be used to manually lock (first argument
X.BR on )
Xand unlock (first argument
X.BR off )
Xa repository. Although this command can be used on separate repositories, it
Xis normally used on a set (tree) of them, which is why it is treated here. It
Xshould
X.I not
Xbe used by the normal user;
X.I CM
Xand
X.I UV
Xhandle all normal cases. The command is required before doing
X.IR NR ,
Xand is useful to ensure that no activity takes place in a repository.
X.PP
X.B "Setting up"
X.br
XTo set up a repository
X.I repos,
Xmake an empty directory of that name, call
X.I "CV repos,"
Xdo
X.I AE
Xfor each file to go into the repository and finally call
X.I CM
Xto commit the initial version.
X.PP
XTo participate in an existing repository
X.I repos,
Xi.e., to create your own private configuration of a repository, just call
X.I "CV repos".
X.PP
XTo turn an existing RCS directory into a repository, you can likewise call
X.I "CV repos",
Xsince no administration is kept in the RCS directory.
XThis works even if both the user files and
Xthe RCS directory already exist (this is useful if you want to start using
X.I CVS
Xfor an existing project).
X.PP
X.B "Remarks"
X.br
XIt is generally not wise to interrupt a CVS command: many of them perform a
Xlarge number of actions that are only meaningful if done in their entirety or
Xnot at all, and UNIX is not good at pretending it's all one indivisible
Xaction. If a CVS command has succumbed to a system crash, act as follows.
XCall
X.I GC
Xrepeatedly and act on its messages until it shuts up.  You can
Xunlock an RCS file that may have been left locked by calling
X.I "rcs -u",
Xand unlock a repository by calling
X.I "LCK off repos".
XThen call
X.I UV
Xand act on its messages until it shuts up.  And then call
X.I UV
Xagain (this is necessary to get the time stamps right in some cases).
X.PP
XIf the user configuration is quiescent (i.e.,
X.I "DF \-n"
Xgives no output), the user can remove his files with impunity; a
Xsubsequent call of
X.I UV
Xwill restore the full configuration.
X.SH "ENVIRONMENT VARIABLES"
X.IP RCSBIN 8
XIf defined: the name of the directory where the RCS programs reside.
XDefault: as determined in the
X.I Makefile.
X.IP CVSPATH 8
XIf defined: the search path for non-RCS programs.  Default:
X.I /bin:/usr/bin.
X.SH FILES
X.ta 8n 36n
XIn the present directory:
X.br
X	*,[pt]	options and text from
X.I AE
X.br
XIn the directory ./CVS.adm:
X.br
X	Repository	holds name of repository
X.br
X	Files	list of file names in the configuration
X.br
X	Entries	version number and time stamp for each file
X.br
X	Entries.Backup
X.br
X	Mod	names of files modified since last
X.I CM
X(or since
X.IR CV )
X.br
X	LastUpdate	time stamp of latest full update
X.br
XIn the repository:
X.br
X	Attic/	attic for removed files
X.br
X	#cvs.*	multi-reader single-writer locks
X.br
X	Admin/	holds
X.I CVS.confrec,v
Xfor the configuration history
X.br
X		and
X.I HighestRelease
Xfor the highest release number
X.br
XElsewhere:
X.br
X	rcs, ci, co, rcsmerge, rlog	RCS programs
X.SH SEE ALSO
Xhistorian(1); RCS documentation, rcsintro(1)
X.SH AUTHOR
XDick Grune, Vrije Universiteit, Amsterdam
X.SH DIAGNOSTICS
XBoth
X.I UV
Xand
X.I CM
Xattempt first to make sure that all required actions are possible before
Xdoing any of them.
X.SH DISADVANTAGES
XIf
X.I N
Xusers participate, there will be
X.I N
Xcopies on disk.
X.br
XIt's all shell files and slow.
X.br
X.SH BUGS
XThere is not (yet) a way to work with branches.
X.br
XFunny file names (e.g. containing spaces or *) will give trouble.
X.br
XWeird things happen if the RCS programs cannot be found.
X.br
XDo not run two of the
X.I CVS
Xprograms simultaneously in the same user
Xdirectory; there is no lock-out on the user directory, for
Xefficiency reasons (though there is on the repository).
+ END-OF-FILE cvs.1
chmod 'u=rw,g=r,o=r' 'cvs.1'
set `wc -c 'cvs.1'`
count=$1
case $count in
16569)	:;;
*)	echo 'Bad character count in ''cvs.1' >&2
		echo 'Count should be 16569' >&2
esac
echo Extracting 'historian.1'
sed 's/^X//' > 'historian.1' << '+ END-OF-FILE ''historian.1'
X.\"	This file is part of the Concurrent Versions System CVS.
X.\"	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X.\"	$Header: historian.1,v 3.2 89/10/02 15:15:21 dick Exp $
X.TH HISTORIAN 1 89/09/25
X.SH NAME
Xhistorian \- reconstruct configuration history for CVS
X.SH SYNOPSIS
X.B historian
X[ repository ]
X.br
X.B hist1
X[ repository ]
X>ph1
X.br
X.B hist2
X[ repository ]
X<ph1 >ph2
X.br
X.B coALL
Xfilename
X.SH DESCRIPTION
XRelease 3 of CVS keeps the history of the project in an RCS file
X.IR $Repository/Admin/CVS.confrec,v ,
Xwhich holds the revisions of the
X.I "configuration record,"
Xwhich in its turn is a file with the names of the files that make up the
Xconfiguration, with their version numbers. If you start using CVS on a new
Xrepository, CVS will create such a configuration history file for you
Xand maintain it. If, however, you use the new CVS on an old
Xrepository, then CVS, not knowing any better, will also create this
Xconfiguration history file, and subsequent calls to RC will suggest that the
Xrepository originated at the time you started using the new CVS: your previous
Xconfiguration history is lost. This may or may not bother you. If it does
Xnot, there is no problem; everything will work normally, except that older
Xconfigurations cannot be retrieved by configuration identifier using
X.I RV
X(they can still be retrieved manually or by using old output of SV).
X.PP
X.I "Reconstruction, ignoring removed files"
X.PP
XThe program
X.I historian
Xcan help you to recreate (or more precisely: to create) the configuration
Xhistory of the entire repository from the moment it was first brought
Xunder RCS (not: CVS!). It can be called with or without a parameter; it will
Xthen reconstruct the configuration history file for the repository belonging
Xto the working directory, or for the repository given as a parameter. This
Xwill take a couple of minutes and the result can be enjoyed by calling
X.I "RC."
X.PP
XThe resulting configuration history file will be correct if no files have
Xever been removed from the indicated configuration.
XIf files have been removed from the configuration (using
X.IR RM ),
Xthen there is a minor but serious problem: the historian cannot find out
Xexactly when a file was removed from the configuration; it will tell you so 
Xbut it will nevertheless construct a configuration history file. Files which
Xare removed are moved to
X.IR $Repository/Attic ,
Xbut their arrival there was not recorded anywhere and their last modification
Xtime is not a good indication either. So, to get this right, the historian
Xneeds help from a human.
X.PP
XThere are two things you can do about this. One is to do nothing; the result is
Xthat some old configurations, as retrieved by
X.I RV,
Xwill contain files
Xthat should not have been there. However, the history of all configurations
Xcreated after the first CM from CVS Release 3 will be correct and will not
Xshow any obsolete files any more. If this is acceptable, doing
Xnothing about the removed files is by far the easiest option.
X.PP
X.I "Reconstruction, considering removed files"
X.PP
XIt is possible to tell the historian exactly when a file was removed. To
Xunderstand the method, we have to take a closer look at what the historian
Xdoes. It consists of three phases, executed by
X.I hist1,
X.I hist2
Xand
X.I sh,
Xrespectively.
X.PP
X.I Hist1
Xdoes a call of the RCS program
X.I rlog
Xon all the files in the repository and the Attic, and combines the output into
Xa list of changes at each commit. For each commit that the historian is able
Xto discern, it writes a group of lines, each line identifying time, file
Xname, RCS version number, author and message of a single file. This group
Xdescribes the forward
X.I delta
Xeffected by the identified commit and is terminated by a blank line, which is
Xessential to the functioning of
X.I hist2.
X.PP
X.I Hist2
Xreads this list from standard input and constructs from it a shell script that
Xwill construct the configuration history file in a sequence of calls to the RCS
Xprogram
X.I ci
Xand to the UNIX editor
X.I ed.
XThe contents of this script can only be described as "gross".
X.PP
XThis script is then fed to the UNIX shell
X.I sh.
XSo, the following pipe line will construct the configuration history file:
X.br
X.B "	hist1 | hist2 | sh"
X.br
X.PP
XThis is indeed the main contents of the program
X.I historian.
X.PP
XThe input to
X.I hist2
Xnormally consists of the list of commit deltas, where each line in a commit
Xdelta consists of many fields. If a line in a commit delta contains one field
Xonly, it is taken by
X.I hist2
Xto be the name of a file which was removed during the commit of that
Xdelta. So, by editing the output of
X.I hist1
Xand adding file names in the proper places, the user can tell
X.I hist2
Xwhen files were removed; be sure not to add or remove blank lines
Xduring this edit operation, especially not the one at the end of the file.
XThe need to manually edit the information stream at some point is the main
Xreason why the historian's process was divided into two parts.
X.PP
XThe problem is that it is very difficult for the user to find out during which
Xcommit the file was removed. The following approach may be useful.
X.PP
XWhen a file is used in a configuration, it is likely to be mentioned in the
XMakefile. The historian's aid
X.I coALL
Xcan be used to retrieve all versions of, e.g., the Makefile. A call
X.br
X.B "	coALL Makefile"
X.br
Xcreates a directory
X.I Makefile.ALL
Xand stores in it all versions of the Makefile, each identified by its RCS
Xversion number. By using the UNIX command
X.I grep
Xon these files, it is often easy to determine in which versions of the
XMakefile a given file was used. This gives the highest version number in
Xwhich it was used, and consequently, the version number of the first Makefile
Xthat no longer uses it. The commit delta in the input of
X.I hist2
Xthat enters this version of the Makefile should contain the remove message for
Xthe file being examined.
X(coALL will also work on other file names).
X.PP
XThe process of identifying a file in a configuration by inspecting e.g., a
XMakefile is so problem-dependent that I think it is not worth while to
Xautomate it. A file
X.I read.c
Xmay for instance occur as
X.I read.o
Xin the Makefile.
X.PP
XThe commands
X.I hist1
Xand
X.I hist2
Xdo not affect any files and can be run as often as desired, irrespective of the
Xpresence of a configuration history file. The resulting shell script will only
Xrun if there is no configuration history file already; it will only affect
X.IR $Repository/Admin/CVS.confrec,v .
XIf this file is removed, the script can be run as often as desired (i.e.
Xuntil it does what you want).
X.SH FILES
Xhist1
X.br
Xhist2
X.br
XcoALL
X.SH SEE ALSO
Xcvs.1
X.SH AUTHOR
Xdick@cs.vu.nl (Dick Grune @ Vrije Universiteit, Amsterdam)
X.SH DIAGNOSTICS
XThe scripts take some liberty with the RCS commands, which sometimes give
Xwarnings or error messages; these can be mostly ignored. Error messages from
Xthe historian's commands are always identified as such.
X.SH CAVEATS
XThis is not production-quality software; be sure to check its effects.
X.br
XThe resulting shell script thinks it knows the internal structure of RCS
Xfiles and modifies them under evasion of the normal interface.
X.SH BUGS
XThe first part of the historian relies on two consecutive commits never
Xhaving the same message; if they have, they will coalesce.
+ END-OF-FILE historian.1
chmod 'u=rw,g=r,o=r' 'historian.1'
set `wc -c 'historian.1'`
count=$1
case $count in
7288)	:;;
*)	echo 'Bad character count in ''historian.1' >&2
		echo 'Count should be 7288' >&2
esac
echo Extracting 'BE.aux'
sed 's/^X//' > 'BE.aux' << '+ END-OF-FILE ''BE.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: BE.aux,v 3.1 89/09/25 16:29:18 dick Exp $
X
X#
X#		B u i l d   E n t r y
X#	Script, to be included.
X#
X#	Assumes set:
X#		$CVSLIB
X#		$Name
X#		$Options
X#		$Rcs
X#		$Repository
X#		$User
X#
X#	Builds an entry for a new file and sets up $User,[pt] by
X#	interrogating the user.
X#
X#	Sets OK to no and calls continue, if necessary.
X#
X
X# there may be an old file with the same name in the attic!
X# this is an awkward place to test, but other places are equally awkward
Xif	# it is in the attic already
X	[ -r $Repository/Attic/$User,v ]
Xthen
X	echo $Name: there is an old file $User already \
X						in $Repository/Attic >&2
X	OK=no
X	continue
Xfi
X
X# isn't the name too long?
Xif	# both $User and $User,x can be linked made by linking
X	ln $User $User, >/dev/null 2>/dev/null \
X&&
X	ln $User $User,x >/dev/null 2>/dev/null
Xthen
X	rm $User, $User,x
Xelse
X	rm -f $User,
X	echo $Name: filename $User is too long >&2
X	OK=no
X	continue
Xfi
X
X# store the options
Xecho "$Options" >$User,p
X
X# get a description file by imitating a call of rcs -i
Xecho "RCS file: $Rcs"
Xecho "enter description, terminated with ^D or '.':"
Xecho "NOTE: This is NOT the log message!"
Xcp /dev/null $User,t
Xwhile	# the user still provides text
X	read TXT
Xdo	# add it to $User,t, except if it is a single dot
X	if	# it is the terminating dot
X		[ "$TXT" = "." ]
X	then
X		break
X	fi
X	echo "$TXT" >>$User,t
Xdone
Xecho done
X
X# create the entry (at the end, since the user may have interrupted)
X$CVSLIB/RG.aux $User 0 "Initial $User"
+ END-OF-FILE BE.aux
chmod 'u=rwx,g=rx,o=rx' 'BE.aux'
set `wc -c 'BE.aux'`
count=$1
case $count in
1585)	:;;
*)	echo 'Bad character count in ''BE.aux' >&2
		echo 'Count should be 1585' >&2
esac
echo Extracting 'CA.aux'
sed 's/^X//' > 'CA.aux' << '+ END-OF-FILE ''CA.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: CA.aux,v 3.1 89/09/25 16:29:27 dick Exp $
X
X#
X#		C r e a t e   A d m i n i s t r a t i o n
X#	Script, to be included.
X#
X#	Assumes set:
X#		$Name
X#		$Repository
X#
X#	Creates a user CVS administration directory based on repository
X#	$Repository.
X#
X
X# install CVS.adm directory
Xif	# there is already a directory CVS.adm
X	[ -d CVS.adm ]
Xthen
X	echo $Name: this directory is already managed by CVS >&2
X	exit 1
Xfi
X
Xif	# we can create the administration directory
X	mkdir CVS.adm
Xthen	:
Xelse
X	echo $Name: cannot make administration directory ./CVS.adm >&2
X	exit 1
Xfi
X
X# set up the administration
Xecho $Repository >CVS.adm/Repository
Xcat /dev/null >CVS.adm/Entries
+ END-OF-FILE CA.aux
chmod 'u=rw,g=r,o=r' 'CA.aux'
set `wc -c 'CA.aux'`
count=$1
case $count in
777)	:;;
*)	echo 'Bad character count in ''CA.aux' >&2
		echo 'Count should be 777' >&2
esac
echo Extracting 'CC.aux'
sed 's/^X//' > 'CC.aux' << '+ END-OF-FILE ''CC.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: CC.aux,v 3.2 89/10/13 12:04:18 dick Exp $
X
X#
X#		C o m m i t  C o n f i g u r a t i o n   f i l e
X#	Script, to be included.
X#
X#	Assumes set:
X#		$Name
X#		$ACT
X#		$Repository
X#		$Message
X#		$RCSBIN
X#		$RcsCfr
X#		$UsrCfr
X#		$Revision		# -r<number> or empty
X#
X#	Commits the new version of the configuration history file, $UsrCfr
X#
X
X# we need the configuration history file
Xif	# there is a configuration history file
X	[ -r $RcsCfr ]
Xthen	:
Xelse	# try to create it
X	if	echo "Configuration history file handled automatically by CVS" |
X		$ACT $RCSBIN/rcs -i $RcsCfr
X	then	:
X	else	echo $Name on $Repository: could not create \
X			automatic configuration history file >&2
X		exit 1
X	fi
Xfi
X
X# check it in
Xif	# lock the RCS file
X	$ACT $RCSBIN/rcs -q -l $RcsCfr 2>&1
Xthen	:
Xelse	# something went wrong
X	echo $Name on $Repository: could not lock \
X		configuration history file >&2
X	rm $UsrCfr
X	exit 1
Xfi
X
Xif	# check in the configuration record
X	$ACT $RCSBIN/ci $Revision -m"$Message" -f $RcsCfr $UsrCfr 2>&1
Xthen	# the file $UsrCfr will now be gone
X	:
Xelse	# something is wrong; unlock the locked file & remove the added file
X	echo $Name on $Repository: automatic configuration history file \
X			not updated >&2
X	if	# unlock $RcsCfr
X		$ACT $RCSBIN/rcs -q -u $RcsCfr
X	then	:
X	else	# something very wrong
X		echo $Name: HELP: could not UNlock $RcsCfr >&2
X	fi
X
X	rm -f $UsrCfr
X
X	# and give up
X	exit 1
Xfi
X
+ END-OF-FILE CC.aux
chmod 'u=rw,g=r,o=r' 'CC.aux'
set `wc -c 'CC.aux'`
count=$1
case $count in
1510)	:;;
*)	echo 'Bad character count in ''CC.aux' >&2
		echo 'Count should be 1510' >&2
esac
echo Extracting 'CI.aux'
sed 's/^X//' > 'CI.aux' << '+ END-OF-FILE ''CI.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: CI.aux,v 3.1 89/09/25 16:29:46 dick Exp $
X
X#
X#		C h e c k   I n
X#	Script, to be included
X#
X#	Assumes set:
X#		$ACT
X#		$CVSLIB
X#		$Message
X#		$Name
X#		$RCSBIN
X#		$Repository
X#		$User
X#
X#	Does a very careful check-in of the file $User, and tries not
X#	to spoil its modification time (to avoid useless recompilations)
X#
X#	Sets OK to no, if necessary.
X#
X
Xecho Checking in $User\; log: "$Message"
XRcs=$Repository/$User,v
X
X# offer a copy of $User to RCS/ci, to preserve the inode
XOrig=,,$User
X$ACT mv $User $Orig
X$ACT cp $Orig $User
X
Xif	# check in $Rcs
X	$ACT $RCSBIN/ci -m"$Message" $Rcs 2>&1
Xthen	# the file $User will now be gone;
X	# get a new $User, with a possibly updated $Header
X	if	# check out $Rcs into $User, creating a new inode
X		$ACT $RCSBIN/co -q $Rcs
X	then	# restore $Orig from it with as few modifications as possible
X		if	# there were no modifications made by $RCSBIN/co
X			$ACT cmp -s $User $Orig
X		then	:
X		else	# we must copy these modifications to $Orig
X			$ACT cp $User $Orig
X		fi
X		# undo the whole renaming
X		$ACT rm -f $User
X		$ACT mv $Orig $User
X	else	# something is wrong but we have still got $Orig
X		$ACT mv $Orig $User
X		echo $Name: could not check out $User again >&2
X		OK=no
X	fi
X	
X	# get new version number and time stamp
X	. $CVSLIB/VT.aux	# sets $VN_User, $VN_Rcs, $TS_User, $TS_Rcs
X	# and register $User
X	$ACT $CVSLIB/RG.aux $User $VN_Rcs "$TS_User"
Xelse	# something is very wrong
X	# restore the old $User
X	$ACT mv $Orig $User
X	echo $Name: could not check in $User >&2
X	OK=no
X	if	# unlock $Rcs
X		$ACT $RCSBIN/rcs -u $Rcs
X	then	:
X	else
X		echo $Name: could not UNlock $Rcs >&2
X	fi
Xfi
+ END-OF-FILE CI.aux
chmod 'u=rw,g=r,o=r' 'CI.aux'
set `wc -c 'CI.aux'`
count=$1
case $count in
1734)	:;;
*)	echo 'Bad character count in ''CI.aux' >&2
		echo 'Count should be 1734' >&2
esac
echo Extracting 'CS.aux'
sed 's/^X//' > 'CS.aux' << '+ END-OF-FILE ''CS.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: CS.aux,v 3.1 89/09/25 16:30:17 dick Exp $
X
X#
X#		C o l l e c t   S e t s
X#	Script, to be included.
X#
X#	Assumes set:
X#		$@
X#		$CVSLIB
X#		$Name
X#		$User
X#		$VN_Rcs
X#		$VN_User
X#		$TS_Rcs
X#		$TS_User
X#
X#	Collects the interesting file names from the administration and
X#	the repository in a number of shell variables:
X#							solved by:
X#		CLIST	conflict-ridden			(user)
X#		GLIST	modified, needs merging		(--/UV)
X#		MLIST	modified, needs checking in	(CM/--)
X#		OLIST	needs checking out		(--/UV)
X#		ALIST	to be added			(CM/--)
X#		RLIST	to be removed			(CM/--)
X#		WLIST	remove entry			(--/UV)
X#
X#	It sets OK to no if something is wrong.
X#
X
Xfor User in $@
Xdo
X	Rcs=$Repository/$User,v
X	. $CVSLIB/VT.aux	# sets $VN_User, $VN_Rcs, $TS_User, $TS_Rcs
X	
X	# what entry is this?
X	case $VN_User in
X	"")
X		# no entry available, $TS_Rcs is invalid
X		
X		# how is the RCS file?
X		case $VN_Rcs in
X		"")
X			# there is no RCS file either
X			
X			# how is the user file?
X			case "$TS_User" in
X			"")
X				# there is no user file
X				echo $Name: nothing known about $User >&2
X				OK=no
X				;;
X			*)
X				# there is a user file
X				echo $Name: use AE to create entry \
X								for $User >&2
X				OK=no
X				;;
X			esac
X			;;
X		*)
X			# there is an RCS file
X			
X			# how is the user file?
X			case "$TS_User" in
X			"")
X				# there is no user file
X				OLIST="$OLIST $User"
X				;;
X			*)
X				# there is a user file
X				echo $Name: move away $User\; \
X							it is in the way >&2
X				CLIST="$CLIST $User"
X				OK=no
X				;;
X			esac
X			;;
X		esac
X		;;
X	
X	0)
X		# an entry for a new-born file, $TS_Rcs is dummy
X		
X		# how is the user file?
X		case "$TS_User" in
X		"")
X			# there is no user file, but there should be one
X			
X			echo $Name: warning: \
X					new-born $User has disappeared >&2
X			WLIST="$WLIST $User"
X			;;
X		*)
X			# there is a user file
X			
X			# how is the RCS file?
X			case $VN_Rcs in
X			"")
X				# there is no RCS file
X				
X				ALIST="$ALIST $User"
X				;;
X			*)
X				# there is an RCS file
X				
X				echo $Name: conflict: $User created \
X					independently by second party >&2
X				CLIST="$CLIST $User"
X				OK=no
X				;;
X			esac
X			;;
X		esac
X		;;
X
X	-*)
X		# an entry for a removed file, $TS_Rcs is valid
X		
X		# how is the user file?
X		case "$TS_User" in
X		"")
X			# there is no user file (as it should be)
X			
X			# how is the RCS file?
X			case -$VN_Rcs in
X			-)
X				# there is no RCS file
X			
X				# this is all-right, however; it has been
X				# removed independently by second party
X				WLIST="$WLIST $User"
X				;;
X			$VN_User)
X				# the RCS file is the same version as
X				# the user file
X				
X				# and that's OK
X				RLIST="$RLIST $User"
X				;;
X			*)
X				# the RCS file is a newer version than
X				# the user file
X				
X				# and this is definitely not OK
X				echo $Name: conflict: removed $User was \
X						modified by second party >&2
X				CLIST="$CLIST $User"
X				OK=no
X				;;
X			esac
X			;;
X		*)
X			# user file shouldn't be there
X			echo $Name: $User should be removed \
X						and is still there >&2
X			OK=no
X			;;
X		esac
X		;;
X	
X	*)
X		# a normal entry, $TS_Rcs is valid
X		
X		# how is the RCS file?
X		case $VN_Rcs in
X		"")
X			# there is no RCS file
X			
X			# how is the user file?
X			case "$TS_User" in
X			"")
X				# there is no user file
X				echo $Name: warning: $User is not \
X						\(no longer\) pertinent >&2
X				WLIST="$WLIST $User"
X				;;
X			"$TS_Rcs")
X				# the user file is still unmodified
X				echo $Name: $User is no longer \
X							in the repository >&2
X				WLIST="$WLIST $User"
X				;;
X			*)
X				# the user file has been modified
X				echo $Name: conflict: $User is modified but \
X					no longer in the repository >&2
X				CLIST="$CLIST $User"
X				OK=no
X				;;
X			esac
X			;;
X		$VN_User)
X			# the RCS file is the same version as the user file
X			
X			# how is the user file?
X			case "$TS_User" in
X			"")
X				# there is no user file
X				echo $Name: warning: $User was lost >&2
X				OLIST="$OLIST $User"
X				;;
X			"$TS_Rcs")
X				# the user file is still unmodified
X				# nothing special at all!
X				;;
X			*)
X				# the user file has been modified
X				# but do we believe it? This is complicated:
X				. $CVSLIB/ND.aux # sets MLIST, if necessary
X				;;
X			esac
X			;;
X		*)
X			# the RCS file is a newer version than the user file
X			
X			# how is the user file?
X			case "$TS_User" in
X			"")
X				# there is no user file
X				echo $Name: warning: $User was lost >&2
X				OLIST="$OLIST $User"
X				;;
X			"$TS_Rcs")
X				# the user file is still unmodified
X				OLIST="$OLIST $User"
X				;;
X			*)
X				# the user file has been modified
X				GLIST="$GLIST $User"
X				;;
X			esac
X			;;
X		esac
X		;;
X	esac
Xdone
+ END-OF-FILE CS.aux
chmod 'u=rwx,g=rx,o=rx' 'CS.aux'
set `wc -c 'CS.aux'`
count=$1
case $count in
4680)	:;;
*)	echo 'Bad character count in ''CS.aux' >&2
		echo 'Count should be 4680' >&2
esac
echo Extracting 'EF.aux'
sed 's/^X//' > 'EF.aux' << '+ END-OF-FILE ''EF.aux'
X#!/bin/sh
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: EF.aux,v 3.1 89/09/25 16:31:12 dick Exp $
X
X#
X#		E n t r i e s   f i l e   t o   F i l e s   f i l e
X#	Creates a file CVS.adm/Files containing the names that comprise
X#	the project, from CVS.adm/Entries.
X#
X
X<CVS.adm/Entries sed '
X	/^-/d
X	s/.* \(.*\)|/\1/
X' |
Xsort >CVS.adm/Files
+ END-OF-FILE EF.aux
chmod 'u=rwx,g=rx,o=rx' 'EF.aux'
set `wc -c 'EF.aux'`
count=$1
case $count in
414)	:;;
*)	echo 'Bad character count in ''EF.aux' >&2
		echo 'Count should be 414' >&2
esac
echo Extracting 'FN.aux'
sed 's/^X//' > 'FN.aux' << '+ END-OF-FILE ''FN.aux'
X#!/bin/sh
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: FN.aux,v 3.1 89/09/25 16:31:20 dick Exp $
X
X#
X#		F i n d  N a m e s
X#	Writes to standard output all the pertinent file names, both from the
X#	administration (included those that were RMed) and from the
X#	repository $1, sorted. 
X#
X
X(
X	(cd $1; ls -a) | grep ',v$' | sed 's/,v$//'
X	(<CVS.adm/Entries sed 's/.* \(.*\)|/\1/')
X) |
Xsort -u
+ END-OF-FILE FN.aux
chmod 'u=rwx,g=rx,o=rx' 'FN.aux'
set `wc -c 'FN.aux'`
count=$1
case $count in
468)	:;;
*)	echo 'Bad character count in ''FN.aux' >&2
		echo 'Count should be 468' >&2
esac
echo Extracting 'HN.aux'
sed 's/^X//' > 'HN.aux' << '+ END-OF-FILE ''HN.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: HN.aux,v 3.1 89/09/25 16:31:41 dick Exp $
X
X#
X#		H e a d e r   N u m b e r
X#	Script, to be included.
X#
X#	Assumes set:
X#		$RCSBIN
X#		$User
X#
X#	Sets the following shell variable:
X#	HN_user		version number in the RCS Header in the file $User
X#			as found by $RCSBIN/ident; may also be empty, if
X#			there is no RCS Header.
X#
X
XHN_User=`
X	($RCSBIN/ident $User 2>&1) |
X	grep 'Header: .*,v' |
X	sed '
X		s/.*,v //
X		s/ .*//
X	'
X`
X	
+ END-OF-FILE HN.aux
chmod 'u=rw,g=r,o=r' 'HN.aux'
set `wc -c 'HN.aux'`
count=$1
case $count in
547)	:;;
*)	echo 'Bad character count in ''HN.aux' >&2
		echo 'Count should be 547' >&2
esac
echo Extracting 'LR.aux'
sed 's/^X//' > 'LR.aux' << '+ END-OF-FILE ''LR.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: LR.aux,v 3.1 89/09/25 16:32:33 dick Exp $
X
X#
X#		L o c a t e   R C S   F i l e
X#	Script, to be included.
X#
X#	Assumes set:
X#		$Repository
X#		$User
X#
X#	Called when the RCS file sought may be in the attic $Repository/Attic.
X#	Sets $Rcs to $Repository/Attic/$User,v if appropriate and to
X#	$Repository/$User,v otherwise.
X#
X
XRcs=$Repository/$User,v
XOld=$Repository/Attic/$User,v
Xif	# it is in the repository
X	[ -r $Rcs ]
Xthen	:
Xelif	# it is in the attic
X	[ -r $Old ]
Xthen
X	Rcs=$Old
Xelse	# it is treated as if it were in the repository
X	:
Xfi
+ END-OF-FILE LR.aux
chmod 'u=rw,g=r,o=r' 'LR.aux'
set `wc -c 'LR.aux'`
count=$1
case $count in
661)	:;;
*)	echo 'Bad character count in ''LR.aux' >&2
		echo 'Count should be 661' >&2
esac
echo Extracting 'MF.aux'
sed 's/^X//' > 'MF.aux' << '+ END-OF-FILE ''MF.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: MF.aux,v 3.1 89/09/25 16:32:49 dick Exp $
X
X#
X#		M o d i f i e d   F i l e s
X#	Prints the names of the files that have been modified since the last
X#	CM.  The list is constructed by combining the contents of CVS.adm/Mod
X#	(verified to be really different) with time stamp information from
X#	CVS.adm/LastUpdate.
X#
X
X(	# list all files modified between last CM and last UV
X	cat CVS.adm/Mod
X
X	# list all files modified after last UV
X	# get the list of all files in the configuration and of
X	# CVS.adm/LastUpdate, sorted on time
X	ls -lt `cat CVS.adm/Files` CVS.adm/LastUpdate 2>/dev/null |
X	# remove the entry CVS.adm/LastUpdate and anything older
X	sed '/CVS.adm\/LastUpdate/,$d' |
X	# retrieve files name only
X	sed 's/.* //'
X) |
Xsort -u
+ END-OF-FILE MF.aux
chmod 'u=rwx,g=rx,o=rx' 'MF.aux'
set `wc -c 'MF.aux'`
count=$1
case $count in
857)	:;;
*)	echo 'Bad character count in ''MF.aux' >&2
		echo 'Count should be 857' >&2
esac
echo Extracting 'ND.aux'
sed 's/^X//' > 'ND.aux' << '+ END-OF-FILE ''ND.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: ND.aux,v 3.1 89/09/25 16:33:07 dick Exp $
X
X#
X#		N o   D i f f e r e n c e
X#	Script, to be included.
X#
X#	Assumes set:
X#		$ACT
X#		$CVSLIB
X#		$Name
X#		$RCSBIN
X#		$Rcs
X#		$TS_User
X#		$User
X#		$VN_Rcs
X#		$VN_User
X#
X#	The user file looks modified judging from its time stamp; however
X#	it needn't be.  ND.aux finds out whether it is or not.
X#	If it is, it adds its name to the $MLIST.
X#	If it is not, it updates the administration.
X#	It may set OK to 'no'.
X#
X
XTmp=,,$User
Xif	# we can retrieve a provisional copy of $Rcs
X	$RCSBIN/co -p -q -r$VN_User $Rcs >$Tmp
Xthen	# test for differences
X	if	# they are equal
X		cmp -s $User $Tmp
X	then	# there were no real user differences:
X		# update reference time stamp
X		TS_Rcs="$TS_User"
X		$ACT $CVSLIB/RG.aux $User $VN_Rcs "$TS_User"
X	else	# its name belongs in the MLIST
X		MLIST="$MLIST $User"
X	fi
X	
X	rm -f $Tmp
X	
Xelse	# something very wrong
X	echo $Name: could not check out revision $VN_User of $User >&2
X	rm $Tmp
X	OK=no
Xfi
X
+ END-OF-FILE ND.aux
chmod 'u=rwx,g=rx,o=rx' 'ND.aux'
set `wc -c 'ND.aux'`
count=$1
case $count in
1086)	:;;
*)	echo 'Bad character count in ''ND.aux' >&2
		echo 'Count should be 1086' >&2
esac
echo Extracting 'NR.aux'
sed 's/^X//' > 'NR.aux' << '+ END-OF-FILE ''NR.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: NR.aux,v 3.1 89/09/25 16:33:29 dick Exp $
X
X#
X#		N a m e   o f   R e p o s i t o r y
X#	Script, to be included.
X#
X#	Assumes set:
X#		$Name
X#		$Repository (optionally)
X#	Sets:
X#		$Repository
X#
X#	Determines the name of the RCS repository and sets $Repository
X#	accordingly. If $Repository is already set, then that is the name,
X#	otherwise the name is retrieved from CVS.adm/Repository.
X#	Checks the presence of the repository.
X#
X
Xif	[ "$Repository" = "" ]
Xthen	# retrieve CVS.adm/Repository
X	if	# there is no administration directory
X		[ ! -d CVS.adm ]
X	then
X		echo $Name: there is no configuration under CVS here\; \
X			do CV first >&2
X		exit 1
X	fi
X
X	if	# the necessary files are there
X		[ -r CVS.adm/Repository -a -r CVS.adm/Entries ]
X	then	# read the name of the RCS repository from the file
X		Repository=`cat CVS.adm/Repository`
X	else	# no good
X		echo $Name: \*PANIC\* administration files missing >&2
X		exit 1
X	fi
Xfi
X
Xif	# the promised repository isn't there
X	[ ! -d $Repository ]
Xthen
X	echo $Name: there is no repository $Repository >&2
X	exit 1
Xfi
X
Xexport Repository
+ END-OF-FILE NR.aux
chmod 'u=rwx,g=rx,o=rx' 'NR.aux'
set `wc -c 'NR.aux'`
count=$1
case $count in
1195)	:;;
*)	echo 'Bad character count in ''NR.aux' >&2
		echo 'Count should be 1195' >&2
esac
echo Extracting 'OP.aux'
sed 's/^X//' > 'OP.aux' << '+ END-OF-FILE ''OP.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: OP.aux,v 3.1 89/09/25 16:33:40 dick Exp $
X
X#
X#		O p t i o n s
X#	Script, to be included.
X#
X#	Collects options from $@ and puts them in $Options.
X#	Each option, including the first, will be preceded by a space.
X#
X
XGO_ON=true
Xwhile	# there may still be an option
X	$GO_ON
Xdo
X	case $1 in
X	-*)
X		Options="$Options $1"
X		shift
X		;;
X	*)
X		GO_ON=false
X		;;
X	esac
Xdone
+ END-OF-FILE OP.aux
chmod 'u=rw,g=r,o=r' 'OP.aux'
set `wc -c 'OP.aux'`
count=$1
case $count in
485)	:;;
*)	echo 'Bad character count in ''OP.aux' >&2
		echo 'Count should be 485' >&2
esac
echo Extracting 'RG.aux'
sed 's/^X//' > 'RG.aux' << '+ END-OF-FILE ''RG.aux'
X#!/bin/sh
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: RG.aux,v 3.1 89/09/25 16:34:19 dick Exp $
X
X#
X#		R e g i s t e r
X#	Enters file $1 into the administration with version number $2
X#	and time stamp $3.  Removes the old entry first, if necessary.
X#
X#	Assumes set:
X#		$CVSLIB
X#
X
X$CVSLIB/SC.aux $1			# scratch the entry
Xecho "$2|$3|" >>CVS.adm/Entries		# and append a new one
+ END-OF-FILE RG.aux
chmod 'u=rwx,g=rx,o=rx' 'RG.aux'
set `wc -c 'RG.aux'`
count=$1
case $count in
456)	:;;
*)	echo 'Bad character count in ''RG.aux' >&2
		echo 'Count should be 456' >&2
esac
echo Extracting 'SC.aux'
sed 's/^X//' > 'SC.aux' << '+ END-OF-FILE ''SC.aux'
X#!/bin/sh
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: SC.aux,v 3.1 89/09/25 16:34:48 dick Exp $
X
X#
X#		S c r a t c h
X#	Scratches file $1 from the administration
X#
X
Xmv CVS.adm/Entries CVS.adm/Entries.Backup
Xfgrep -v " $1|" CVS.adm/Entries.Backup >CVS.adm/Entries
+ END-OF-FILE SC.aux
chmod 'u=rwx,g=rx,o=rx' 'SC.aux'
set `wc -c 'SC.aux'`
count=$1
case $count in
343)	:;;
*)	echo 'Bad character count in ''SC.aux' >&2
		echo 'Count should be 343' >&2
esac
echo Extracting 'SL.aux'
sed 's/^X//' > 'SL.aux' << '+ END-OF-FILE ''SL.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: SL.aux,v 3.1 89/09/25 16:34:58 dick Exp $
X
X#
X#		S e t   L o c k
X#	Script, to be included.
X#
X#	Assumes set:
X#		$Name
X#		$Repository
X#		$LCK		name of lock
X#
X#	Persistently tries to make the directory $LCK, which serves as
X#	a lock.
X#
X
Xuntil	# we can enter the critical section
X	trap '' 1 2 3 15		# play deaf
X	mkdir $LCK >/dev/null 2>/dev/null
Xdo
X	# we missed it this cycle
X	echo $Name: `date`: waiting for access to $Repository
X	
X	# sleep with both ears open
X	trap 'exit 1' 1 2 3 15
X	sleep 60
Xdone
+ END-OF-FILE SL.aux
chmod 'u=rw,g=r,o=r' 'SL.aux'
set `wc -c 'SL.aux'`
count=$1
case $count in
622)	:;;
*)	echo 'Bad character count in ''SL.aux' >&2
		echo 'Count should be 622' >&2
esac
echo Extracting 'VN.aux'
sed 's/^X//' > 'VN.aux' << '+ END-OF-FILE ''VN.aux'
X#!/bin/sh
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: VN.aux,v 3.1 89/09/25 16:35:19 dick Exp $
X
X#
X#		V e r s i o n   N u m b e r
X#	Writes the version number of the most recent revision of $1
X#	to standard output.
X#	This is sloppy, but the only way to do it, short of analyzing
X#	the *,v file itself.
X#
X#	Assumes set:
X#		$RCSBIN
X#
X
X(	#	The following stupid construction is necessary, since the
X	#	shell sometimes generates a NL when a pipe breaks, as it
X	#	does here, where sed stops after a few lines.  Letting
X	#	sed process all the rest is also a shame.
X	#
X$RCSBIN/rlog $1 |
Xsed -n '
X	/^head:/{
X		s/.* //p
X		q
X	}
X'
X) 2>/dev/null
+ END-OF-FILE VN.aux
chmod 'u=rwx,g=rx,o=rx' 'VN.aux'
set `wc -c 'VN.aux'`
count=$1
case $count in
714)	:;;
*)	echo 'Bad character count in ''VN.aux' >&2
		echo 'Count should be 714' >&2
esac
echo Extracting 'VT.aux'
sed 's/^X//' > 'VT.aux' << '+ END-OF-FILE ''VT.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: VT.aux,v 3.1 89/09/25 16:35:27 dick Exp $
X
X#
X#		V e r s i o n   &   T i m e   S t a m p
X#	Script, to be included.
X#
X#	Assumes set:
X#		$CVSLIB
X#		$Rcs
X#		$User
X#
X#	Sets the following shell variables:
X#	VN_User		version # of the RCS file the user file derives from
X#			may also be:
X#				empty:		no entry for user file
X#				0:		user file is new
X#				-$VN_User:	user file is to be removed
X#	VN_Rcs		version # of active RCS file
X#				is empty for absent RCS file
X#	TS_User		present time stamp of the user file
X#				is empty for absent user file
X#	TS_Rcs		time stamp of the lastest check-out of the RCS file.
X#
X#	The syntax of an entry is
X#		<version-number>|<time-stamp>|
X#	and since the time stamp is obtained through ls, it includes
X#	the file name.
X#
X
XVN_Rcs=`$CVSLIB/VN.aux $Rcs`
X
Xif	# the user file exists
X	[ -r $User ]
Xthen	#get its time stamp
X	TS_User=`ls -ld $User`
Xelse	# yield null
X	TS_User=
Xfi
X
XENTRY=`fgrep " $User|" CVS.adm/Entries`
Xif	# the entry is non-empty
X	[ "$ENTRY" != "" ]
Xthen	# dissect it
X	VN_User=`expr "$ENTRY" : '\(.*\)|.' `
X	TS_Rcs=`expr "$ENTRY" : '.*|\(.*\)|' `
Xelse	# yield nulls
X	VN_User=
X	TS_Rcs=
Xfi
+ END-OF-FILE VT.aux
chmod 'u=rwx,g=rx,o=rx' 'VT.aux'
set `wc -c 'VT.aux'`
count=$1
case $count in
1253)	:;;
*)	echo 'Bad character count in ''VT.aux' >&2
		echo 'Count should be 1253' >&2
esac
echo Extracting 'WL.aux'
sed 's/^X//' > 'WL.aux' << '+ END-OF-FILE ''WL.aux'
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: WL.aux,v 3.2 89/10/13 12:04:40 dick Exp $
X
X#
X#		W r i t e   L o c k
X#	Script, to be included.
X#
X#	Assumes set:
X#		$Repository
X#		$Name
X#		$CVSLIB
X#		$AutoRemove		set to yes if lock is to be removed
X#					automatically upon script exit
X#
X#	Sets a write lock in $Repository for exclusive write access
X#
X
XLCK=$Repository/\#cvs.lock		# the lock
XTFL=$Repository/\#cvs.tfl.$$		# a temporary test file
XRFL=$Repository/\#cvs.rfl		# pattern of the read flags
XWFL=$Repository/\#cvs.wfl		# the general write flag
X
X# do we have write access at all?
Xif	# we can write at all
X	cp /dev/null $TFL >/dev/null 2>/dev/null
Xthen	# OK so far
X	rm $TFL
Xelse	# not so OK
X	echo $Name: you have no write permission in $Repository >&2
X	exit 1
Xfi
X
X# set the lock itself
X. $CVSLIB/SL.aux			# persistently tries to mkdir $LCK
X
X# set trap to remove flag and lock on interrupt
Xtrap 'rm -f $WFL; rmdir $LCK; exit 1' 1 2 3 15
X
X# conditionally set trap to remove flag and lock on exit
Xcase "$AutoRemove" in
Xyes)	# lock to be removed automatically upon exit
X	trap 'rm -f $WFL; rmdir $LCK; exit 0' 0
X	;;
Xesac
X
X# start of critical section
X
X# notify others of intention
Xcp /dev/null $WFL			# plant write flag
X
X# wait for the readers to disappear
Xwhile	# there are still read flags
X	[ "`echo $RFL.* | grep -v '\*'`" != "" ]
Xdo
X	echo $Name: `date`: waiting for readers to disappear from $Repository
X	sleep 60
Xdone
X
X# the caller of WL.aux can now write in safety
X
+ END-OF-FILE WL.aux
chmod 'u=rw,g=r,o=r' 'WL.aux'
set `wc -c 'WL.aux'`
count=$1
case $count in
1548)	:;;
*)	echo 'Bad character count in ''WL.aux' >&2
		echo 'Count should be 1548' >&2
esac
echo Extracting 'historian'
sed 's/^X//' > 'historian' << '+ END-OF-FILE ''historian'
X#!/bin/sh
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: historian,v 3.1 89/09/25 16:36:25 dick Exp $
X
X#
X#	Historian: ad-hoc configuration history reconstruction program
X#
X#		historian [ repository ]
X#	attempts to reconstruct the configuration history file of the
X#	repository, using reasonable(?) heuristics.  If no repository is given,
X#	the repository of the present directory is used.
X#
X#	This simple script assumes that there are no "removed files", i.e.,
X#	that the Attic is non-existent or empty.
X#
XName=historian; export Name
X
X# CVSBIN, CVSLIB and RCSBIN directories
XCVSBIN=/home/top/dick/cvs
XCVSLIB=/home/top/dick/cvs
XRCSBIN=${RCSBIN-/usr/local/bin}
Xexport CVSBIN CVSLIB RCSBIN
X
X# avoid spurious identifications
XPATH=${CVSPATH-/bin:/usr/bin}; export PATH
X
X# determine the name of the repository
XRepository=$1
X. $CVSLIB/NR.aux
X
X# worry about the Attic
Xif	# there is an Attic
X	[ -d $Repository/Attic ]
Xthen	# it may still be empty
X	REMOVED=`ls $Repository/Attic`
Xfi
X
Xif	# some files have been removed
X	[ -n "$REMOVED" ]
Xthen	# tell the truth
X	echo "The configuration history file reconstructed for $Repository"
X	echo "will not be completely correct, although it is still a good"
X	echo "approximation. Obtaining a correct configuration history file"
X	echo "requires manual assistance concerning the removal dates of"
X	echo "$REMOVED" |
X	sed 's/,v//'
X	echo "See the manual page of 'historian' for further information."
X	echo ""
Xfi
X
X$CVSBIN/hist1 $Repository |
X$CVSBIN/hist2 $Repository |
Xsh
X
+ END-OF-FILE historian
chmod 'u=rwx,g=rx,o=rx' 'historian'
set `wc -c 'historian'`
count=$1
case $count in
1576)	:;;
*)	echo 'Bad character count in ''historian' >&2
		echo 'Count should be 1576' >&2
esac
echo Extracting 'hist1'
sed 's/^X//' > 'hist1' << '+ END-OF-FILE ''hist1'
X#!/bin/sh
X#	This file is part of the Concurrent Versions System CVS.
X#	Written by Dick Grune, Vrije Universiteit, Amsterdam.
X#	$Header: hist1,v 3.2 89/10/13 11:54:39 dick Exp $
X
X#
X#	Historian: ad-hoc configuration history reconstruction program, part 1
X#
X#		hist1 [ repository ]
X#	writes on standard output phase 1 of the reconstruction of the
X#	configuration history file of the repository, using reasonable(?)
X#	heuristics. If no repository is given, the repository of the present
X#	directory is used.
X#
XName=hist1; export Name
X
X# CVSBIN, CVSLIB and RCSBIN directories
XCVSBIN=/home/top/dick/cvs
XCVSLIB=/home/top/dick/cvs
XRCSBIN=${RCSBIN-/usr/local/bin}
Xexport CVSBIN CVSLIB RCSBIN
X
X# avoid spurious identifications
XPATH=${CVSPATH-/bin:/usr/bin}; export PATH
X
X# determine the name of the repository
XRepository=$1
X. $CVSLIB/NR.aux
X
X# get the whole rlog of all files
XRCSFILES=`
X	ls $Repository/*,v $Repository/.*,v \
X		$Repository/Attic/*,v $Repository/Attic/.*,v 2>/dev/null |
X	grep -v "\*"
X`
Xfor Rcs in $RCSFILES
Xdo
X	$RCSBIN/rlog $Rcs
Xdone |
X
X# remove all kinds of garbage
Xtr '\200-\377' '' |
X
X# identify and combine revision and date lines
Xsed '
X	/^--*$/{
X		N
X		s/\nrevision /\
X<REV> /
X		N
X		s/\ndate: / /
X		s/; *author:/ /
X		s/;.*//
X	}
X	/^==*$/s/.*/----------------------------/
X' |
X
X# construct one line for each file modification
Xawk '
X	$1 == "RCS" && running == 0 {
X		# establish file name
X		fname = $6;
X	}
X	$1 == "<REV>" {
X		# print			date time fname rev author
X		printf("%s %s %s %s %s ; ", $3, $4, fname, $2, $5);
X		running = 1;
X	}
X	$1 ~ /^--*$/ && running != 0 {
X		# revision description terminator
X		printf("\n");
X	}
X	$1 != "<REV>" && $1 !~ /^--*$/ && running != 0 {
X		# one line of revision description
X		if (running > 1) {
X			# multi-line revision message
X			printf("\\n");
X		}
X		printf("%s", $0);
X		running++;
X	}
X' |
X
X# sort on date and time
Xsort -n |
X
X# put a separator after each group of identical messages
Xawk -F\; '
X	{	if (msg != "" && $2 != msg) {print ""; }
X		msg = $2;
X		print;
X	}
X	END	{
X		if (msg != "") {print ""; }
X	}
X'
X
Xexit 0
X
+ END-OF-FILE hist1
chmod 'u=rwx,g=rx,o=rx' 'hist1'
set `wc -c 'hist1'`
count=$1
case $count in
2055)	:;;
*)	echo 'Bad character count in ''hist1' >&2
		echo 'Count should be 2055' >&2
esac
exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.