[PATCH 4 of 4 NEW-CONCEPT] track-tags: write all tag changes to a file

Pierre-Yves David pierre-yves.david at ens-lyon.org
Thu Mar 30 11:03:42 EDT 2017


# HG changeset patch
# User Pierre-Yves David <pierre-yves.david at ens-lyon.org>
# Date 1490688902 -7200
#      Tue Mar 28 10:15:02 2017 +0200
# Node ID 46005886092380991a30c2a02486c2876ecac341
# Parent  2dcaa99d6160561166269f192a89b25f84fd4667
# EXP-Topic tags
# Available At https://www.mercurial-scm.org/repo/users/marmoute/mercurial/
#              hg pull https://www.mercurial-scm.org/repo/users/marmoute/mercurial/ -r 460058860923
track-tags: write all tag changes to a file

The tag changes information we compute are not written to disk. This gives
hooks full acces to that data.

The format picked for that file use a 2 characters prefix for the action:

    -R: tag removed
    +A: tag added
    -M: tag moved (old value)
    +M: tag moved (new value)

This format allows hooks to easily select the line that matters to them without
having to post process the file too much. Here is
a couple of example:

 * to select all newly tagged changeset, match "^+",
 * to detect tag move, match "^.M",
 * to detect tag deletion, match "-R".

Once again we rely on the fact the tag tests run through all possible
situations to test this change.

diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1015,6 +1015,25 @@ class localrepository(object):
         # and do not use caches as much as it could.  The current focus is on
         # the behavior of the feature so we disable it by default. The flag
         # will be removed when we are happy with the performance impact.
+        #
+        # Once this feature is no longer experimental move the following
+        # documentation to the appropriate help section:
+        #
+        # The ``HG_TAG_MOVED`` variable will be set if the transaction touched
+        # tags (new or changed or deleted tags). In addition the details of
+        # these changes are made available in a file at:
+        #     ``REPOROOT/.hg/changes/tags.changes``.
+        # Make sure you check for HG_TAG_MOVED before reading that file as it
+        # might exist from a previous transaction even if no tag were touched
+        # in this one. Change are recorded in a line base format::
+        #
+        #     <action> <hex-node> <tag-name>\n
+        #
+        # Actions are defined as follow:
+        #   "-R": tag is removed,
+        #   "+A": tag is added,
+        #   "-M": tag is moved (old value),
+        #   "+M": tag is moved (new value),
         tracktags = lambda x: None
         # experimental config: experimental.hook-track-tags
         shouldtracktags = self.ui.configbool('experimental', 'hook-track-tags',
@@ -1031,6 +1050,12 @@ class localrepository(object):
                 changes = tagsmod.difftags(repo.ui, repo, oldfnodes, newfnodes)
                 if changes:
                     tr2.hookargs['tag_moved'] = '1'
+                    with repo.vfs('changes/tags.changes', 'w',
+                                  atomictemp=True) as changesfile:
+                        # note: we do not register the file to the transaction
+                        # because we needs it to still exist on the transaction
+                        # is close (for txnclose hooks)
+                        tagsmod.writediff(changesfile, changes)
         def validate(tr2):
             """will run pre-closing hooks"""
             # XXX the transaction API is a bit lacking here so we take a hacky
diff --git a/mercurial/tags.py b/mercurial/tags.py
--- a/mercurial/tags.py
+++ b/mercurial/tags.py
@@ -129,6 +129,44 @@ def difftags(ui, repo, oldfnodes, newfno
     entries.sort()
     return entries
 
+def writediff(fp, difflist):
+    """write tags diff information to a file.
+
+    Data are stored with a line based format:
+
+        <action> <hex-node> <tag-name>\n
+
+    Action are defined as follow:
+       -R tag is removed,
+       +A tag is added,
+       -M tag is moved (old value),
+       +M tag is moved (new value),
+
+    Example:
+
+         +A 875517b4806a848f942811a315a5bce30804ae85 t5
+
+    See documentation of difftags output for details about the input.
+    """
+    add = '+A %s %s\n'
+    remove = '-R %s %s\n'
+    updateold = '-M %s %s\n'
+    updatenew = '+M %s %s\n'
+    for tag, old, new in difflist:
+        # translate to hex
+        if old is not None:
+            old = hex(old)
+        if new is not None:
+            new = hex(new)
+        # write to file
+        if old is None:
+            fp.write(add % (new, tag))
+        elif new is None:
+            fp.write(remove % (old, tag))
+        else:
+            fp.write(updateold % (old, tag))
+            fp.write(updatenew % (new, tag))
+
 def findglobaltags(ui, repo):
     '''Find global tags in a repo: return a tagsmap
 
diff --git a/tests/test-tag.t b/tests/test-tag.t
--- a/tests/test-tag.t
+++ b/tests/test-tag.t
@@ -11,6 +11,7 @@
   > # file...
   > if [ -n "\$HG_TAG_MOVED" ]; then
   >     echo 'hook: tag changes detected'
+  >     sed 's/^/hook: /' .hg/changes/tags.changes
   > fi
   > EOF
   $ chmod +x taghook.sh
@@ -37,6 +38,7 @@ specified)
 
   $ HGEDITOR=cat hg tag "bleah"
   hook: tag changes detected
+  hook: +A acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
   $ hg history
   changeset:   1:d4f0d2909abc
   tag:         tip
@@ -86,13 +88,21 @@ specified)
 
   $ hg tag -r 0 "bleah0"
   hook: tag changes detected
+  hook: +A acb14030fe0a21b60322c440ad2d20cf7685a376 bleah0
   $ hg tag -l -r 1 "bleah1"
   $ hg tag gack gawk gorp
   hook: tag changes detected
+  hook: +A 336fccc858a4eb69609a291105009e484a6b6b8d gack
+  hook: +A 336fccc858a4eb69609a291105009e484a6b6b8d gawk
+  hook: +A 336fccc858a4eb69609a291105009e484a6b6b8d gorp
   $ hg tag -f gack
   hook: tag changes detected
+  hook: -M 336fccc858a4eb69609a291105009e484a6b6b8d gack
+  hook: +M 799667b6f2d9b957f73fa644a918c2df22bab58f gack
   $ hg tag --remove gack gorp
   hook: tag changes detected
+  hook: -R 799667b6f2d9b957f73fa644a918c2df22bab58f gack
+  hook: -R 336fccc858a4eb69609a291105009e484a6b6b8d gorp
 
   $ hg tag "bleah "
   abort: tag 'bleah' already exists (use -f to force)
@@ -105,8 +115,10 @@ specified)
   [255]
   $ hg tag -r 0 "  bleahbleah  "
   hook: tag changes detected
+  hook: +A acb14030fe0a21b60322c440ad2d20cf7685a376 bleahbleah
   $ hg tag -r 0 " bleah bleah "
   hook: tag changes detected
+  hook: +A acb14030fe0a21b60322c440ad2d20cf7685a376 bleah bleah
 
   $ cat .hgtags
   acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
@@ -136,6 +148,7 @@ tagging on a non-head revision
   [255]
   $ hg tag -f "foobar"
   hook: tag changes detected
+  hook: +A acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
   $ cat .hgtags
   acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
   $ cat .hg/localtags
@@ -194,18 +207,23 @@ cloning local tags
   
   $ hg clone -q -rbleah1 test test1
   hook: tag changes detected
+  hook: +A acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
   $ hg -R test1 parents --style=compact
   1[tip]   d4f0d2909abc   1970-01-01 00:00 +0000   test
     Added tag bleah for changeset acb14030fe0a
   
   $ hg clone -q -r5 test#bleah1 test2
   hook: tag changes detected
+  hook: +A acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
+  hook: +A acb14030fe0a21b60322c440ad2d20cf7685a376 bleah0
+  hook: +A 336fccc858a4eb69609a291105009e484a6b6b8d gawk
   $ hg -R test2 parents --style=compact
   5[tip]   b4bb47aaff09   1970-01-01 00:00 +0000   test
     Removed tag gack, gorp
   
   $ hg clone -q -U test#bleah1 test3
   hook: tag changes detected
+  hook: +A acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
   $ hg -R test3 parents --style=compact
 
   $ cd test
@@ -234,6 +252,7 @@ doesn't end with EOL
   acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
   $ hg tag newline
   hook: tag changes detected
+  hook: +A a0eea09de1eeec777b46f2085260a373b2fbc293 newline
   $ cat .hgtags; echo
   acb14030fe0a21b60322c440ad2d20cf7685a376 foobar
   a0eea09de1eeec777b46f2085260a373b2fbc293 newline
@@ -248,6 +267,7 @@ tag and branch using same name
   $ hg tag tag-and-branch-same-name
   warning: tag tag-and-branch-same-name conflicts with existing branch name
   hook: tag changes detected
+  hook: +A fc93d2ea1cd78e91216c6cfbbf26747c10ce11ae tag-and-branch-same-name
 
 test custom commit messages
 
@@ -333,6 +353,7 @@ then, test custom commit message itself
   HG: changed .hgtags
   ====
   hook: tag changes detected
+  hook: +A 75a534207be6b03576e0c7a4fa5708d045f1c876 custom-tag
   $ hg log -l1 --template "{desc}\n"
   custom tag message
   second line
@@ -342,6 +363,7 @@ local tag with .hgtags modified
 
   $ hg tag hgtags-modified
   hook: tag changes detected
+  hook: +A 0f26aaea6f74c3ed6c4aad8844403c9ba128d23a hgtags-modified
   $ hg rollback
   repository tip rolled back to revision 13 (undo commit)
   working directory now based on revision 13
@@ -362,10 +384,16 @@ tagging when at named-branch-head that's
   (branch merge, don't forget to commit)
   $ hg ci -m 'merge named branch'
   hook: tag changes detected
+  hook: -R acb14030fe0a21b60322c440ad2d20cf7685a376 bleah
+  hook: -R acb14030fe0a21b60322c440ad2d20cf7685a376 bleah bleah
+  hook: -R acb14030fe0a21b60322c440ad2d20cf7685a376 bleah0
+  hook: -R acb14030fe0a21b60322c440ad2d20cf7685a376 bleahbleah
+  hook: -R 336fccc858a4eb69609a291105009e484a6b6b8d gawk
   $ hg up 13
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   $ hg tag new-topo-head
   hook: tag changes detected
+  hook: +A 0f26aaea6f74c3ed6c4aad8844403c9ba128d23a new-topo-head
 
 tagging on null rev
 
@@ -433,6 +461,7 @@ commit hook on tag used to be run withou
   > EOF
   $ hg -R repo-tag --config hooks.commit="sh ../issue3344.sh" tag tag
   hook: tag changes detected
+  hook: +A be090ea6625635128e90f7d89df8beeb2bcc1653 tag
   pushing to $TESTTMP/repo-tag-target (glob)
   searching for changes
   adding changesets
@@ -440,6 +469,7 @@ commit hook on tag used to be run withou
   adding file changes
   added 2 changesets with 2 changes to 2 files
   hook: tag changes detected
+  hook: +A be090ea6625635128e90f7d89df8beeb2bcc1653 tag
 
 automatically merge resolvable tag conflicts (i.e. tags that differ in rank)
 create two clones with some different tags as well as some common tags
@@ -452,6 +482,7 @@ check that we can merge tags that differ
   adding f0
   $ hg tag tbase
   hook: tag changes detected
+  hook: +A 6cee5c8f3e5b4ae1a3996d2f6489c3e08eb5aea7 tbase
   $ hg up -qr '.^'
   $ hg log -r 'wdir()' -T "{latesttagdistance}\n"
   1
@@ -468,15 +499,22 @@ check that we can merge tags that differ
   adding f1
   $ hg tag t1 t2 t3
   hook: tag changes detected
+  hook: +A 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t1
+  hook: +A 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
+  hook: +A 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
   $ hg tag --remove t2
   hook: tag changes detected
+  hook: -R 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t2
   $ hg tag t5
   hook: tag changes detected
+  hook: +A 875517b4806a848f942811a315a5bce30804ae85 t5
   $ echo c2 > f2
   $ hg ci -A -m2
   adding f2
   $ hg tag -f t3
   hook: tag changes detected
+  hook: -M 4f3e9b90005b68b4d8a3f4355cedc302a8364f5c t3
+  hook: +M 79505d5360b07e3e79d1052e347e73c02b8afa5b t3
 
   $ cd ../repo-automatic-tag-merge
   $ echo c3 > f3
@@ -484,6 +522,9 @@ check that we can merge tags that differ
   adding f3
   $ hg tag -f t4 t5 t6
   hook: tag changes detected
+  hook: +A 9aa4e1292a27a248f8d07339bed9931d54907be7 t4
+  hook: +A 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
+  hook: +A 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
 
   $ hg up -q '.^'
   $ hg log -r 'wdir()' -T "{changessincelatesttag} changes since {latesttag}\n"
@@ -497,6 +538,7 @@ check that we can merge tags that differ
 
   $ hg tag --remove t5
   hook: tag changes detected
+  hook: -R 9aa4e1292a27a248f8d07339bed9931d54907be7 t5
   $ echo c4 > f4
   $ hg log -r '.' -T "{changessincelatesttag} changes since {latesttag}\n"
   2 changes since t4:t6
@@ -516,8 +558,11 @@ check that we can merge tags that differ
   4 changes since t4:t6
   $ hg tag t2
   hook: tag changes detected
+  hook: +A 929bca7b18d067cbf3844c3896319a940059d748 t2
   $ hg tag -f t6
   hook: tag changes detected
+  hook: -M 9aa4e1292a27a248f8d07339bed9931d54907be7 t6
+  hook: +M 09af2ce14077a94effef208b49a718f4836d4338 t6
 
   $ cd ../repo-automatic-tag-merge-clone
   $ hg pull
@@ -528,6 +573,10 @@ check that we can merge tags that differ
   adding file changes
   added 6 changesets with 6 changes to 3 files (+1 heads)
   hook: tag changes detected
+  hook: +A 929bca7b18d067cbf3844c3896319a940059d748 t2
+  hook: +A 9aa4e1292a27a248f8d07339bed9931d54907be7 t4
+  hook: -R 875517b4806a848f942811a315a5bce30804ae85 t5
+  hook: +A 09af2ce14077a94effef208b49a718f4836d4338 t6
   (run 'hg heads' to see heads, 'hg merge' to merge)
   $ hg merge --tool internal:tagmerge
   merging .hgtags
@@ -589,11 +638,16 @@ detect merge tag conflicts
   3 files updated, 0 files merged, 2 files removed, 0 files unresolved
   $ hg tag t7
   hook: tag changes detected
+  hook: +A b325cc5b642c5b465bdbe8c09627cb372de3d47d t7
   $ hg update -C -r 'first(sort(head()))'
   3 files updated, 0 files merged, 2 files removed, 0 files unresolved
   $ printf "%s %s\n" `hg log -r . --template "{node} t7"` >> .hgtags
   $ hg commit -m "manually add conflicting t7 tag"
   hook: tag changes detected
+  hook: -R 929bca7b18d067cbf3844c3896319a940059d748 t2
+  hook: +A 875517b4806a848f942811a315a5bce30804ae85 t5
+  hook: -M b325cc5b642c5b465bdbe8c09627cb372de3d47d t7
+  hook: +M ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
   $ hg merge --tool internal:tagmerge
   merging .hgtags
   automatic .hgtags merge failed
@@ -629,6 +683,8 @@ handle the loss of tags
   adding f5
   $ hg tag -f t7
   hook: tag changes detected
+  hook: -M ea918d56be86a4afc5a95312e8b6750e1428d9d2 t7
+  hook: +M fd3a9e394ce3afb354a496323bf68ac1755a30de t7
   $ hg update -r 'p1(t7)'
   1 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ printf '' > .hgtags


More information about the Mercurial-devel mailing list