##// END OF EJS Templates
bookmarks: rewrite "updatefromremote()" by "compare()"...
FUJIWARA Katsunori -
r20025:e8a11791 default
parent child Browse files
Show More
@@ -1,402 +1,397 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 from mercurial.i18n import _
8 from mercurial.i18n import _
9 from mercurial.node import hex
9 from mercurial.node import hex, bin
10 from mercurial import encoding, error, util, obsolete
10 from mercurial import encoding, error, util, obsolete
11 import errno
11 import errno
12
12
13 class bmstore(dict):
13 class bmstore(dict):
14 """Storage for bookmarks.
14 """Storage for bookmarks.
15
15
16 This object should do all bookmark reads and writes, so that it's
16 This object should do all bookmark reads and writes, so that it's
17 fairly simple to replace the storage underlying bookmarks without
17 fairly simple to replace the storage underlying bookmarks without
18 having to clone the logic surrounding bookmarks.
18 having to clone the logic surrounding bookmarks.
19
19
20 This particular bmstore implementation stores bookmarks as
20 This particular bmstore implementation stores bookmarks as
21 {hash}\s{name}\n (the same format as localtags) in
21 {hash}\s{name}\n (the same format as localtags) in
22 .hg/bookmarks. The mapping is stored as {name: nodeid}.
22 .hg/bookmarks. The mapping is stored as {name: nodeid}.
23
23
24 This class does NOT handle the "current" bookmark state at this
24 This class does NOT handle the "current" bookmark state at this
25 time.
25 time.
26 """
26 """
27
27
28 def __init__(self, repo):
28 def __init__(self, repo):
29 dict.__init__(self)
29 dict.__init__(self)
30 self._repo = repo
30 self._repo = repo
31 try:
31 try:
32 for line in repo.vfs('bookmarks'):
32 for line in repo.vfs('bookmarks'):
33 line = line.strip()
33 line = line.strip()
34 if not line:
34 if not line:
35 continue
35 continue
36 if ' ' not in line:
36 if ' ' not in line:
37 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
37 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
38 % line)
38 % line)
39 continue
39 continue
40 sha, refspec = line.split(' ', 1)
40 sha, refspec = line.split(' ', 1)
41 refspec = encoding.tolocal(refspec)
41 refspec = encoding.tolocal(refspec)
42 try:
42 try:
43 self[refspec] = repo.changelog.lookup(sha)
43 self[refspec] = repo.changelog.lookup(sha)
44 except LookupError:
44 except LookupError:
45 pass
45 pass
46 except IOError, inst:
46 except IOError, inst:
47 if inst.errno != errno.ENOENT:
47 if inst.errno != errno.ENOENT:
48 raise
48 raise
49
49
50 def write(self):
50 def write(self):
51 '''Write bookmarks
51 '''Write bookmarks
52
52
53 Write the given bookmark => hash dictionary to the .hg/bookmarks file
53 Write the given bookmark => hash dictionary to the .hg/bookmarks file
54 in a format equal to those of localtags.
54 in a format equal to those of localtags.
55
55
56 We also store a backup of the previous state in undo.bookmarks that
56 We also store a backup of the previous state in undo.bookmarks that
57 can be copied back on rollback.
57 can be copied back on rollback.
58 '''
58 '''
59 repo = self._repo
59 repo = self._repo
60 if repo._bookmarkcurrent not in self:
60 if repo._bookmarkcurrent not in self:
61 setcurrent(repo, None)
61 setcurrent(repo, None)
62
62
63 wlock = repo.wlock()
63 wlock = repo.wlock()
64 try:
64 try:
65
65
66 file = repo.vfs('bookmarks', 'w', atomictemp=True)
66 file = repo.vfs('bookmarks', 'w', atomictemp=True)
67 for name, node in self.iteritems():
67 for name, node in self.iteritems():
68 file.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
68 file.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
69 file.close()
69 file.close()
70
70
71 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
71 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
72 try:
72 try:
73 repo.svfs.utime('00changelog.i', None)
73 repo.svfs.utime('00changelog.i', None)
74 except OSError:
74 except OSError:
75 pass
75 pass
76
76
77 finally:
77 finally:
78 wlock.release()
78 wlock.release()
79
79
80 def readcurrent(repo):
80 def readcurrent(repo):
81 '''Get the current bookmark
81 '''Get the current bookmark
82
82
83 If we use gittish branches we have a current bookmark that
83 If we use gittish branches we have a current bookmark that
84 we are on. This function returns the name of the bookmark. It
84 we are on. This function returns the name of the bookmark. It
85 is stored in .hg/bookmarks.current
85 is stored in .hg/bookmarks.current
86 '''
86 '''
87 mark = None
87 mark = None
88 try:
88 try:
89 file = repo.opener('bookmarks.current')
89 file = repo.opener('bookmarks.current')
90 except IOError, inst:
90 except IOError, inst:
91 if inst.errno != errno.ENOENT:
91 if inst.errno != errno.ENOENT:
92 raise
92 raise
93 return None
93 return None
94 try:
94 try:
95 # No readline() in osutil.posixfile, reading everything is cheap
95 # No readline() in osutil.posixfile, reading everything is cheap
96 mark = encoding.tolocal((file.readlines() or [''])[0])
96 mark = encoding.tolocal((file.readlines() or [''])[0])
97 if mark == '' or mark not in repo._bookmarks:
97 if mark == '' or mark not in repo._bookmarks:
98 mark = None
98 mark = None
99 finally:
99 finally:
100 file.close()
100 file.close()
101 return mark
101 return mark
102
102
103 def setcurrent(repo, mark):
103 def setcurrent(repo, mark):
104 '''Set the name of the bookmark that we are currently on
104 '''Set the name of the bookmark that we are currently on
105
105
106 Set the name of the bookmark that we are on (hg update <bookmark>).
106 Set the name of the bookmark that we are on (hg update <bookmark>).
107 The name is recorded in .hg/bookmarks.current
107 The name is recorded in .hg/bookmarks.current
108 '''
108 '''
109 current = repo._bookmarkcurrent
109 current = repo._bookmarkcurrent
110 if current == mark:
110 if current == mark:
111 return
111 return
112
112
113 if mark not in repo._bookmarks:
113 if mark not in repo._bookmarks:
114 mark = ''
114 mark = ''
115
115
116 wlock = repo.wlock()
116 wlock = repo.wlock()
117 try:
117 try:
118 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
118 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
119 file.write(encoding.fromlocal(mark))
119 file.write(encoding.fromlocal(mark))
120 file.close()
120 file.close()
121 finally:
121 finally:
122 wlock.release()
122 wlock.release()
123 repo._bookmarkcurrent = mark
123 repo._bookmarkcurrent = mark
124
124
125 def unsetcurrent(repo):
125 def unsetcurrent(repo):
126 wlock = repo.wlock()
126 wlock = repo.wlock()
127 try:
127 try:
128 try:
128 try:
129 repo.vfs.unlink('bookmarks.current')
129 repo.vfs.unlink('bookmarks.current')
130 repo._bookmarkcurrent = None
130 repo._bookmarkcurrent = None
131 except OSError, inst:
131 except OSError, inst:
132 if inst.errno != errno.ENOENT:
132 if inst.errno != errno.ENOENT:
133 raise
133 raise
134 finally:
134 finally:
135 wlock.release()
135 wlock.release()
136
136
137 def iscurrent(repo, mark=None, parents=None):
137 def iscurrent(repo, mark=None, parents=None):
138 '''Tell whether the current bookmark is also active
138 '''Tell whether the current bookmark is also active
139
139
140 I.e., the bookmark listed in .hg/bookmarks.current also points to a
140 I.e., the bookmark listed in .hg/bookmarks.current also points to a
141 parent of the working directory.
141 parent of the working directory.
142 '''
142 '''
143 if not mark:
143 if not mark:
144 mark = repo._bookmarkcurrent
144 mark = repo._bookmarkcurrent
145 if not parents:
145 if not parents:
146 parents = [p.node() for p in repo[None].parents()]
146 parents = [p.node() for p in repo[None].parents()]
147 marks = repo._bookmarks
147 marks = repo._bookmarks
148 return (mark in marks and marks[mark] in parents)
148 return (mark in marks and marks[mark] in parents)
149
149
150 def updatecurrentbookmark(repo, oldnode, curbranch):
150 def updatecurrentbookmark(repo, oldnode, curbranch):
151 try:
151 try:
152 return update(repo, oldnode, repo.branchtip(curbranch))
152 return update(repo, oldnode, repo.branchtip(curbranch))
153 except error.RepoLookupError:
153 except error.RepoLookupError:
154 if curbranch == "default": # no default branch!
154 if curbranch == "default": # no default branch!
155 return update(repo, oldnode, repo.lookup("tip"))
155 return update(repo, oldnode, repo.lookup("tip"))
156 else:
156 else:
157 raise util.Abort(_("branch %s not found") % curbranch)
157 raise util.Abort(_("branch %s not found") % curbranch)
158
158
159 def deletedivergent(repo, deletefrom, bm):
159 def deletedivergent(repo, deletefrom, bm):
160 '''Delete divergent versions of bm on nodes in deletefrom.
160 '''Delete divergent versions of bm on nodes in deletefrom.
161
161
162 Return True if at least one bookmark was deleted, False otherwise.'''
162 Return True if at least one bookmark was deleted, False otherwise.'''
163 deleted = False
163 deleted = False
164 marks = repo._bookmarks
164 marks = repo._bookmarks
165 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
165 divergent = [b for b in marks if b.split('@', 1)[0] == bm.split('@', 1)[0]]
166 for mark in divergent:
166 for mark in divergent:
167 if mark and marks[mark] in deletefrom:
167 if mark and marks[mark] in deletefrom:
168 if mark != bm:
168 if mark != bm:
169 del marks[mark]
169 del marks[mark]
170 deleted = True
170 deleted = True
171 return deleted
171 return deleted
172
172
173 def calculateupdate(ui, repo, checkout):
173 def calculateupdate(ui, repo, checkout):
174 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
174 '''Return a tuple (targetrev, movemarkfrom) indicating the rev to
175 check out and where to move the active bookmark from, if needed.'''
175 check out and where to move the active bookmark from, if needed.'''
176 movemarkfrom = None
176 movemarkfrom = None
177 if checkout is None:
177 if checkout is None:
178 curmark = repo._bookmarkcurrent
178 curmark = repo._bookmarkcurrent
179 if iscurrent(repo):
179 if iscurrent(repo):
180 movemarkfrom = repo['.'].node()
180 movemarkfrom = repo['.'].node()
181 elif curmark:
181 elif curmark:
182 ui.status(_("updating to active bookmark %s\n") % curmark)
182 ui.status(_("updating to active bookmark %s\n") % curmark)
183 checkout = curmark
183 checkout = curmark
184 return (checkout, movemarkfrom)
184 return (checkout, movemarkfrom)
185
185
186 def update(repo, parents, node):
186 def update(repo, parents, node):
187 deletefrom = parents
187 deletefrom = parents
188 marks = repo._bookmarks
188 marks = repo._bookmarks
189 update = False
189 update = False
190 cur = repo._bookmarkcurrent
190 cur = repo._bookmarkcurrent
191 if not cur:
191 if not cur:
192 return False
192 return False
193
193
194 if marks[cur] in parents:
194 if marks[cur] in parents:
195 old = repo[marks[cur]]
195 old = repo[marks[cur]]
196 new = repo[node]
196 new = repo[node]
197 divs = [repo[b] for b in marks
197 divs = [repo[b] for b in marks
198 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
198 if b.split('@', 1)[0] == cur.split('@', 1)[0]]
199 anc = repo.changelog.ancestors([new.rev()])
199 anc = repo.changelog.ancestors([new.rev()])
200 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
200 deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
201 if old.descendant(new):
201 if old.descendant(new):
202 marks[cur] = new.node()
202 marks[cur] = new.node()
203 update = True
203 update = True
204
204
205 if deletedivergent(repo, deletefrom, cur):
205 if deletedivergent(repo, deletefrom, cur):
206 update = True
206 update = True
207
207
208 if update:
208 if update:
209 marks.write()
209 marks.write()
210 return update
210 return update
211
211
212 def listbookmarks(repo):
212 def listbookmarks(repo):
213 # We may try to list bookmarks on a repo type that does not
213 # We may try to list bookmarks on a repo type that does not
214 # support it (e.g., statichttprepository).
214 # support it (e.g., statichttprepository).
215 marks = getattr(repo, '_bookmarks', {})
215 marks = getattr(repo, '_bookmarks', {})
216
216
217 d = {}
217 d = {}
218 hasnode = repo.changelog.hasnode
218 hasnode = repo.changelog.hasnode
219 for k, v in marks.iteritems():
219 for k, v in marks.iteritems():
220 # don't expose local divergent bookmarks
220 # don't expose local divergent bookmarks
221 if hasnode(v) and ('@' not in k or k.endswith('@')):
221 if hasnode(v) and ('@' not in k or k.endswith('@')):
222 d[k] = hex(v)
222 d[k] = hex(v)
223 return d
223 return d
224
224
225 def pushbookmark(repo, key, old, new):
225 def pushbookmark(repo, key, old, new):
226 w = repo.wlock()
226 w = repo.wlock()
227 try:
227 try:
228 marks = repo._bookmarks
228 marks = repo._bookmarks
229 if hex(marks.get(key, '')) != old:
229 if hex(marks.get(key, '')) != old:
230 return False
230 return False
231 if new == '':
231 if new == '':
232 del marks[key]
232 del marks[key]
233 else:
233 else:
234 if new not in repo:
234 if new not in repo:
235 return False
235 return False
236 marks[key] = repo[new].node()
236 marks[key] = repo[new].node()
237 marks.write()
237 marks.write()
238 return True
238 return True
239 finally:
239 finally:
240 w.release()
240 w.release()
241
241
242 def compare(repo, srcmarks, dstmarks,
242 def compare(repo, srcmarks, dstmarks,
243 srchex=None, dsthex=None, targets=None):
243 srchex=None, dsthex=None, targets=None):
244 '''Compare bookmarks between srcmarks and dstmarks
244 '''Compare bookmarks between srcmarks and dstmarks
245
245
246 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
246 This returns tuple "(addsrc, adddst, advsrc, advdst, diverge,
247 differ, invalid)", each are list of bookmarks below:
247 differ, invalid)", each are list of bookmarks below:
248
248
249 :addsrc: added on src side (removed on dst side, perhaps)
249 :addsrc: added on src side (removed on dst side, perhaps)
250 :adddst: added on dst side (removed on src side, perhaps)
250 :adddst: added on dst side (removed on src side, perhaps)
251 :advsrc: advanced on src side
251 :advsrc: advanced on src side
252 :advdst: advanced on dst side
252 :advdst: advanced on dst side
253 :diverge: diverge
253 :diverge: diverge
254 :differ: changed, but changeset referred on src is unknown on dst
254 :differ: changed, but changeset referred on src is unknown on dst
255 :invalid: unknown on both side
255 :invalid: unknown on both side
256
256
257 Each elements of lists in result tuple is tuple "(bookmark name,
257 Each elements of lists in result tuple is tuple "(bookmark name,
258 changeset ID on source side, changeset ID on destination
258 changeset ID on source side, changeset ID on destination
259 side)". Each changeset IDs are 40 hexadecimal digit string or
259 side)". Each changeset IDs are 40 hexadecimal digit string or
260 None.
260 None.
261
261
262 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
262 Changeset IDs of tuples in "addsrc", "adddst", "differ" or
263 "invalid" list may be unknown for repo.
263 "invalid" list may be unknown for repo.
264
264
265 This function expects that "srcmarks" and "dstmarks" return
265 This function expects that "srcmarks" and "dstmarks" return
266 changeset ID in 40 hexadecimal digit string for specified
266 changeset ID in 40 hexadecimal digit string for specified
267 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
267 bookmark. If not so (e.g. bmstore "repo._bookmarks" returning
268 binary value), "srchex" or "dsthex" should be specified to convert
268 binary value), "srchex" or "dsthex" should be specified to convert
269 into such form.
269 into such form.
270
270
271 If "targets" is specified, only bookmarks listed in it are
271 If "targets" is specified, only bookmarks listed in it are
272 examined.
272 examined.
273 '''
273 '''
274 if not srchex:
274 if not srchex:
275 srchex = lambda x: x
275 srchex = lambda x: x
276 if not dsthex:
276 if not dsthex:
277 dsthex = lambda x: x
277 dsthex = lambda x: x
278
278
279 if targets:
279 if targets:
280 bset = set(targets)
280 bset = set(targets)
281 else:
281 else:
282 srcmarkset = set(srcmarks)
282 srcmarkset = set(srcmarks)
283 dstmarkset = set(dstmarks)
283 dstmarkset = set(dstmarks)
284 bset = srcmarkset ^ dstmarkset
284 bset = srcmarkset ^ dstmarkset
285 for b in srcmarkset & dstmarkset:
285 for b in srcmarkset & dstmarkset:
286 if srchex(srcmarks[b]) != dsthex(dstmarks[b]):
286 if srchex(srcmarks[b]) != dsthex(dstmarks[b]):
287 bset.add(b)
287 bset.add(b)
288
288
289 results = ([], [], [], [], [], [], [])
289 results = ([], [], [], [], [], [], [])
290 addsrc = results[0].append
290 addsrc = results[0].append
291 adddst = results[1].append
291 adddst = results[1].append
292 advsrc = results[2].append
292 advsrc = results[2].append
293 advdst = results[3].append
293 advdst = results[3].append
294 diverge = results[4].append
294 diverge = results[4].append
295 differ = results[5].append
295 differ = results[5].append
296 invalid = results[6].append
296 invalid = results[6].append
297
297
298 for b in sorted(bset):
298 for b in sorted(bset):
299 if b not in srcmarks:
299 if b not in srcmarks:
300 if b in dstmarks:
300 if b in dstmarks:
301 adddst((b, None, dsthex(dstmarks[b])))
301 adddst((b, None, dsthex(dstmarks[b])))
302 else:
302 else:
303 invalid((b, None, None))
303 invalid((b, None, None))
304 elif b not in dstmarks:
304 elif b not in dstmarks:
305 addsrc((b, srchex(srcmarks[b]), None))
305 addsrc((b, srchex(srcmarks[b]), None))
306 else:
306 else:
307 scid = srchex(srcmarks[b])
307 scid = srchex(srcmarks[b])
308 dcid = dsthex(dstmarks[b])
308 dcid = dsthex(dstmarks[b])
309 if scid in repo and dcid in repo:
309 if scid in repo and dcid in repo:
310 sctx = repo[scid]
310 sctx = repo[scid]
311 dctx = repo[dcid]
311 dctx = repo[dcid]
312 if sctx.rev() < dctx.rev():
312 if sctx.rev() < dctx.rev():
313 if validdest(repo, sctx, dctx):
313 if validdest(repo, sctx, dctx):
314 advdst((b, scid, dcid))
314 advdst((b, scid, dcid))
315 else:
315 else:
316 diverge((b, scid, dcid))
316 diverge((b, scid, dcid))
317 else:
317 else:
318 if validdest(repo, dctx, sctx):
318 if validdest(repo, dctx, sctx):
319 advsrc((b, scid, dcid))
319 advsrc((b, scid, dcid))
320 else:
320 else:
321 diverge((b, scid, dcid))
321 diverge((b, scid, dcid))
322 else:
322 else:
323 # it is too expensive to examine in detail, in this case
323 # it is too expensive to examine in detail, in this case
324 differ((b, scid, dcid))
324 differ((b, scid, dcid))
325
325
326 return results
326 return results
327
327
328 def updatefromremote(ui, repo, remotemarks, path):
328 def _diverge(ui, b, path, localmarks):
329 ui.debug("checking for updated bookmarks\n")
329 if b == '@':
330 changed = False
330 b = ''
331 localmarks = repo._bookmarks
332 for k in sorted(remotemarks):
333 if k in localmarks:
334 nr, nl = remotemarks[k], localmarks[k]
335 if nr in repo:
336 cr = repo[nr]
337 cl = repo[nl]
338 if cl.rev() >= cr.rev():
339 continue
340 if validdest(repo, cl, cr):
341 localmarks[k] = cr.node()
342 changed = True
343 ui.status(_("updating bookmark %s\n") % k)
344 else:
345 if k == '@':
346 kd = ''
347 else:
348 kd = k
349 # find a unique @ suffix
331 # find a unique @ suffix
350 for x in range(1, 100):
332 for x in range(1, 100):
351 n = '%s@%d' % (kd, x)
333 n = '%s@%d' % (b, x)
352 if n not in localmarks:
334 if n not in localmarks:
353 break
335 break
354 # try to use an @pathalias suffix
336 # try to use an @pathalias suffix
355 # if an @pathalias already exists, we overwrite (update) it
337 # if an @pathalias already exists, we overwrite (update) it
356 for p, u in ui.configitems("paths"):
338 for p, u in ui.configitems("paths"):
357 if path == u:
339 if path == u:
358 n = '%s@%s' % (kd, p)
340 n = '%s@%s' % (b, p)
341 return n
342
343 def updatefromremote(ui, repo, remotemarks, path):
344 ui.debug("checking for updated bookmarks\n")
345 localmarks = repo._bookmarks
346 (addsrc, adddst, advsrc, advdst, diverge, differ, invalid
347 ) = compare(repo, remotemarks, localmarks, dsthex=hex)
359
348
360 localmarks[n] = cr.node()
349 changed = []
361 changed = True
350 for b, scid, dcid in addsrc:
362 ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n))
351 if scid in repo: # add remote bookmarks for changes we already have
363 elif remotemarks[k] in repo:
352 changed.append((b, bin(scid), ui.status,
364 # add remote bookmarks for changes we already have
353 _("adding remote bookmark %s\n") % (b)))
365 localmarks[k] = repo[remotemarks[k]].node()
354 for b, scid, dcid in advsrc:
366 changed = True
355 changed.append((b, bin(scid), ui.status,
367 ui.status(_("adding remote bookmark %s\n") % k)
356 _("updating bookmark %s\n") % (b)))
368
357 for b, scid, dcid in diverge:
358 db = _diverge(ui, b, path, localmarks)
359 changed.append((db, bin(scid), ui.warn,
360 _("divergent bookmark %s stored as %s\n") % (b, db)))
369 if changed:
361 if changed:
362 for b, node, writer, msg in sorted(changed):
363 localmarks[b] = node
364 writer(msg)
370 localmarks.write()
365 localmarks.write()
371
366
372 def diff(ui, dst, src):
367 def diff(ui, dst, src):
373 ui.status(_("searching for changed bookmarks\n"))
368 ui.status(_("searching for changed bookmarks\n"))
374
369
375 smarks = src.listkeys('bookmarks')
370 smarks = src.listkeys('bookmarks')
376 dmarks = dst.listkeys('bookmarks')
371 dmarks = dst.listkeys('bookmarks')
377
372
378 diff = sorted(set(smarks) - set(dmarks))
373 diff = sorted(set(smarks) - set(dmarks))
379 for k in diff:
374 for k in diff:
380 mark = ui.debugflag and smarks[k] or smarks[k][:12]
375 mark = ui.debugflag and smarks[k] or smarks[k][:12]
381 ui.write(" %-25s %s\n" % (k, mark))
376 ui.write(" %-25s %s\n" % (k, mark))
382
377
383 if len(diff) <= 0:
378 if len(diff) <= 0:
384 ui.status(_("no changed bookmarks found\n"))
379 ui.status(_("no changed bookmarks found\n"))
385 return 1
380 return 1
386 return 0
381 return 0
387
382
388 def validdest(repo, old, new):
383 def validdest(repo, old, new):
389 """Is the new bookmark destination a valid update from the old one"""
384 """Is the new bookmark destination a valid update from the old one"""
390 repo = repo.unfiltered()
385 repo = repo.unfiltered()
391 if old == new:
386 if old == new:
392 # Old == new -> nothing to update.
387 # Old == new -> nothing to update.
393 return False
388 return False
394 elif not old:
389 elif not old:
395 # old is nullrev, anything is valid.
390 # old is nullrev, anything is valid.
396 # (new != nullrev has been excluded by the previous check)
391 # (new != nullrev has been excluded by the previous check)
397 return True
392 return True
398 elif repo.obsstore:
393 elif repo.obsstore:
399 return new.node() in obsolete.foreground(repo, [old.node()])
394 return new.node() in obsolete.foreground(repo, [old.node()])
400 else:
395 else:
401 # still an independent clause as it is lazyer (and therefore faster)
396 # still an independent clause as it is lazyer (and therefore faster)
402 return old.descendant(new)
397 return old.descendant(new)
General Comments 0
You need to be logged in to leave comments. Login now