[PATCH][RFC] Support for keyword expansion

Goffredo Baroncelli kreijack at libero.it
Tue Aug 30 14:29:38 CDT 2005


Hi all,

the patch below is an initial support for a keywords expansion framework. 
The patch works expanding the keyword when the file is written to the working dir,
and collapsing the keyword ( '$Date: 11/22/33... $' -> '$Date: $' ) when the file 
is read from the working dir. On the repository the keywords are collapsed

Now the only supported keywords are:

CheckOutDate:  checkout date
RevShort:  checkout revision in short format
Rev:   checkout revision
Date:   revision date


examples:

$ cat a
 bla bla bla

$Rev: 5c0bbb2cc5ada491f53dbee6ff8845456073ff26 $
$RevShort: 5c0bbb2c $
$CheckOutDate: Tue Aug 30 20:37:00 2005 $
$Date: Tue Aug 30 20:36:38 2005 +0200 $

bla bla bla
$ hg log
changeset:   2:5c0bbb2cc5ad
tag:         tip
user:        kreijack at inwind.REMOVEME.it
date:        Tue Aug 30 20:36:38 2005 +0200
summary:     rev added

[...]
#
# regen the 'a' file from the repository, note the different CheckOutDate
#
$ rm a
$ hg co 
$ cat a
 bla bla bla

$Rev: 5c0bbb2cc5ada491f53dbee6ff8845456073ff26 $
$RevShort: 5c0bbb2c $
$CheckOutDate: Tue Aug 30 20:53:59 2005 $
$Date: Tue Aug 30 20:36:38 2005 +0200 $

bla bla bla

#
# The diffs/merge are indifferent to the keyword expansion:
#
$ head a
 bla bla bla

$Rev: 5c0bbb2cc5ada491f53dbee6ff8845456073ff26 $
$RevShort: 5c0bbb2c $
$CheckOutDate: Tue Aug 30 20:53:59 2005 $
$Date: Tue Aug 30 20:36:38 2005 +0200 $

bla bla bla
$ rm a
$ hg co
$ touch a
#
# even tough the CheckOutDate line is different, and the time of the file is
# different the hg diff command shows nothing
#
$ hg diff a
$ head a
 bla bla bla

$Rev: 5c0bbb2cc5ada491f53dbee6ff8845456073ff26 $
$RevShort: 5c0bbb2c $
$CheckOutDate: Tue Aug 30 21:05:40 2005 $
$Date: Tue Aug 30 20:36:38 2005 +0200 $

bla bla bla


The implemented keywords are not very useful, but the patch should be only a 
start point, to begin the discussion.


TODO:
 - expand the keyword only for some file ( for the source file only )
 - add a hgrc option to activate/deactivate the keyword expansion
 - add some user defined keyword expansion
 - better support for multilinear expansion (for example log )
 - support for per _file_ revision/date
 - support for more keyword ( Author, Path, FileName.... )

Comments are welcome

Goffredo


---------------------------------------------------------

# HG changeset patch
# User kreijack at inwind.REMOVEME.it
# Node ID b6ca0465c6f7beb0255d98974647ce743c449caf
# Parent  3a1a46dcd3978a790f4c56486124880dbefeb1d4
Initial support for keyword expansion

diff -r 3a1a46dcd397 -r b6ca0465c6f7 mercurial/commands.py
--- a/mercurial/commands.py     Sat Aug 27 08:55:10 2005
+++ b/mercurial/commands.py     Tue Aug 30 18:49:22 2005
@@ -237,7 +237,7 @@
         if not node1:
             node1 = repo.dirstate.parents()[0]
         def read(f):
-            return repo.wfile(f).read()
+            return repo.ke.collapse_key(repo.wfile(f).read())

     if ui.quiet:
         r = None
diff -r 3a1a46dcd397 -r b6ca0465c6f7 mercurial/hg.py
--- a/mercurial/hg.py   Sat Aug 27 08:55:10 2005
+++ b/mercurial/hg.py   Tue Aug 30 18:49:22 2005
@@ -6,7 +6,7 @@
 # of the GNU General Public License, incorporated herein by reference.

 import sys, struct, os
-import util
+import util, re
 from revlog import *
 from demandload import *
 demandload(globals(), "re lock urllib urllib2 transaction time socket")
@@ -620,6 +620,57 @@

 class RepoError(Exception): pass

+class KeywordExpansion:
+
+        keys = {"CheckOutDate:": lambda self: time.asctime(time.localtime()),
+            "RevShort:": lambda self: str(self.node)[:8],
+            "Rev:": lambda self: str(self.node),
+            "Date:" : lambda self: self.date
+        }
+
+        def __init__(self, repo = None, node = None):
+            self.set(repo, node)
+            self.xkeys = []
+            for i in self.keys:
+                self.xkeys.append([ i, self.keys[i],
+                    re.compile("\$"+i+"[^$]*\$") ])
+
+        def set( self, repo = None, node = None ):
+            self.repo = repo
+            self.node = node
+            self.date = "<missing>"
+
+            if node != None and repo != None:
+                log = self.repo.changelog
+                changenode = self.repo.lookup(node)
+                changes = log.read(changenode)
+                t, tz = changes[2].split(' ')
+                try:
+                    tz = int(tz)
+                except ValueError:
+                    tz = 0
+                date = time.asctime(time.localtime(float(t))) + \
+                    " %+05d" % (int(tz)/-36)
+                self.date = date
+
+        def expand_key( self, l ):
+            for (name, func, regex) in self.xkeys:
+                l = regex.sub("$%s %s $"%(name, str(func(self))),l)
+            return l
+
+        def collapse_key( self, l ):
+            for (name, func, regex) in self.xkeys:
+                l = regex.sub("$%s $"%(name),l)
+            return l
+
+        def collapse_key_list( self, data ):
+            return [ self.collapse_key( l ) for l in data ]
+
+        def expand_key_list( self, data ):
+            return [ self.expand_key( l ) for l in data ]
+
+
+
 class localrepository:
     def __init__(self, ui, path=None, create=0):
         self.remote = 0
@@ -641,6 +692,7 @@

         self.root = os.path.abspath(path)
         self.ui = ui
+        self.ke = KeywordExpansion( )

         if create:
             os.mkdir(self.path)
@@ -847,7 +899,7 @@
         linkrev = self.changelog.count()
         for f in files:
             try:
-                t = self.wread(f)
+                t = self.ke.collapse_key(self.wread(f))
                 tm = util.is_exec(self.wjoin(f), mfm.get(f, False))
                 r = self.file(f)
                 mfm[f] = tm
@@ -940,7 +992,7 @@
             self.ui.note(f + "\n")
             try:
                 mf1[f] = util.is_exec(self.wjoin(f), mf1.get(f, False))
-                t = self.wread(f)
+                t = self.ke.collapse_key(self.wread(f))
             except IOError:
                 self.ui.warn("trouble committing %s!\n" % f)
                 raise
@@ -1031,7 +1083,7 @@
         mf2, u = None, []

         def fcmp(fn, mf):
-            t1 = self.wread(fn)
+            t1 = self.ke.collapse_key(self.wread(fn))
             t2 = self.file(fn).read(mf.get(fn, nullid))
             return cmp(t1, t2)

@@ -1635,6 +1687,8 @@
         ma = self.manifest.read(man)
         mfa = self.manifest.readflags(man)

+        self.ke.set( repo = self, node = hex(node))
+
         (c, a, d, u) = self.changes()

         # is this a jump, or a merge?  i.e. is there a linear path
@@ -1681,7 +1735,7 @@

                 # is the wfile new since m1, and match m2?
                 if f not in m1:
-                    t1 = self.wread(f)
+                    t1 = self.collapse_key(self.wread(f))
                     t2 = self.file(f).read(m2[f])
                     if cmp(t1, t2) == 0:
                         n = m2[f]
@@ -1801,10 +1855,10 @@
             self.ui.note("getting %s\n" % f)
             t = self.file(f).read(get[f])
             try:
-                self.wwrite(f, t)
+                self.wwrite(f, self.ke.expand_key(t))
             except IOError:
                 os.makedirs(os.path.dirname(self.wjoin(f)))
-                self.wwrite(f, t)
+                self.wwrite(f, self.ke.expand_key(t))
             util.set_exec(self.wjoin(f), mf2[f])
             if moddirstate:
                 if branch_merge:
@@ -1857,13 +1911,14 @@
             pre = "%s~%s." % (os.path.basename(fn), prefix)
             (fd, name) = tempfile.mkstemp("", pre)
             f = os.fdopen(fd, "wb")
-            self.wwrite(fn, fl.read(node), f)
+            self.wwrite(fn, self.ke.expand_key(fl.read(node)), f)
             f.close()
             return name

         fl = self.file(fn)
         base = fl.ancestor(my, other)
         a = self.wjoin(fn)
+        self.ke.set(repo = self, node = hex(my))
         b = temp("base", base)
         c = temp("other", other)



-- 
gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijack @ inwind.it>
Key fingerprint = CE3C 7E01 6782 30A3 5B87  87C0 BB86 505C 6B2A CFF9
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://www.selenic.com/pipermail/mercurial/attachments/20050830/2a32707d/attachment.pgp


More information about the Mercurial mailing list