Commits

Benoit Boissinot committed 7e2e3aa Merge

merge with dsop

  • Participants
  • Parent commits 671b3e1, 3cbadcf

Comments (0)

Files changed (3)

File hgext/bookmarks.py

 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
+
 '''mercurial bookmarks
 
-Mercurial bookmarks are local moveable pointers to changesets. Every bookmark
-points to a changesets identified by it's hash. If you commit a changeset
-that is based on a changeset that has a bookmark on it, the bookmark is forwarded
-to the new changeset.
+Mercurial bookmarks are local moveable pointers to changesets. Every
+bookmark points to a changeset identified by its hash. If you commit a
+changeset that is based on a changeset that has a bookmark on it, the
+bookmark is forwarded to the new changeset.
 
-It is possible to use bookmark names in every revision lookup (e.g. hg merge, hg update)
+It is possible to use bookmark names in every revision lookup (e.g. hg
+merge, hg update).
 '''
+
 from mercurial.commands import templateopts, hex, short
 from mercurial.i18n import _
 from mercurial import cmdutil, util, commands, changelog
-from mercurial.node import nullrev
+from mercurial.node import nullid, nullrev
 from mercurial.repo import RepoError
 import mercurial, mercurial.localrepo, mercurial.repair, os
 
-
 def parse(repo):
     '''Parse .hg/bookmarks file and return a dictionary
-    
-    Bookmarks are stored as {HASH}\s{NAME}\n (localtags format) 
-    values in the .hg/bookmarks file.
-    They are read by the parse() method and returned as a dictionary with
-    name => hash values.
-    
+
+    Bookmarks are stored as {HASH}\s{NAME}\n (localtags format) values
+    in the .hg/bookmarks file. They are read by the parse() method and
+    returned as a dictionary with name => hash values.
+
     The parsed dictionary is cached until a write() operation is done.
     '''
     try:
 
 def write(repo, refs):
     '''Write bookmarks
-    
+
     Write the given bookmark => hash dictionary to the .hg/bookmarks file
     in a format equal to those of localtags.
 
     We also store a backup of the previous state in undo.bookmarks that
     can be copied back on rollback.
     '''
-    util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks'))
+    if os.path.exists(repo.join('bookmarks')):
+        util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks'))
     file = repo.opener('bookmarks', 'w+')
     for refspec, node in refs.items():
         file.write("%s %s\n" % (hex(node), refspec))
     file.close()
 
-def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, move=None):
+def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
     '''mercurial bookmarks
-    
-    Bookmarks are pointer to certain commits that move when commiting.
-    Bookmarks are local. They can be renamed, copied and deleted.
-    It is possible to use bookmark names in 'hg merge' and 'hg update' to 
-    update to a given bookmark.
-    
-    You can use 'hg bookmark [NAME]' to set a bookmark on the current tip
-    with the given name. If you specify a second [NAME] the bookmark is
-    set to the bookmark that has that name. You can also pass revision
-    identifiers to set bookmarks too.
+
+    Bookmarks are pointers to certain commits that move when
+    commiting. Bookmarks are local. They can be renamed, copied and
+    deleted. It is possible to use bookmark names in 'hg merge' and 'hg
+    update' to update to a given bookmark.
+
+    You can use 'hg bookmark NAME' to set a bookmark on the current
+    tip with the given name. If you specify a revision using -r REV
+    (where REV may be an existing bookmark), the bookmark is set to
+    that revision.
     '''
     hexfn = ui.debugflag and hex or short
     marks = parse(repo)
     cur   = repo.changectx('.').node()
 
-    if move:
-        if move not in marks:
-            raise util.Abort(_("a bookmark of this name doesnot exists"))
+    if rename:
+        if rename not in marks:
+            raise util.Abort(_("a bookmark of this name does not exist"))
         if mark in marks and not force:
             raise util.Abort(_("a bookmark of the same name already exists"))
-        marks[mark] = marks[move]
-        del marks[move]
+        if mark is None:
+            raise util.Abort(_("new bookmark name required"))
+        marks[mark] = marks[rename]
+        del marks[rename]
         write(repo, marks)
         return
-    
+
     if delete:
         if mark == None:
             raise util.Abort(_("bookmark name required"))
         if mark not in marks:
-            raise util.Abort(_("a bookmark of this name does not exists"))
+            raise util.Abort(_("a bookmark of this name does not exist"))
         del marks[mark]
         write(repo, marks)
         return
 
     if mark != None:
-        if mark.strip().count("\n") > 0:
-            raise Exception("bookmark cannot contain newlines")
+        if "\n" in mark:
+            raise util.Abort(_("bookmark name cannot contain newlines"))
+        mark = mark.strip()
         if mark in marks and not force:
             raise util.Abort(_("a bookmark of the same name already exists"))
-        if ((mark in repo.branchtags() or mark == repo.dirstate.branch()) 
+        if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
             and not force):
-            raise util.Abort(_("a bookmark cannot have the name of an existing branch"))
+            raise util.Abort(
+                _("a bookmark cannot have the name of an existing branch"))
         if rev:
             marks[mark] = repo.lookup(rev)
         else:
         return
 
     if mark == None:
+        if rev:
+            raise util.Abort(_("bookmark name required"))
         if len(marks) == 0:
             ui.status("no bookmarks set\n")
         else:
             for bmark, n in marks.iteritems():
                 prefix = (n == cur) and '*' or ' '
-                ui.write(" %s %-25s %d:%s\n" % (prefix, bmark, repo.changelog.rev(n), hexfn(n)))
+                ui.write(" %s %-25s %d:%s\n" % (
+                    prefix, bmark, repo.changelog.rev(n), hexfn(n)))
         return
 
 def _revstostrip(changelog, node):
         def rollback(self):
             if os.path.exists(self.join('undo.bookmarks')):
                 util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
-            return super(bookmark_repo, self).rollback() 
+            return super(bookmark_repo, self).rollback()
 
         def lookup(self, key):
             if self._bookmarks is None:
             """Add a revision to the repository and
             move the bookmark"""
             node  = super(bookmark_repo, self).commit(*k, **kw)
+            if node == None:
+                return None
             parents = repo.changelog.parents(node)
+            if parents[1] == nullid:
+                parents = (parents[0],)
             marks = parse(repo)
             update = False
             for mark, n in marks.items():
             except RepoError, inst:
                 pass
 
-            result = super(bookmark_repo, self).addchangegroup(source, srctype, url, emptyok)
+            result = super(bookmark_repo, self).addchangegroup(
+                source, srctype, url, emptyok)
             if result > 1:
                 # We have more heads than before
                 return result
          [('f', 'force', False, _('force')),
           ('r', 'rev', '', _('revision')),
           ('d', 'delete', False, _('delete a given bookmark')),
-          ('m', 'move', '', _('move a given bookmark'))],
+          ('m', 'rename', '', _('rename a given bookmark'))],
          _('hg bookmarks [-d] [-m NAME] [-r NAME] [NAME]')),
 }

File tests/test-bookmarks

+#!/bin/sh
+
+echo "[extensions]" >> $HGRCPATH
+echo "bookmarks=" >> $HGRCPATH
+
+hg init
+
+echo % no bookmarks
+hg bookmarks
+
+echo % bookmark rev -1
+hg bookmark X
+
+echo % list bookmarks
+hg bookmarks
+
+echo a > a
+hg add a
+hg commit -m 0
+
+echo % bookmark X moved to rev 0
+hg bookmarks
+
+echo % look up bookmark
+hg log -r X
+
+echo % second bookmark for rev 0
+hg bookmark X2
+
+echo % bookmark rev -1 again
+hg bookmark -r null Y
+
+echo % list bookmarks
+hg bookmarks
+
+echo b > b
+hg add b
+hg commit -m 1
+
+echo % bookmarks X and X2 moved to rev 1, Y at rev -1
+hg bookmarks
+
+echo % bookmark rev 0 again
+hg bookmark -r 0 Z
+
+echo c > c
+hg add c
+hg commit -m 2
+
+echo % bookmarks X and X2 moved to rev 2, Y at rev -1, Z at rev 0
+hg bookmarks
+
+echo % rename nonexistent bookmark
+hg bookmark -m A B
+
+echo % rename to existent bookmark
+hg bookmark -m X Y
+
+echo % force rename to existent bookmark
+hg bookmark -f -m X Y
+
+echo % list bookmarks
+hg bookmark
+
+echo % rename without new name
+hg bookmark -m Y
+
+echo % delete without name
+hg bookmark -d
+
+echo % delete nonexistent bookmark
+hg bookmark -d A
+
+echo % bookmark name with spaces should be stripped
+hg bookmark ' x  y '
+
+echo % list bookmarks
+hg bookmarks
+
+echo % look up stripped bookmark name
+hg log -r 'x  y'
+
+echo % reject bookmark name with newline
+hg bookmark '
+'
+
+echo % bookmark with existing name
+hg bookmark Z
+
+echo % force bookmark with existing name
+hg bookmark -f Z
+
+echo % list bookmarks
+hg bookmark
+
+echo % revision but no bookmark name
+hg bookmark -r .
+
+true

File tests/test-bookmarks.out

+% no bookmarks
+no bookmarks set
+% bookmark rev -1
+% list bookmarks
+ * X                         -1:000000000000
+% bookmark X moved to rev 0
+ * X                         0:f7b1eb17ad24
+% look up bookmark
+changeset:   0:f7b1eb17ad24
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     0
+
+% second bookmark for rev 0
+% bookmark rev -1 again
+% list bookmarks
+ * X2                        0:f7b1eb17ad24
+ * X                         0:f7b1eb17ad24
+   Y                         -1:000000000000
+% bookmarks X and X2 moved to rev 1, Y at rev -1
+ * X2                        1:925d80f479bb
+ * X                         1:925d80f479bb
+   Y                         -1:000000000000
+% bookmark rev 0 again
+% bookmarks X and X2 moved to rev 2, Y at rev -1, Z at rev 0
+ * X2                        2:0316ce92851d
+ * X                         2:0316ce92851d
+   Z                         0:f7b1eb17ad24
+   Y                         -1:000000000000
+% rename nonexistent bookmark
+abort: a bookmark of this name does not exist
+% rename to existent bookmark
+abort: a bookmark of the same name already exists
+% force rename to existent bookmark
+% list bookmarks
+ * X2                        2:0316ce92851d
+ * Y                         2:0316ce92851d
+   Z                         0:f7b1eb17ad24
+% rename without new name
+abort: new bookmark name required
+% delete without name
+abort: bookmark name required
+% delete nonexistent bookmark
+abort: a bookmark of this name does not exist
+% bookmark name with spaces should be stripped
+% list bookmarks
+ * X2                        2:0316ce92851d
+ * Y                         2:0316ce92851d
+   Z                         0:f7b1eb17ad24
+ * x  y                      2:0316ce92851d
+% look up stripped bookmark name
+changeset:   2:0316ce92851d
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     2
+
+% reject bookmark name with newline
+abort: bookmark name cannot contain newlines
+% bookmark with existing name
+abort: a bookmark of the same name already exists
+% force bookmark with existing name
+% list bookmarks
+ * X2                        2:0316ce92851d
+ * Y                         2:0316ce92851d
+ * Z                         2:0316ce92851d
+ * x  y                      2:0316ce92851d
+% revision but no bookmark name
+abort: bookmark name required