tag: handle .hgtags and .hg/localtags with missing final newline (issue 601)
authorBryan O'Sullivan <bos@serpentine.com>
Mon, 16 Jul 2007 20:15:03 -0700
changeset 4892 d69b1fb111b9
parent 4891 2d545b98a7bc
child 4893 44b0031514c1
tag: handle .hgtags and .hg/localtags with missing final newline (issue 601) This also fixes an asymmetry bug in which we called the pretag hook if we were going to create a local tag, but didn't call the tag hook afterwards.
mercurial/localrepo.py
tests/test-hook.out
tests/test-tag
tests/test-tag.out
--- a/mercurial/localrepo.py	Mon Jul 16 18:01:20 2007 -0700
+++ b/mercurial/localrepo.py	Mon Jul 16 20:15:03 2007 -0700
@@ -119,22 +119,43 @@
 
         self.hook('pretag', throw=True, node=hex(node), tag=name, local=local)
 
+        def writetag(fp, name, munge, prevtags):
+            if prevtags and prevtags[-1] != '\n':
+                fp.write('\n')
+            fp.write('%s %s\n' % (hex(node), munge and munge(name) or name))
+            fp.close()
+            self.hook('tag', node=hex(node), tag=name, local=local)
+            
+        prevtags = ''
         if local:
+            try:
+                fp = self.opener('localtags', 'r+')
+            except IOError, err:
+                fp = self.opener('localtags', 'a')
+            else:
+                prevtags = fp.read()
+
             # local tags are stored in the current charset
-            self.opener('localtags', 'a').write('%s %s\n' % (hex(node), name))
-            self.hook('tag', node=hex(node), tag=name, local=local)
+            writetag(fp, name, None, prevtags)
             return
 
+        if use_dirstate:
+            try:
+                fp = self.wfile('.hgtags', 'rb+')
+            except IOError, err:
+                fp = self.wfile('.hgtags', 'ab')
+            else:
+                prevtags = fp.read()
+        else:
+            try:
+                prevtags = self.filectx('.hgtags', parent).data()
+            except revlog.LookupError:
+                pass
+            fp = self.wfile('.hgtags', 'wb')
+
         # committed tags are stored in UTF-8
-        line = '%s %s\n' % (hex(node), util.fromlocal(name))
-        if use_dirstate:
-            self.wfile('.hgtags', 'ab').write(line)
-        else:
-            try:
-                ntags = self.filectx('.hgtags', parent).data()
-            except revlog.LookupError:
-                ntags = ''
-            self.wfile('.hgtags', 'wb').write(ntags + line)
+        writetag(fp, name, util.fromlocal, prevtags)
+
         if use_dirstate and self.dirstate.state('.hgtags') == '?':
             self.add(['.hgtags'])
 
--- a/tests/test-hook.out	Mon Jul 16 18:01:20 2007 -0700
+++ b/tests/test-hook.out	Mon Jul 16 20:15:03 2007 -0700
@@ -40,6 +40,7 @@
 added 3 changesets with 2 changes to 2 files
 (run 'hg update' to get a working copy)
 pretag hook: HG_LOCAL=0 HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_TAG=a 
+tag hook: HG_LOCAL=0 HG_NODE=4c52fb2e402287dd5dc052090682536c8406c321 HG_TAG=a 
 precommit hook: HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 
 pretxncommit hook: HG_NODE=8ea2ef7ad3e8cac946c72f1e0c79d6aebc301198 HG_PARENT1=4c52fb2e402287dd5dc052090682536c8406c321 
 4:8ea2ef7ad3e8
--- a/tests/test-tag	Mon Jul 16 18:01:20 2007 -0700
+++ b/tests/test-tag	Mon Jul 16 20:15:03 2007 -0700
@@ -27,4 +27,17 @@
 hg tag -l 'xx
 newline'
 hg tag -l 'xx:xx'
-true
+
+echo % issue 601
+mv .hg/localtags .hg/ltags
+head -1 .hg/ltags | tr -d '\n' > .hg/localtags
+cat .hg/localtags
+hg tag -l localnewline
+cat .hg/localtags
+
+mv .hgtags hgtags
+head -1 hgtags | tr -d '\n' > .hgtags
+hg ci -d '1000000 0' -m'broken manual edit of .hgtags'
+cat .hgtags
+hg tag -d '1000000 0' newline
+cat .hgtags
--- a/tests/test-tag.out	Mon Jul 16 18:01:20 2007 -0700
+++ b/tests/test-tag.out	Mon Jul 16 20:15:03 2007 -0700
@@ -30,3 +30,8 @@
 3ecf002a1c572a2f3bb4e665417e60fca65bbd42 bleah1
 abort: '\n' cannot be used in a tag name
 abort: ':' cannot be used in a tag name
+% issue 601
+3ecf002a1c572a2f3bb4e665417e60fca65bbd42 bleah13ecf002a1c572a2f3bb4e665417e60fca65bbd42 bleah1
+f68b039e72eacbb2e68b0543e1f6e50990aa2bb5 localnewline
+0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar0acdaf8983679e0aac16e811534eb49d7ee1f2b4 foobar
+6ae703d793c8b1f097116869275ecd97b2977a2b newline