--- Begin Message ---
Package: rcs
Version: 5.7-17
Severity: wishlist
Tags: patch
Recent versions of CVS and CVSNT add a new phrase `commitid ...;' to
attach a unique commitid to the delta section of all files committed at
the same time. This allows users to better be able to identify the set
of files that were changed as a unit.
Production versions of RCS do not know what to do with this information
and generate a message to STDERR about it such as the following:
% rlog CVSROOT/config,v > /dev/null
rlog: CVSROOT/config,v: warning: Unknown phrases like `commitid ...;' are
present.
%
The standard workaround is for users to use the -q switch to avoid
getting these messages on STDERR.
% rlog -q CVSROOT/config,v > /dev/null
%
However, some users may not desire to use the -q switch and instead
might even want to see the commitid information as a part of the rlog
output.
A patch against rcs-5.7 to teach it how to handle this new phrase and to
use it for its own commits is included in the CVS source repository
contrib directory and is presented here for your consideration.
The URL is
http://cvs.savannah.nongnu.org/viewcvs/*checkout*/ccvs/contrib/rcs-5.7-commitid.patch?rev=HEAD&root=cvs
The attached patch is a snapshot of version 1.9 of this file.
I hope you find the patch to be useful enough to incorporate into a future
debian revision of rcs.
-- Mark
ChangeLog entry:
Thanks to Paul Eggert who suggested using better random numbers as
well as using the base62 format for compactness and provided the
sample divide_by and convert functions used here.
2005-10-04 Mark D. Baushke <[EMAIL PROTECTED]>
* src/rcssyn.c (getdelta): Initialize Delta->commitid.
2005-09-29 Mark D. Baushke <[EMAIL PROTECTED]>
* man/rcsfile.5in: Document new commitid delta phrase.
* man/rcsfile.5: Regenerated.
* src/ci.c (RANDOM_BYTES, COMMITID_RAW_SIZE): New constants.
(mainProg): Add commitid to delta records. Use
random data and represent in base62 or fall back to using the
same basic format construction as is used by CVS and CVSNT.
(divide_by): New function used by convert.
(convert): New fucntion to convert to base62.
* rcsbase.h (commitidsize): Room for base62 encoded block or
32bit pid plus a 32bit time rendered as hex plus one
NUL byte round up to 64.
(struct hshentry): Add new commitid field.
* src/rcsgen.c (putdelta): Preserve old commitid entries.
* src/rcssyn.c (Kcommitid): New global constant keyword.
(getdelta): Add optional parsing for it.
* src/rlog.c (putadelta): Print it out.
Index:man/rcsfile.5
--- man/rcsfile.5~ 1995-06-16 06:58:26.000000000 +0000
+++ man/rcsfile.5 2005-09-27 20:53:01.023504000 +0000
@@ -1,4 +1,4 @@
-.lf 1 ./rcsfile.5in
+.lf 1 rcsfile.5in
.\" Set p to 1 if your formatter can handle pic output.
.if t .nr p 1
.de Id
@@ -69,6 +69,7 @@ nonterminal symbols are in
\f3state\fP {\f2id\fP}\f3;\fP
\f3branches\fP {\f2num\fP}*\f3;\fP
\f3next\fP {\f2num\fP}\f3;\fP
+ { \f3commitid\fP \f2id\fP\f3;\fP }
{ \f2newphrase\fP }*
.LP
\f2desc\fP ::= \f3desc\fP \f2string\fP
@@ -128,6 +129,18 @@ and all the digits of years thereafter.
Dates use the Gregorian calendar; times use UTC.
.PP
The
+.I commitid
+is followed by an
+.I id
+token. This token is intended to be unique across
+multiple files and is used to help group files as
+being a part of the same logical commit.
+This token must uniquely identify the commit
+operation that was applied to a set of RCS files.
+In particular, it must be unique among all the
+commitids in this file.
+.PP
+The
.I newphrase
productions in the grammar are reserved for future extensions
to the format of \*r files.
@@ -230,7 +243,7 @@ The following diagram shows an example o
.fi
.\}
.if \np \{\
-.lf 232
+.lf 245
.PS 4.250i 3.812i
.\" -2.0625 -4.25 1.75 0
.\" 0.000i 4.250i 3.812i 0.000i
@@ -239,7 +252,7 @@ The following diagram shows an example o
.nr 0x 1
\h'3.812i'
.sp -1
-.lf 242
+.lf 255
\h'2.062i-(\w'Head'u/2u)'\v'0.125i-(0v/2u)+0v+0.22m'Head
.sp -1
\h'2.062i'\v'0.250i'\D'l0.000i 0.500i'
@@ -256,7 +269,7 @@ The following diagram shows an example o
.sp -1
\h'1.688i'\v'0.750i'\D'l0.000i 0.500i'
.sp -1
-.lf 244
+.lf 257
\h'2.062i-(\w'2.1'u/2u)'\v'1.000i-(0v/2u)+0v+0.22m'2.1
.sp -1
\h'2.062i'\v'1.250i'\D'l0.000i 0.500i'
@@ -265,7 +278,7 @@ The following diagram shows an example o
.sp -1
\h'2.062i'\v'1.750i'\D'l-0.025i -0.100i'
.sp -1
-.lf 246
+.lf 259
\h'2.062i-(\w'1.3'u/2u)'\v'2.000i-(1v/2u)+0v+0.22m'1.3
.sp -1
\h'2.062i'\v'2.250i'\D'l-0.375i -0.500i'
@@ -280,7 +293,7 @@ The following diagram shows an example o
.sp -1
\h'1.375i'\v'1.500i'\D'l0.025i 0.100i'
.sp -1
-.lf 249
+.lf 262
\h'1.375i-(\w'1.3.1.1'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.3.1.1
.sp -1
\h'1.375i'\v'1.000i'\D'l-0.375i 0.500i'
@@ -295,7 +308,7 @@ The following diagram shows an example o
.sp -1
\h'2.062i'\v'2.750i'\D'l-0.025i -0.100i'
.sp -1
-.lf 252
+.lf 265
\h'2.062i-(\w'1.2'u/2u)'\v'3.000i-(1v/2u)+0v+0.22m'1.2
.sp -1
\h'2.062i'\v'3.250i'\D'l-0.375i -0.500i'
@@ -310,7 +323,7 @@ The following diagram shows an example o
.sp -1
\h'0.375i'\v'2.500i'\D'l0.025i 0.100i'
.sp -1
-.lf 255
+.lf 268
\h'0.375i-(\w'1.2.1.1'u/2u)'\v'2.250i-(1v/2u)+1v+0.22m'1.2.1.1
.sp -1
\h'0.375i'\v'2.000i'\D'l-0.375i 0.500i'
@@ -325,7 +338,7 @@ The following diagram shows an example o
.sp -1
\h'0.375i'\v'1.500i'\D'l0.025i 0.100i'
.sp -1
-.lf 257
+.lf 270
\h'0.375i-(\w'1.2.1.3'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.2.1.3
.sp -1
\h'0.375i'\v'1.000i'\D'l-0.375i 0.500i'
@@ -340,7 +353,7 @@ The following diagram shows an example o
.sp -1
\h'2.750i'\v'2.500i'\D'l0.025i 0.100i'
.sp -1
-.lf 261
+.lf 274
\h'2.750i-(\w'1.2.2.1'u/2u)'\v'2.250i-(1v/2u)+1v+0.22m'1.2.2.1
.sp -1
\h'2.750i'\v'2.000i'\D'l-0.375i 0.500i'
@@ -355,7 +368,7 @@ The following diagram shows an example o
.sp -1
\h'3.438i'\v'1.250i'\D'l0.025i 0.100i'
.sp -1
-.lf 264
+.lf 277
\h'3.438i-(\w'\s-21.2.2.1.1.1\s0'u/2u)'\v'1.000i-(1v/2u)+1v+0.22m'\s-21.2.2.1.1.1\s0
.sp -1
\h'3.438i'\v'0.750i'\D'l-0.375i 0.500i'
@@ -370,7 +383,7 @@ The following diagram shows an example o
.sp -1
\h'2.750i'\v'1.500i'\D'l0.025i 0.100i'
.sp -1
-.lf 267
+.lf 280
\h'2.750i-(\w'1.2.2.2'u/2u)'\v'1.250i-(1v/2u)+1v+0.22m'1.2.2.2
.sp -1
\h'2.750i'\v'1.000i'\D'l-0.375i 0.500i'
@@ -385,7 +398,7 @@ The following diagram shows an example o
.sp -1
\h'2.062i'\v'3.750i'\D'l-0.025i -0.100i'
.sp -1
-.lf 270
+.lf 283
\h'2.062i-(\w'1.1'u/2u)'\v'4.000i-(1v/2u)+0v+0.22m'1.1
.sp -1
\h'2.062i'\v'4.250i'\D'l-0.375i -0.500i'
@@ -398,9 +411,9 @@ The following diagram shows an example o
.if \n(00 .fi
.br
.nr 0x 0
-.lf 271
+.lf 284
.PE
-.lf 272
+.lf 285
.\}
.PP
.SH IDENTIFICATION
Index:man/rcsfile.5in
--- man/rcsfile.5in~ 1995-06-05 08:28:35.000000000 +0000
+++ man/rcsfile.5in 2005-09-27 20:52:46.424504000 +0000
@@ -68,6 +68,7 @@ nonterminal symbols are in
\f3state\fP {\f2id\fP}\f3;\fP
\f3branches\fP {\f2num\fP}*\f3;\fP
\f3next\fP {\f2num\fP}\f3;\fP
+ { \f3commitid\fP \f2id\fP\f3;\fP }
{ \f2newphrase\fP }*
.LP
\f2desc\fP ::= \f3desc\fP \f2string\fP
@@ -127,6 +128,18 @@ and all the digits of years thereafter.
Dates use the Gregorian calendar; times use UTC.
.PP
The
+.I commitid
+is followed by an
+.I id
+token. This token is intended to be unique across
+multiple files and is used to help group files as
+being a part of the same logical commit.
+This token must uniquely identify the commit
+operation that was applied to a set of RCS files.
+In particular, it must be unique among all the
+commitids in this file.
+.PP
+The
.I newphrase
productions in the grammar are reserved for future extensions
to the format of \*r files.
Index:src/rcsbase.h
--- src/rcsbase.h~ 1995-06-16 06:19:24.000000000 +0000
+++ src/rcsbase.h 2005-09-28 21:47:51.490505000 +0000
@@ -222,6 +222,11 @@ Report problems and direct all questions
/* 1 sets the default locking to strict; */
/* used in production environments. */
+/* base64_encode(128 random bits) needs 24 bytes + 1 for NUL */
+/* time_t may be 64bits on some machines needs 16 bytes + 1 as hex */
+#define commitidsize 64 /* time+1+base64(128bits)+1 | pid+time+rand+1 */
+#define urandom_dev "/dev/urandom"
+
#define yearlength 16 /* (good through AD 9,999,999,999,999,999) */
#define datesize (yearlength+16) /* size of output of time2date */
#define RCSTMPPREFIX '_' /* prefix for temp files in working dir */
@@ -358,6 +363,7 @@ struct hshentry {
char const * lockedby; /* who locks the revision */
char const * state; /* state of revision (Exp by default) */
char const * name; /* name (if any) by which retrieved */
+ char const * commitid; /* text string to associate commits */
struct cbuf log; /* log message requested at checkin */
struct branchhead * branches; /* list of first revisions on branches*/
struct cbuf ig; /* ignored phrases in admin part */
@@ -662,6 +668,7 @@ extern int TotalDeltas;
extern char const *const expand_names[];
extern char const
Kaccess[], Kauthor[], Kbranch[], Kcomment[],
+ Kcommitid[],
Kdate[], Kdesc[], Kexpand[], Khead[], Klocks[], Klog[],
Knext[], Kstate[], Kstrict[], Ksymbols[], Ktext[];
void unexpected_EOF P((void)) exiting;
Index:src/ci.c
--- src/ci.c~ 1995-06-16 06:19:24.000000000 +0000
+++ src/ci.c 2005-09-29 21:57:57.814504000 +0000
@@ -262,6 +262,10 @@ static void cleanup P((void));
static void incnum P((char const*,struct buf*));
static void addassoclst P((int,char const*));
+enum {RANDOM_BYTES = 8};
+enum {COMMITID_RAW_SIZE = (sizeof(time_t) + RANDOM_BYTES)};
+static void convert P((char const input[COMMITID_RAW_SIZE], char *output));
+
static FILE *exfile;
static RILE *workptr; /* working file pointer */
static struct buf newdelnum; /* new revision number */
@@ -285,6 +289,7 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.30 1
char olddate[datesize];
char newdatebuf[datesize + zonelenmax];
char targetdatebuf[datesize + zonelenmax];
+ char commitid[commitidsize];
char *a, **newargv, *textfile;
char const *author, *krev, *rev, *state;
char const *diffname, *expname;
@@ -309,6 +314,45 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.30 1
suffixes = X_DEFAULT;
nextassoc = &assoclst;
+ {
+ char buf[COMMITID_RAW_SIZE] = { 0, };
+ ssize_t len = 0;
+ time_t rightnow = time (NULL);
+ char *startrand = buf + sizeof (time_t);
+ unsigned char *p = (unsigned char *) startrand;
+ size_t randbytes = RANDOM_BYTES;
+ int flags = O_RDONLY;
+ int fd;
+#ifdef O_NOCTTY
+ flags |= O_NOCTTY;
+#endif
+ if (rightnow != (time_t)-1)
+ while (rightnow > 0) {
+ *--p = rightnow % (UCHAR_MAX + 1);
+ rightnow /= UCHAR_MAX + 1;
+ }
+ else {
+ /* try to use more random data */
+ randbytes = COMMITID_RAW_SIZE;
+ startrand = buf;
+ }
+ fd = open (urandom_dev, flags);
+ if (fd >= 0) {
+ len = read (fd, startrand, randbytes);
+ close (fd);
+ }
+ if (len <= 0) {
+ /* no random data was available so use pid */
+ long int pid = (long int)getpid ();
+ p = (unsigned char *) (startrand + sizeof (pid));
+ while (pid > 0) {
+ *--p = pid % (UCHAR_MAX + 1);
+ pid /= UCHAR_MAX + 1;
+ }
+ }
+ convert(buf, commitid);
+ }
+
argc = getRCSINIT(argc, argv, &newargv);
argv = newargv;
while (a = *++argv, 0<--argc && *a++=='-') {
@@ -532,6 +576,8 @@ mainProg(ciId, "ci", "$Id: ci.c,v 5.30 1
newdelta.name = 0;
clear_buf(&newdelta.ig);
clear_buf(&newdelta.igtext);
+ /* set commitid */
+ newdelta.commitid=commitid;
/* set author */
if (author)
newdelta.author=author; /* set author given by -w */
@@ -1317,3 +1363,38 @@ addassoclst(flag, sp)
*nextassoc = pt;
nextassoc = &pt->nextsym;
}
+
+static char const alphabet[62] =
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+/* Divide BUF by D, returning the remainder. Replace BUF by the
+ quotient. BUF[0] is the most significant part of BUF.
+ D must not exceed UINT_MAX >> CHAR_BIT. */
+static unsigned int
+divide_by (unsigned char buf[COMMITID_RAW_SIZE], unsigned int d)
+{
+ unsigned int carry = 0;
+ int i;
+ for (i = 0; i < COMMITID_RAW_SIZE; i++)
+ {
+ unsigned int byte = buf[i];
+ unsigned int dividend = (carry << CHAR_BIT) + byte;
+ buf[i] = dividend / d;
+ carry = dividend % d;
+ }
+ return carry;
+}
+
+static void
+convert (char const input[COMMITID_RAW_SIZE], char *output)
+{
+ static char const zero[COMMITID_RAW_SIZE] = { 0, };
+ unsigned char buf[COMMITID_RAW_SIZE];
+ size_t o = 0;
+ memcpy (buf, input, COMMITID_RAW_SIZE);
+ while (memcmp (buf, zero, COMMITID_RAW_SIZE) != 0)
+ output[o++] = alphabet[divide_by (buf, sizeof alphabet)];
+ if (! o)
+ output[o++] = '0';
+ output[o] = '\0';
+}
Index:src/rcsgen.c
--- src/rcsgen.c~ 1995-06-16 06:19:24.000000000 +0000
+++ src/rcsgen.c 2005-09-27 22:08:47.421504000 +0000
@@ -547,6 +547,9 @@ putdelta(node, fout)
aprintf(fout, ";\n%s\t%s;\n", Knext, node->next?node->next->num:"");
awrite(node->ig.string, node->ig.size, fout);
+
+ if (node->commitid)
+ aprintf(fout, "%s\t%s;\n", Kcommitid, node->commitid);
}
Index:src/rcssyn.c
--- src/rcssyn.c~ 1995-06-16 06:19:24.000000000 +0000
+++ src/rcssyn.c 2005-10-04 08:05:21.000000000 +0000
@@ -171,6 +171,7 @@ char const
Kauthor[] = "author",
Kbranch[] = "branch",
Kcomment[] = "comment",
+ Kcommitid[] = "commitid",
Kdate[] = "date",
Kdesc[] = "desc",
Kexpand[] = "expand",
@@ -433,6 +434,14 @@ getdelta()
Delta->lockedby = 0;
Delta->log.string = 0;
Delta->selector = true;
+
+ if (getkeyopt(Kcommitid)) {
+ Delta->commitid = NextString;
+ nextlex();
+ getsemi(Kcommitid);
+ } else
+ Delta->commitid = NULL;
+
Delta->ig = getphrases(Kdesc);
TotalDeltas++;
return (true);
Index:src/rlog.c
--- src/rlog.c~ 1995-06-16 06:19:24.000000000 +0000
+++ src/rlog.c 2005-09-26 17:23:55.257504000 +0000
@@ -591,6 +591,10 @@ putadelta(node,editscript,trunk)
aprintf(out, insDelFormat,
editscript->insertlns, editscript->deletelns);
+ if ( node->commitid )
+ aprintf(out, "%s commitid: %s", (editscript) ? ";" : "",
+ node->commitid);
+
newbranch = node->branches;
if ( newbranch ) {
bufautobegin(&branchnum);
pgpk3KPLJrnZ6.pgp
Description: PGP signature
--- End Message ---