# HG changeset patch # User Mads Kiilerich # Date 1254587480 -7200 # Node ID f04d179124410d491a8def230e408c3b6c98cbfc # Parent 75d290db2df6060c160153eb788dcb7249e932f3 cmdutil: templating keywords latesttag and latesttagdistance This can be used for referring to revisions in a reasonable meaningful, stable and monotonically increasing way, suitable for releases or builds directly from a repository. The latest tag is found by searching through untagged ancestors and finding the latest tagged ancestor based on tag date. The distance is found from the length of the longest path to the tagged revision. For example: hg log -l1 --template '{latesttag}+{latesttagdistance}\n' can return 1.3.1+197 This is mostly work by Gilles Moris diff -r 75d290db2df6 -r f04d17912441 mercurial/cmdutil.py --- a/mercurial/cmdutil.py Sat Oct 03 23:38:10 2009 +0200 +++ b/mercurial/cmdutil.py Sat Oct 03 18:31:20 2009 +0200 @@ -745,6 +745,9 @@ 'parent': '{rev}:{node|formatnode} ', 'manifest': '{rev}:{node|formatnode}', 'filecopy': '{name} ({source})'}) + # Cache mapping from rev to a tuple with tag date, tag + # distance and tag name + self._latesttagcache = {-1: (0, 0, 'null')} def use_template(self, t): '''set template string to use''' @@ -762,6 +765,30 @@ return [] return parents + def _latesttaginfo(self, rev): + '''return date, distance and name for the latest tag of rev''' + todo = [rev] + while todo: + rev = todo.pop() + if rev in self._latesttagcache: + continue + ctx = self.repo[rev] + tags = [t for t in ctx.tags() if self.repo.tagtype(t) == 'global'] + if tags: + self._latesttagcache[rev] = ctx.date()[0], 0, ':'.join(sorted(tags)) + continue + try: + # The tuples are laid out so the right one can be found by comparison. + pdate, pdist, ptag = max( + self._latesttagcache[p.rev()] for p in ctx.parents()) + except KeyError: + # Cache miss - recurse + todo.append(rev) + todo.extend(p.rev() for p in ctx.parents()) + continue + self._latesttagcache[rev] = pdate, pdist + 1, ptag + return self._latesttagcache[rev] + def _show(self, ctx, copies, props): '''show a single changeset or file revision''' @@ -879,6 +906,11 @@ removes += i[2] return '%s: +%s/-%s' % (files, adds, removes) + def showlatesttag(**args): + return self._latesttaginfo(ctx.rev())[2] + def showlatesttagdistance(**args): + return self._latesttaginfo(ctx.rev())[1] + defprops = { 'author': ctx.user(), 'branches': showbranches, @@ -896,6 +928,8 @@ 'tags': showtags, 'extras': showextras, 'diffstat': showdiffstat, + 'latesttag': showlatesttag, + 'latesttagdistance': showlatesttagdistance, } props = props.copy() props.update(defprops) diff -r 75d290db2df6 -r f04d17912441 mercurial/help.py --- a/mercurial/help.py Sat Oct 03 23:38:10 2009 +0200 +++ b/mercurial/help.py Sat Oct 03 18:31:20 2009 +0200 @@ -393,6 +393,9 @@ number. :tags: List of strings. Any tags associated with the changeset. + :latesttag: String. Most recent global tag in the ancestors of this + changeset. + :latesttagdistance: Integer. Longest path to the latest tag. The "date" keyword does not produce human-readable output. If you want to use a date in your output, you can use a filter to process diff -r 75d290db2df6 -r f04d17912441 tests/test-command-template --- a/tests/test-command-template Sat Oct 03 23:38:10 2009 +0200 +++ b/tests/test-command-template Sat Oct 03 18:31:20 2009 +0200 @@ -127,4 +127,49 @@ echo 'x = "f' >> t hg log +cd .. + +echo '# latesttag' +hg init latesttag +cd latesttag + +echo a > file +hg ci -Am a -d '0 0' + +echo b >> file +hg ci -m b -d '1 0' + +echo c >> head1 +hg ci -Am h1c -d '2 0' + +hg update -q 1 +echo d >> head2 +hg ci -Am h2d -d '3 0' + +echo e >> head2 +hg ci -m h2e -d '4 0' + +hg merge -q +hg ci -m merge -d '5 0' + +echo '# No tag set' +hg log --template '{rev}: {latesttag}+{latesttagdistance}\n' + +echo '# one common tag: longuest path wins' +hg tag -r 1 -m t1 -d '6 0' t1 +hg log --template '{rev}: {latesttag}+{latesttagdistance}\n' + +echo '# one ancestor tag: more recent wins' +hg tag -r 2 -m t2 -d '7 0' t2 +hg log --template '{rev}: {latesttag}+{latesttagdistance}\n' + +echo '# two branch tags: more recent wins' +hg tag -r 3 -m t3 -d '8 0' t3 +hg log --template '{rev}: {latesttag}+{latesttagdistance}\n' + +echo '# merged tag overrides' +hg tag -r 5 -m t5 -d '9 0' t5 +hg tag -r 3 -m at3 -d '10 0' at3 +hg log --template '{rev}: {latesttag}+{latesttagdistance}\n' + echo '# done' diff -r 75d290db2df6 -r f04d17912441 tests/test-command-template.out --- a/tests/test-command-template.out Sat Oct 03 23:38:10 2009 +0200 +++ b/tests/test-command-template.out Sat Oct 03 18:31:20 2009 +0200 @@ -672,4 +672,55 @@ 1e4e1b8f71e05681d422154f5421e385fec3454f # error on syntax abort: t:3: unmatched quotes +# latesttag +adding file +adding head1 +adding head2 +created new head +# No tag set +5: null+5 +4: null+4 +3: null+3 +2: null+3 +1: null+2 +0: null+1 +# one common tag: longuest path wins +6: t1+4 +5: t1+3 +4: t1+2 +3: t1+1 +2: t1+1 +1: t1+0 +0: null+1 +# one ancestor tag: more recent wins +7: t2+3 +6: t2+2 +5: t2+1 +4: t1+2 +3: t1+1 +2: t2+0 +1: t1+0 +0: null+1 +# two branch tags: more recent wins +8: t3+5 +7: t3+4 +6: t3+3 +5: t3+2 +4: t3+1 +3: t3+0 +2: t2+0 +1: t1+0 +0: null+1 +# merged tag overrides +10: t5+5 +9: t5+4 +8: t5+3 +7: t5+2 +6: t5+1 +5: t5+0 +4: at3:t3+1 +3: at3:t3+0 +2: t2+0 +1: t1+0 +0: null+1 # done