##// END OF EJS Templates
bookmarks: Avoid long lines
Joel Rosdahl -
r7252:104a8324 default
parent child Browse files
Show More
@@ -1,220 +1,224
1 1 # Mercurial extension to provide the 'hg bookmark' command
2 2 #
3 3 # Copyright 2008 David Soria Parra <dsp@php.net>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7
7 8 '''mercurial bookmarks
8 9
9 Mercurial bookmarks are local moveable pointers to changesets. Every bookmark
10 points to a changeset identified by its hash. If you commit a changeset
11 that is based on a changeset that has a bookmark on it, the bookmark is forwarded
12 to the new changeset.
10 Mercurial bookmarks are local moveable pointers to changesets. Every
11 bookmark points to a changeset identified by its hash. If you commit a
12 changeset that is based on a changeset that has a bookmark on it, the
13 bookmark is forwarded to the new changeset.
13 14
14 It is possible to use bookmark names in every revision lookup (e.g. hg merge, hg update)
15 It is possible to use bookmark names in every revision lookup (e.g. hg
16 merge, hg update).
15 17 '''
18
16 19 from mercurial.commands import templateopts, hex, short
17 20 from mercurial.i18n import _
18 21 from mercurial import cmdutil, util, commands, changelog
19 22 from mercurial.node import nullrev
20 23 from mercurial.repo import RepoError
21 24 import mercurial, mercurial.localrepo, mercurial.repair, os
22 25
23
24 26 def parse(repo):
25 27 '''Parse .hg/bookmarks file and return a dictionary
26 28
27 Bookmarks are stored as {HASH}\s{NAME}\n (localtags format)
28 values in the .hg/bookmarks file.
29 They are read by the parse() method and returned as a dictionary with
30 name => hash values.
29 Bookmarks are stored as {HASH}\s{NAME}\n (localtags format) values
30 in the .hg/bookmarks file. They are read by the parse() method and
31 returned as a dictionary with name => hash values.
31 32
32 33 The parsed dictionary is cached until a write() operation is done.
33 34 '''
34 35 try:
35 36 if repo._bookmarks:
36 37 return repo._bookmarks
37 38 repo._bookmarks = {}
38 39 for line in repo.opener('bookmarks'):
39 40 sha, refspec = line.strip().split(' ', 1)
40 41 repo._bookmarks[refspec] = repo.lookup(sha)
41 42 except:
42 43 pass
43 44 return repo._bookmarks
44 45
45 46 def write(repo, refs):
46 47 '''Write bookmarks
47 48
48 49 Write the given bookmark => hash dictionary to the .hg/bookmarks file
49 50 in a format equal to those of localtags.
50 51
51 52 We also store a backup of the previous state in undo.bookmarks that
52 53 can be copied back on rollback.
53 54 '''
54 55 util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks'))
55 56 file = repo.opener('bookmarks', 'w+')
56 57 for refspec, node in refs.items():
57 58 file.write("%s %s\n" % (hex(node), refspec))
58 59 file.close()
59 60
60 61 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, move=None):
61 62 '''mercurial bookmarks
62 63
63 Bookmarks are pointers to certain commits that move when commiting.
64 Bookmarks are local. They can be renamed, copied and deleted.
65 It is possible to use bookmark names in 'hg merge' and 'hg update' to
66 update to a given bookmark.
64 Bookmarks are pointers to certain commits that move when
65 commiting. Bookmarks are local. They can be renamed, copied and
66 deleted. It is possible to use bookmark names in 'hg merge' and 'hg
67 update' to update to a given bookmark.
67 68
68 69 You can use 'hg bookmark [NAME]' to set a bookmark on the current tip
69 70 with the given name. If you specify a second [NAME] the bookmark is
70 71 set to the bookmark that has that name. You can also pass revision
71 72 identifiers to set bookmarks too.
72 73 '''
73 74 hexfn = ui.debugflag and hex or short
74 75 marks = parse(repo)
75 76 cur = repo.changectx('.').node()
76 77
77 78 if move:
78 79 if move not in marks:
79 80 raise util.Abort(_("a bookmark of this name does not exist"))
80 81 if mark in marks and not force:
81 82 raise util.Abort(_("a bookmark of the same name already exists"))
82 83 marks[mark] = marks[move]
83 84 del marks[move]
84 85 write(repo, marks)
85 86 return
86 87
87 88 if delete:
88 89 if mark == None:
89 90 raise util.Abort(_("bookmark name required"))
90 91 if mark not in marks:
91 92 raise util.Abort(_("a bookmark of this name does not exist"))
92 93 del marks[mark]
93 94 write(repo, marks)
94 95 return
95 96
96 97 if mark != None:
97 98 if mark.strip().count("\n") > 0:
98 99 raise Exception("bookmark cannot contain newlines")
99 100 if mark in marks and not force:
100 101 raise util.Abort(_("a bookmark of the same name already exists"))
101 102 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
102 103 and not force):
103 raise util.Abort(_("a bookmark cannot have the name of an existing branch"))
104 raise util.Abort(
105 _("a bookmark cannot have the name of an existing branch"))
104 106 if rev:
105 107 marks[mark] = repo.lookup(rev)
106 108 else:
107 109 marks[mark] = repo.changectx('.').node()
108 110 write(repo, marks)
109 111 return
110 112
111 113 if mark == None:
112 114 if len(marks) == 0:
113 115 ui.status("no bookmarks set\n")
114 116 else:
115 117 for bmark, n in marks.iteritems():
116 118 prefix = (n == cur) and '*' or ' '
117 ui.write(" %s %-25s %d:%s\n" % (prefix, bmark, repo.changelog.rev(n), hexfn(n)))
119 ui.write(" %s %-25s %d:%s\n" % (
120 prefix, bmark, repo.changelog.rev(n), hexfn(n)))
118 121 return
119 122
120 123 def _revstostrip(changelog, node):
121 124 srev = changelog.rev(node)
122 125 tostrip = [srev]
123 126 saveheads = []
124 127 for r in xrange(srev, changelog.rev(changelog.tip()) + 1):
125 128 parents = changelog.parentrevs(r)
126 129 if parents[0] in tostrip or parents[1] in tostrip:
127 130 tostrip.append(r)
128 131 if parents[1] != nullrev:
129 132 for p in parents:
130 133 if p not in tostrip and p > striprev:
131 134 saveheads.append(p)
132 135 return [r for r in tostrip if r not in saveheads]
133 136
134 137 def strip(ui, repo, node, backup="all"):
135 138 """Strip bookmarks if revisions are stripped using
136 139 the mercurial.strip method. This usually happens during
137 140 qpush and qpop"""
138 141 revisions = _revstostrip(repo.changelog, node)
139 142 marks = parse(repo)
140 143 update = []
141 144 for mark, n in marks.items():
142 145 if repo.changelog.rev(n) in revisions:
143 146 update.append(mark)
144 147 result = oldstrip(ui, repo, node, backup)
145 148 if len(update) > 0:
146 149 for m in update:
147 150 marks[m] = repo.changectx('.').node()
148 151 write(repo, marks)
149 152
150 153 oldstrip = mercurial.repair.strip
151 154 mercurial.repair.strip = strip
152 155
153 156 def reposetup(ui, repo):
154 157 if not isinstance(repo, mercurial.localrepo.localrepository):
155 158 return
156 159
157 160 # init a bookmark cache as otherwise we would get a infinite reading
158 161 # in lookup()
159 162 repo._bookmarks = None
160 163
161 164 class bookmark_repo(repo.__class__):
162 165 def rollback(self):
163 166 if os.path.exists(self.join('undo.bookmarks')):
164 167 util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
165 168 return super(bookmark_repo, self).rollback()
166 169
167 170 def lookup(self, key):
168 171 if self._bookmarks is None:
169 172 self._bookmarks = parse(self)
170 173 if key in self._bookmarks:
171 174 key = self._bookmarks[key]
172 175 return super(bookmark_repo, self).lookup(key)
173 176
174 177 def commit(self, *k, **kw):
175 178 """Add a revision to the repository and
176 179 move the bookmark"""
177 180 node = super(bookmark_repo, self).commit(*k, **kw)
178 181 parents = repo.changelog.parents(node)
179 182 marks = parse(repo)
180 183 update = False
181 184 for mark, n in marks.items():
182 185 if n in parents:
183 186 marks[mark] = node
184 187 update = True
185 188 if update:
186 189 write(repo, marks)
187 190 return node
188 191
189 192 def addchangegroup(self, source, srctype, url, emptyok=False):
190 193 try:
191 194 onode = repo.changectx('.').node()
192 195 except RepoError, inst:
193 196 pass
194 197
195 result = super(bookmark_repo, self).addchangegroup(source, srctype, url, emptyok)
198 result = super(bookmark_repo, self).addchangegroup(
199 source, srctype, url, emptyok)
196 200 if result > 1:
197 201 # We have more heads than before
198 202 return result
199 203 node = repo.changelog.tip()
200 204 marks = parse(repo)
201 205 update = False
202 206 for mark, n in marks.items():
203 207 if n == onode:
204 208 marks[mark] = node
205 209 update = True
206 210 if update:
207 211 write(repo, marks)
208 212 return result
209 213
210 214 repo.__class__ = bookmark_repo
211 215
212 216 cmdtable = {
213 217 "bookmarks":
214 218 (bookmark,
215 219 [('f', 'force', False, _('force')),
216 220 ('r', 'rev', '', _('revision')),
217 221 ('d', 'delete', False, _('delete a given bookmark')),
218 222 ('m', 'move', '', _('move a given bookmark'))],
219 223 _('hg bookmarks [-d] [-m NAME] [-r NAME] [NAME]')),
220 224 }
General Comments 0
You need to be logged in to leave comments. Login now