##// END OF EJS Templates
bookmarks: remove unused updatecurrentbookmark function (API)...
Ryan McElroy -
r24962:eecd4836 default
parent child Browse files
Show More
@@ -1,558 +1,549 b''
1 # Mercurial bookmark support code
1 # Mercurial bookmark support code
2 #
2 #
3 # Copyright 2008 David Soria Parra <dsp@php.net>
3 # Copyright 2008 David Soria Parra <dsp@php.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import os
8 import os
9 from mercurial.i18n import _
9 from mercurial.i18n import _
10 from mercurial.node import hex, bin
10 from mercurial.node import hex, bin
11 from mercurial import encoding, error, util, obsolete, lock as lockmod
11 from mercurial import encoding, util, obsolete, lock as lockmod
12 import errno
12 import errno
13
13
14 class bmstore(dict):
14 class bmstore(dict):
15 """Storage for bookmarks.
15 """Storage for bookmarks.
16
16
17 This object should do all bookmark reads and writes, so that it's
17 This object should do all bookmark reads and writes, so that it's
18 fairly simple to replace the storage underlying bookmarks without
18 fairly simple to replace the storage underlying bookmarks without
19 having to clone the logic surrounding bookmarks.
19 having to clone the logic surrounding bookmarks.
20
20
21 This particular bmstore implementation stores bookmarks as
21 This particular bmstore implementation stores bookmarks as
22 {hash}\s{name}\n (the same format as localtags) in
22 {hash}\s{name}\n (the same format as localtags) in
23 .hg/bookmarks. The mapping is stored as {name: nodeid}.
23 .hg/bookmarks. The mapping is stored as {name: nodeid}.
24
24
25 This class does NOT handle the "current" bookmark state at this
25 This class does NOT handle the "current" bookmark state at this
26 time.
26 time.
27 """
27 """
28
28
29 def __init__(self, repo):
29 def __init__(self, repo):
30 dict.__init__(self)
30 dict.__init__(self)
31 self._repo = repo
31 self._repo = repo
32 try:
32 try:
33 bkfile = self.getbkfile(repo)
33 bkfile = self.getbkfile(repo)
34 for line in bkfile:
34 for line in bkfile:
35 line = line.strip()
35 line = line.strip()
36 if not line:
36 if not line:
37 continue
37 continue
38 if ' ' not in line:
38 if ' ' not in line:
39 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
39 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
40 % line)
40 % line)
41 continue
41 continue
42 sha, refspec = line.split(' ', 1)
42 sha, refspec = line.split(' ', 1)
43 refspec = encoding.tolocal(refspec)
43 refspec = encoding.tolocal(refspec)
44 try:
44 try:
45 self[refspec] = repo.changelog.lookup(sha)
45 self[refspec] = repo.changelog.lookup(sha)
46 except LookupError:
46 except LookupError:
47 pass
47 pass
48 except IOError, inst:
48 except IOError, inst:
49 if inst.errno != errno.ENOENT:
49 if inst.errno != errno.ENOENT:
50 raise
50 raise
51
51
52 def getbkfile(self, repo):
52 def getbkfile(self, repo):
53 bkfile = None
53 bkfile = None
54 if 'HG_PENDING' in os.environ:
54 if 'HG_PENDING' in os.environ:
55 try:
55 try:
56 bkfile = repo.vfs('bookmarks.pending')
56 bkfile = repo.vfs('bookmarks.pending')
57 except IOError, inst:
57 except IOError, inst:
58 if inst.errno != errno.ENOENT:
58 if inst.errno != errno.ENOENT:
59 raise
59 raise
60 if bkfile is None:
60 if bkfile is None:
61 bkfile = repo.vfs('bookmarks')
61 bkfile = repo.vfs('bookmarks')
62 return bkfile
62 return bkfile
63
63
64 def recordchange(self, tr):
64 def recordchange(self, tr):
65 """record that bookmarks have been changed in a transaction
65 """record that bookmarks have been changed in a transaction
66
66
67 The transaction is then responsible for updating the file content."""
67 The transaction is then responsible for updating the file content."""
68 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
68 tr.addfilegenerator('bookmarks', ('bookmarks',), self._write,
69 location='plain')
69 location='plain')
70 tr.hookargs['bookmark_moved'] = '1'
70 tr.hookargs['bookmark_moved'] = '1'
71
71
72 def write(self):
72 def write(self):
73 '''Write bookmarks
73 '''Write bookmarks
74
74
75 Write the given bookmark => hash dictionary to the .hg/bookmarks file
75 Write the given bookmark => hash dictionary to the .hg/bookmarks file
76 in a format equal to those of localtags.
76 in a format equal to those of localtags.
77
77
78 We also store a backup of the previous state in undo.bookmarks that
78 We also store a backup of the previous state in undo.bookmarks that
79 can be copied back on rollback.
79 can be copied back on rollback.
80 '''
80 '''
81 repo = self._repo
81 repo = self._repo
82 self._writerepo(repo)
82 self._writerepo(repo)
83
83
84 def _writerepo(self, repo):
84 def _writerepo(self, repo):
85 """Factored out for extensibility"""
85 """Factored out for extensibility"""
86 if repo._activebookmark not in self:
86 if repo._activebookmark not in self:
87 deactivate(repo)
87 deactivate(repo)
88
88
89 wlock = repo.wlock()
89 wlock = repo.wlock()
90 try:
90 try:
91
91
92 file = repo.vfs('bookmarks', 'w', atomictemp=True)
92 file = repo.vfs('bookmarks', 'w', atomictemp=True)
93 self._write(file)
93 self._write(file)
94 file.close()
94 file.close()
95
95
96 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
96 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
97 try:
97 try:
98 repo.svfs.utime('00changelog.i', None)
98 repo.svfs.utime('00changelog.i', None)
99 except OSError:
99 except OSError:
100 pass
100 pass
101
101
102 finally:
102 finally:
103 wlock.release()
103 wlock.release()
104
104
105 def _write(self, fp):
105 def _write(self, fp):
106 for name, node in self.iteritems():
106 for name, node in self.iteritems():
107 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
107 fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
108
108
109 def readactive(repo):
109 def readactive(repo):
110 """
110 """
111 Get the active bookmark. We can have an active bookmark that updates
111 Get the active bookmark. We can have an active bookmark that updates
112 itself as we commit. This function returns the name of that bookmark.
112 itself as we commit. This function returns the name of that bookmark.
113 It is stored in .hg/bookmarks.current
113 It is stored in .hg/bookmarks.current
114 """
114 """
115 mark = None
115 mark = None
116 try:
116 try:
117 file = repo.vfs('bookmarks.current')
117 file = repo.vfs('bookmarks.current')
118 except IOError, inst:
118 except IOError, inst:
119 if inst.errno != errno.ENOENT:
119 if inst.errno != errno.ENOENT:
120 raise
120 raise
121 return None
121 return None
122 try:
122 try:
123 # No readline() in osutil.posixfile, reading everything is cheap
123 # No readline() in osutil.posixfile, reading everything is cheap
124 mark = encoding.tolocal((file.readlines() or [''])[0])
124 mark = encoding.tolocal((file.readlines() or [''])[0])
125 if mark == '' or mark not in repo._bookmarks:
125 if mark == '' or mark not in repo._bookmarks:
126 mark = None
126 mark = None
127 finally:
127 finally:
128 file.close()
128 file.close()
129 return mark
129 return mark
130
130
131 def activate(repo, mark):
131 def activate(repo, mark):
132 """
132 """
133 Set the given bookmark to be 'active', meaning that this bookmark will
133 Set the given bookmark to be 'active', meaning that this bookmark will
134 follow new commits that are made.
134 follow new commits that are made.
135 The name is recorded in .hg/bookmarks.current
135 The name is recorded in .hg/bookmarks.current
136 """
136 """
137 if mark not in repo._bookmarks:
137 if mark not in repo._bookmarks:
138 raise AssertionError('bookmark %s does not exist!' % mark)
138 raise AssertionError('bookmark %s does not exist!' % mark)
139
139
140 current = repo._activebookmark
140 current = repo._activebookmark
141 if current == mark:
141 if current == mark:
142 return
142 return
143
143
144 wlock = repo.wlock()
144 wlock = repo.wlock()
145 try:
145 try:
146 file = repo.vfs('bookmarks.current', 'w', atomictemp=True)
146 file = repo.vfs('bookmarks.current', 'w', atomictemp=True)
147 file.write(encoding.fromlocal(mark))
147 file.write(encoding.fromlocal(mark))
148 file.close()
148 file.close()
149 finally:
149 finally:
150 wlock.release()
150 wlock.release()
151 repo._activebookmark = mark
151 repo._activebookmark = mark
152
152
153 def deactivate(repo):
153 def deactivate(repo):
154 """
154 """
155 Unset the active bookmark in this reposiotry.
155 Unset the active bookmark in this reposiotry.
156 """
156 """
157 wlock = repo.wlock()
157 wlock = repo.wlock()
158 try:
158 try:
159 try:
159 try:
160 repo.vfs.unlink('bookmarks.current')
160 repo.vfs.unlink('bookmarks.current')
161 repo._activebookmark = None
161 repo._activebookmark = None
162 except OSError, inst:
162 except OSError, inst:
163 if inst.errno != errno.ENOENT:
163 if inst.errno != errno.ENOENT:
164 raise
164 raise
165 finally:
165 finally:
166 wlock.release()
166 wlock.release()
167
167
168 def iscurrent(repo, mark=None, parents=None):
168 def iscurrent(repo, mark=None, parents=None):
169 '''Tell whether the current bookmark is also active
169 '''Tell whether the current bookmark is also active
170
170
171 I.e., the bookmark listed in .hg/bookmarks.current also points to a
171 I.e., the bookmark listed in .hg/bookmarks.current also points to a
172 parent of the working directory.
172 parent of the working directory.
173 '''
173 '''
174 if not mark:
174 if not mark:
175 mark = repo._activebookmark
175 mark = repo._activebookmark
176 if not parents:
176 if not parents:
177 parents = [p.node() for p in repo[None].parents()]
177 parents = [p.node() for p in repo[None].parents()]
178 marks = repo._bookmarks
178 marks = repo._bookmarks
179 return (mark in marks and marks[mark] in parents)
179 return (mark in marks and marks[mark] in parents)
180
180
181 def updatecurrentbookmark(repo, oldnode, curbranch):
182 try:
183 return update(repo, oldnode, repo.branchtip(curbranch))
184 except error.RepoLookupError:
185 if curbranch == "default": # no default branch!
186 return update(repo, oldnode, repo.lookup("tip"))
187 else:
188 raise util.Abort(_("branch %s not found") % curbranch)
189
190 def deletedivergent(repo, deletefrom, bm):
181 def deletedivergent(repo, deletefrom, bm):
191 '''Delete divergent versions of bm on nodes in deletefrom.
182 '''Delete divergent versions of bm on nodes in deletefrom.
192
183
193 Return True if at least one bookmark was deleted, False otherwise.'''
184 Return True if at least one bookmark was deleted, False otherwise.'''
194 deleted = False
185 deleted = False
195 marks = repo._bookmarks
186 marks = repo._bookmarks
196 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
187 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
197 for mark in divergent:
188 for mark in divergent:
198 if mark == '@' or '@' not in mark:
189 if mark == '@' or '@' not in mark:
199 # can't be divergent by definition
190 # can't be divergent by definition
200 continue
191 continue
201 if mark and marks[mark] in deletefrom:
192 if mark and marks[mark] in deletefrom:
202 if mark != bm:
193 if mark != bm:
203 del marks[mark]
194 del marks[mark]
204 deleted = True
195 deleted = True
205 return deleted
196 return deleted
206
197
207 def calculateupdate(ui, repo, checkout):
198 def calculateupdate(ui, repo, checkout):
208 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
199 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
209 check out and where to move the active bookmark from, if needed.'''
200 check out and where to move the active bookmark from, if needed.'''
210 movemarkfrom = None
201 movemarkfrom = None
211 if checkout is None:
202 if checkout is None:
212 curmark = repo._activebookmark
203 curmark = repo._activebookmark
213 if iscurrent(repo):
204 if iscurrent(repo):
214 movemarkfrom = repo['.'].node()
205 movemarkfrom = repo['.'].node()
215 elif curmark:
206 elif curmark:
216 ui.status(_("updating to active bookmark %s\n") % curmark)
207 ui.status(_("updating to active bookmark %s\n") % curmark)
217 checkout = curmark
208 checkout = curmark
218 return (checkout, movemarkfrom)
209 return (checkout, movemarkfrom)
219
210
220 def update(repo, parents, node):
211 def update(repo, parents, node):
221 deletefrom = parents
212 deletefrom = parents
222 marks = repo._bookmarks
213 marks = repo._bookmarks
223 update = False
214 update = False
224 cur = repo._activebookmark
215 cur = repo._activebookmark
225 if not cur:
216 if not cur:
226 return False
217 return False
227
218
228 if marks[cur] in parents:
219 if marks[cur] in parents:
229 new = repo[node]
220 new = repo[node]
230 divs = [repo[b] for b in marks
221 divs = [repo[b] for b in marks
231 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
222 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
232 anc = repo.changelog.ancestors([new.rev()])
223 anc = repo.changelog.ancestors([new.rev()])
233 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
224 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
234 if validdest(repo, repo[marks[cur]], new):
225 if validdest(repo, repo[marks[cur]], new):
235 marks[cur] = new.node()
226 marks[cur] = new.node()
236 update = True
227 update = True
237
228
238 if deletedivergent(repo, deletefrom, cur):
229 if deletedivergent(repo, deletefrom, cur):
239 update = True
230 update = True
240
231
241 if update:
232 if update:
242 marks.write()
233 marks.write()
243 return update
234 return update
244
235
245 def listbookmarks(repo):
236 def listbookmarks(repo):
246 # We may try to list bookmarks on a repo type that does not
237 # We may try to list bookmarks on a repo type that does not
247 # support it (e.g., statichttprepository).
238 # support it (e.g., statichttprepository).
248 marks = getattr(repo, '_bookmarks', {})
239 marks = getattr(repo, '_bookmarks', {})
249
240
250 d = {}
241 d = {}
251 hasnode = repo.changelog.hasnode
242 hasnode = repo.changelog.hasnode
252 for k, v in marks.iteritems():
243 for k, v in marks.iteritems():
253 # don't expose local divergent bookmarks
244 # don't expose local divergent bookmarks
254 if hasnode(v) and ('@' not in k or k.endswith('@')):
245 if hasnode(v) and ('@' not in k or k.endswith('@')):
255 d[k] = hex(v)
246 d[k] = hex(v)
256 return d
247 return d
257
248
258 def pushbookmark(repo, key, old, new):
249 def pushbookmark(repo, key, old, new):
259 w = l = tr = None
250 w = l = tr = None
260 try:
251 try:
261 w = repo.wlock()
252 w = repo.wlock()
262 l = repo.lock()
253 l = repo.lock()
263 tr = repo.transaction('bookmarks')
254 tr = repo.transaction('bookmarks')
264 marks = repo._bookmarks
255 marks = repo._bookmarks
265 existing = hex(marks.get(key, ''))
256 existing = hex(marks.get(key, ''))
266 if existing != old and existing != new:
257 if existing != old and existing != new:
267 return False
258 return False
268 if new == '':
259 if new == '':
269 del marks[key]
260 del marks[key]
270 else:
261 else:
271 if new not in repo:
262 if new not in repo:
272 return False
263 return False
273 marks[key] = repo[new].node()
264 marks[key] = repo[new].node()
274 marks.recordchange(tr)
265 marks.recordchange(tr)
275 tr.close()
266 tr.close()
276 return True
267 return True
277 finally:
268 finally:
278 lockmod.release(tr, l, w)
269 lockmod.release(tr, l, w)
279
270
280 def compare(repo, srcmarks, dstmarks,
271 def compare(repo, srcmarks, dstmarks,
281 srchex=None, dsthex=None, targets=None):
272 srchex=None, dsthex=None, targets=None):
282 '''Compare bookmarks between srcmarks and dstmarks
273 '''Compare bookmarks between srcmarks and dstmarks
283
274
284 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
275 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
285 differ, invalid)", each are list of bookmarks below:
276 differ, invalid)", each are list of bookmarks below:
286
277
287 :addsrc: added on src side (removed on dst side, perhaps)
278 :addsrc: added on src side (removed on dst side, perhaps)
288 :adddst: added on dst side (removed on src side, perhaps)
279 :adddst: added on dst side (removed on src side, perhaps)
289 :advsrc: advanced on src side
280 :advsrc: advanced on src side
290 :advdst: advanced on dst side
281 :advdst: advanced on dst side
291 :diverge: diverge
282 :diverge: diverge
292 :differ: changed, but changeset referred on src is unknown on dst
283 :differ: changed, but changeset referred on src is unknown on dst
293 :invalid: unknown on both side
284 :invalid: unknown on both side
294 :same: same on both side
285 :same: same on both side
295
286
296 Each elements of lists in result tuple is tuple "(bookmark name,
287 Each elements of lists in result tuple is tuple "(bookmark name,
297 changeset ID on source side, changeset ID on destination
288 changeset ID on source side, changeset ID on destination
298 side)". Each changeset IDs are 40 hexadecimal digit string or
289 side)". Each changeset IDs are 40 hexadecimal digit string or
299 None.
290 None.
300
291
301 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
292 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
302 "invalid" list may be unknown for repo.
293 "invalid" list may be unknown for repo.
303
294
304 This function expects that "srcmarks" and "dstmarks" return
295 This function expects that "srcmarks" and "dstmarks" return
305 changeset ID in 40 hexadecimal digit string for specified
296 changeset ID in 40 hexadecimal digit string for specified
306 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
297 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
307 binary value), "srchex" or "dsthex" should be specified to convert
298 binary value), "srchex" or "dsthex" should be specified to convert
308 into such form.
299 into such form.
309
300
310 If "targets" is specified, only bookmarks listed in it are
301 If "targets" is specified, only bookmarks listed in it are
311 examined.
302 examined.
312 '''
303 '''
313 if not srchex:
304 if not srchex:
314 srchex = lambda x: x
305 srchex = lambda x: x
315 if not dsthex:
306 if not dsthex:
316 dsthex = lambda x: x
307 dsthex = lambda x: x
317
308
318 if targets:
309 if targets:
319 bset = set(targets)
310 bset = set(targets)
320 else:
311 else:
321 srcmarkset = set(srcmarks)
312 srcmarkset = set(srcmarks)
322 dstmarkset = set(dstmarks)
313 dstmarkset = set(dstmarks)
323 bset = srcmarkset | dstmarkset
314 bset = srcmarkset | dstmarkset
324
315
325 results = ([], [], [], [], [], [], [], [])
316 results = ([], [], [], [], [], [], [], [])
326 addsrc = results[0].append
317 addsrc = results[0].append
327 adddst = results[1].append
318 adddst = results[1].append
328 advsrc = results[2].append
319 advsrc = results[2].append
329 advdst = results[3].append
320 advdst = results[3].append
330 diverge = results[4].append
321 diverge = results[4].append
331 differ = results[5].append
322 differ = results[5].append
332 invalid = results[6].append
323 invalid = results[6].append
333 same = results[7].append
324 same = results[7].append
334
325
335 for b in sorted(bset):
326 for b in sorted(bset):
336 if b not in srcmarks:
327 if b not in srcmarks:
337 if b in dstmarks:
328 if b in dstmarks:
338 adddst((b, None, dsthex(dstmarks[b])))
329 adddst((b, None, dsthex(dstmarks[b])))
339 else:
330 else:
340 invalid((b, None, None))
331 invalid((b, None, None))
341 elif b not in dstmarks:
332 elif b not in dstmarks:
342 addsrc((b, srchex(srcmarks[b]), None))
333 addsrc((b, srchex(srcmarks[b]), None))
343 else:
334 else:
344 scid = srchex(srcmarks[b])
335 scid = srchex(srcmarks[b])
345 dcid = dsthex(dstmarks[b])
336 dcid = dsthex(dstmarks[b])
346 if scid == dcid:
337 if scid == dcid:
347 same((b, scid, dcid))
338 same((b, scid, dcid))
348 elif scid in repo and dcid in repo:
339 elif scid in repo and dcid in repo:
349 sctx = repo[scid]
340 sctx = repo[scid]
350 dctx = repo[dcid]
341 dctx = repo[dcid]
351 if sctx.rev() < dctx.rev():
342 if sctx.rev() < dctx.rev():
352 if validdest(repo, sctx, dctx):
343 if validdest(repo, sctx, dctx):
353 advdst((b, scid, dcid))
344 advdst((b, scid, dcid))
354 else:
345 else:
355 diverge((b, scid, dcid))
346 diverge((b, scid, dcid))
356 else:
347 else:
357 if validdest(repo, dctx, sctx):
348 if validdest(repo, dctx, sctx):
358 advsrc((b, scid, dcid))
349 advsrc((b, scid, dcid))
359 else:
350 else:
360 diverge((b, scid, dcid))
351 diverge((b, scid, dcid))
361 else:
352 else:
362 # it is too expensive to examine in detail, in this case
353 # it is too expensive to examine in detail, in this case
363 differ((b, scid, dcid))
354 differ((b, scid, dcid))
364
355
365 return results
356 return results
366
357
367 def _diverge(ui, b, path, localmarks, remotenode):
358 def _diverge(ui, b, path, localmarks, remotenode):
368 '''Return appropriate diverged bookmark for specified ``path``
359 '''Return appropriate diverged bookmark for specified ``path``
369
360
370 This returns None, if it is failed to assign any divergent
361 This returns None, if it is failed to assign any divergent
371 bookmark name.
362 bookmark name.
372
363
373 This reuses already existing one with "@number" suffix, if it
364 This reuses already existing one with "@number" suffix, if it
374 refers ``remotenode``.
365 refers ``remotenode``.
375 '''
366 '''
376 if b == '@':
367 if b == '@':
377 b = ''
368 b = ''
378 # try to use an @pathalias suffix
369 # try to use an @pathalias suffix
379 # if an @pathalias already exists, we overwrite (update) it
370 # if an @pathalias already exists, we overwrite (update) it
380 if path.startswith("file:"):
371 if path.startswith("file:"):
381 path = util.url(path).path
372 path = util.url(path).path
382 for p, u in ui.configitems("paths"):
373 for p, u in ui.configitems("paths"):
383 if u.startswith("file:"):
374 if u.startswith("file:"):
384 u = util.url(u).path
375 u = util.url(u).path
385 if path == u:
376 if path == u:
386 return '%s@%s' % (b, p)
377 return '%s@%s' % (b, p)
387
378
388 # assign a unique "@number" suffix newly
379 # assign a unique "@number" suffix newly
389 for x in range(1, 100):
380 for x in range(1, 100):
390 n = '%s@%d' % (b, x)
381 n = '%s@%d' % (b, x)
391 if n not in localmarks or localmarks[n] == remotenode:
382 if n not in localmarks or localmarks[n] == remotenode:
392 return n
383 return n
393
384
394 return None
385 return None
395
386
396 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
387 def updatefromremote(ui, repo, remotemarks, path, trfunc, explicit=()):
397 ui.debug("checking for updated bookmarks\n")
388 ui.debug("checking for updated bookmarks\n")
398 localmarks = repo._bookmarks
389 localmarks = repo._bookmarks
399 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
390 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same
400 ) = compare(repo, remotemarks, localmarks, dsthex=hex)
391 ) = compare(repo, remotemarks, localmarks, dsthex=hex)
401
392
402 status = ui.status
393 status = ui.status
403 warn = ui.warn
394 warn = ui.warn
404 if ui.configbool('ui', 'quietbookmarkmove', False):
395 if ui.configbool('ui', 'quietbookmarkmove', False):
405 status = warn = ui.debug
396 status = warn = ui.debug
406
397
407 explicit = set(explicit)
398 explicit = set(explicit)
408 changed = []
399 changed = []
409 for b, scid, dcid in addsrc:
400 for b, scid, dcid in addsrc:
410 if scid in repo: # add remote bookmarks for changes we already have
401 if scid in repo: # add remote bookmarks for changes we already have
411 changed.append((b, bin(scid), status,
402 changed.append((b, bin(scid), status,
412 _("adding remote bookmark %s\n") % (b)))
403 _("adding remote bookmark %s\n") % (b)))
413 for b, scid, dcid in advsrc:
404 for b, scid, dcid in advsrc:
414 changed.append((b, bin(scid), status,
405 changed.append((b, bin(scid), status,
415 _("updating bookmark %s\n") % (b)))
406 _("updating bookmark %s\n") % (b)))
416 # remove normal movement from explicit set
407 # remove normal movement from explicit set
417 explicit.difference_update(d[0] for d in changed)
408 explicit.difference_update(d[0] for d in changed)
418
409
419 for b, scid, dcid in diverge:
410 for b, scid, dcid in diverge:
420 if b in explicit:
411 if b in explicit:
421 explicit.discard(b)
412 explicit.discard(b)
422 changed.append((b, bin(scid), status,
413 changed.append((b, bin(scid), status,
423 _("importing bookmark %s\n") % (b)))
414 _("importing bookmark %s\n") % (b)))
424 else:
415 else:
425 snode = bin(scid)
416 snode = bin(scid)
426 db = _diverge(ui, b, path, localmarks, snode)
417 db = _diverge(ui, b, path, localmarks, snode)
427 if db:
418 if db:
428 changed.append((db, snode, warn,
419 changed.append((db, snode, warn,
429 _("divergent bookmark %s stored as %s\n") %
420 _("divergent bookmark %s stored as %s\n") %
430 (b, db)))
421 (b, db)))
431 else:
422 else:
432 warn(_("warning: failed to assign numbered name "
423 warn(_("warning: failed to assign numbered name "
433 "to divergent bookmark %s\n") % (b))
424 "to divergent bookmark %s\n") % (b))
434 for b, scid, dcid in adddst + advdst:
425 for b, scid, dcid in adddst + advdst:
435 if b in explicit:
426 if b in explicit:
436 explicit.discard(b)
427 explicit.discard(b)
437 changed.append((b, bin(scid), status,
428 changed.append((b, bin(scid), status,
438 _("importing bookmark %s\n") % (b)))
429 _("importing bookmark %s\n") % (b)))
439
430
440 if changed:
431 if changed:
441 tr = trfunc()
432 tr = trfunc()
442 for b, node, writer, msg in sorted(changed):
433 for b, node, writer, msg in sorted(changed):
443 localmarks[b] = node
434 localmarks[b] = node
444 writer(msg)
435 writer(msg)
445 localmarks.recordchange(tr)
436 localmarks.recordchange(tr)
446
437
447 def incoming(ui, repo, other):
438 def incoming(ui, repo, other):
448 '''Show bookmarks incoming from other to repo
439 '''Show bookmarks incoming from other to repo
449 '''
440 '''
450 ui.status(_("searching for changed bookmarks\n"))
441 ui.status(_("searching for changed bookmarks\n"))
451
442
452 r = compare(repo, other.listkeys('bookmarks'), repo._bookmarks,
443 r = compare(repo, other.listkeys('bookmarks'), repo._bookmarks,
453 dsthex=hex)
444 dsthex=hex)
454 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
445 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
455
446
456 incomings = []
447 incomings = []
457 if ui.debugflag:
448 if ui.debugflag:
458 getid = lambda id: id
449 getid = lambda id: id
459 else:
450 else:
460 getid = lambda id: id[:12]
451 getid = lambda id: id[:12]
461 if ui.verbose:
452 if ui.verbose:
462 def add(b, id, st):
453 def add(b, id, st):
463 incomings.append(" %-25s %s %s\n" % (b, getid(id), st))
454 incomings.append(" %-25s %s %s\n" % (b, getid(id), st))
464 else:
455 else:
465 def add(b, id, st):
456 def add(b, id, st):
466 incomings.append(" %-25s %s\n" % (b, getid(id)))
457 incomings.append(" %-25s %s\n" % (b, getid(id)))
467 for b, scid, dcid in addsrc:
458 for b, scid, dcid in addsrc:
468 # i18n: "added" refers to a bookmark
459 # i18n: "added" refers to a bookmark
469 add(b, scid, _('added'))
460 add(b, scid, _('added'))
470 for b, scid, dcid in advsrc:
461 for b, scid, dcid in advsrc:
471 # i18n: "advanced" refers to a bookmark
462 # i18n: "advanced" refers to a bookmark
472 add(b, scid, _('advanced'))
463 add(b, scid, _('advanced'))
473 for b, scid, dcid in diverge:
464 for b, scid, dcid in diverge:
474 # i18n: "diverged" refers to a bookmark
465 # i18n: "diverged" refers to a bookmark
475 add(b, scid, _('diverged'))
466 add(b, scid, _('diverged'))
476 for b, scid, dcid in differ:
467 for b, scid, dcid in differ:
477 # i18n: "changed" refers to a bookmark
468 # i18n: "changed" refers to a bookmark
478 add(b, scid, _('changed'))
469 add(b, scid, _('changed'))
479
470
480 if not incomings:
471 if not incomings:
481 ui.status(_("no changed bookmarks found\n"))
472 ui.status(_("no changed bookmarks found\n"))
482 return 1
473 return 1
483
474
484 for s in sorted(incomings):
475 for s in sorted(incomings):
485 ui.write(s)
476 ui.write(s)
486
477
487 return 0
478 return 0
488
479
489 def outgoing(ui, repo, other):
480 def outgoing(ui, repo, other):
490 '''Show bookmarks outgoing from repo to other
481 '''Show bookmarks outgoing from repo to other
491 '''
482 '''
492 ui.status(_("searching for changed bookmarks\n"))
483 ui.status(_("searching for changed bookmarks\n"))
493
484
494 r = compare(repo, repo._bookmarks, other.listkeys('bookmarks'),
485 r = compare(repo, repo._bookmarks, other.listkeys('bookmarks'),
495 srchex=hex)
486 srchex=hex)
496 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
487 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
497
488
498 outgoings = []
489 outgoings = []
499 if ui.debugflag:
490 if ui.debugflag:
500 getid = lambda id: id
491 getid = lambda id: id
501 else:
492 else:
502 getid = lambda id: id[:12]
493 getid = lambda id: id[:12]
503 if ui.verbose:
494 if ui.verbose:
504 def add(b, id, st):
495 def add(b, id, st):
505 outgoings.append(" %-25s %s %s\n" % (b, getid(id), st))
496 outgoings.append(" %-25s %s %s\n" % (b, getid(id), st))
506 else:
497 else:
507 def add(b, id, st):
498 def add(b, id, st):
508 outgoings.append(" %-25s %s\n" % (b, getid(id)))
499 outgoings.append(" %-25s %s\n" % (b, getid(id)))
509 for b, scid, dcid in addsrc:
500 for b, scid, dcid in addsrc:
510 # i18n: "added refers to a bookmark
501 # i18n: "added refers to a bookmark
511 add(b, scid, _('added'))
502 add(b, scid, _('added'))
512 for b, scid, dcid in adddst:
503 for b, scid, dcid in adddst:
513 # i18n: "deleted" refers to a bookmark
504 # i18n: "deleted" refers to a bookmark
514 add(b, ' ' * 40, _('deleted'))
505 add(b, ' ' * 40, _('deleted'))
515 for b, scid, dcid in advsrc:
506 for b, scid, dcid in advsrc:
516 # i18n: "advanced" refers to a bookmark
507 # i18n: "advanced" refers to a bookmark
517 add(b, scid, _('advanced'))
508 add(b, scid, _('advanced'))
518 for b, scid, dcid in diverge:
509 for b, scid, dcid in diverge:
519 # i18n: "diverged" refers to a bookmark
510 # i18n: "diverged" refers to a bookmark
520 add(b, scid, _('diverged'))
511 add(b, scid, _('diverged'))
521 for b, scid, dcid in differ:
512 for b, scid, dcid in differ:
522 # i18n: "changed" refers to a bookmark
513 # i18n: "changed" refers to a bookmark
523 add(b, scid, _('changed'))
514 add(b, scid, _('changed'))
524
515
525 if not outgoings:
516 if not outgoings:
526 ui.status(_("no changed bookmarks found\n"))
517 ui.status(_("no changed bookmarks found\n"))
527 return 1
518 return 1
528
519
529 for s in sorted(outgoings):
520 for s in sorted(outgoings):
530 ui.write(s)
521 ui.write(s)
531
522
532 return 0
523 return 0
533
524
534 def summary(repo, other):
525 def summary(repo, other):
535 '''Compare bookmarks between repo and other for "hg summary" output
526 '''Compare bookmarks between repo and other for "hg summary" output
536
527
537 This returns "(# of incoming, # of outgoing)" tuple.
528 This returns "(# of incoming, # of outgoing)" tuple.
538 '''
529 '''
539 r = compare(repo, other.listkeys('bookmarks'), repo._bookmarks,
530 r = compare(repo, other.listkeys('bookmarks'), repo._bookmarks,
540 dsthex=hex)
531 dsthex=hex)
541 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
532 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = r
542 return (len(addsrc), len(adddst))
533 return (len(addsrc), len(adddst))
543
534
544 def validdest(repo, old, new):
535 def validdest(repo, old, new):
545 """Is the new bookmark destination a valid update from the old one"""
536 """Is the new bookmark destination a valid update from the old one"""
546 repo = repo.unfiltered()
537 repo = repo.unfiltered()
547 if old == new:
538 if old == new:
548 # Old == new -> nothing to update.
539 # Old == new -> nothing to update.
549 return False
540 return False
550 elif not old:
541 elif not old:
551 # old is nullrev, anything is valid.
542 # old is nullrev, anything is valid.
552 # (new != nullrev has been excluded by the previous check)
543 # (new != nullrev has been excluded by the previous check)
553 return True
544 return True
554 elif repo.obsstore:
545 elif repo.obsstore:
555 return new.node() in obsolete.foreground(repo, [old.node()])
546 return new.node() in obsolete.foreground(repo, [old.node()])
556 else:
547 else:
557 # still an independent clause as it is lazier (and therefore faster)
548 # still an independent clause as it is lazier (and therefore faster)
558 return old.descendant(new)
549 return old.descendant(new)
General Comments 0
You need to be logged in to leave comments. Login now