##// END OF EJS Templates
bookmarks: introduce a bmstore to manage bookmark persistence...
Augie Fackler -
r17922:7f5dab94 default
parent child Browse files
Show More
@@ -219,9 +219,10 b' class mercurial_sink(converter_sink):'
219 return
219 return
220
220
221 self.ui.status(_("updating bookmarks\n"))
221 self.ui.status(_("updating bookmarks\n"))
222 destmarks = self.repo._bookmarks
222 for bookmark in updatedbookmark:
223 for bookmark in updatedbookmark:
223 self.repo._bookmarks[bookmark] = bin(updatedbookmark[bookmark])
224 destmarks[bookmark] = bin(updatedbookmark[bookmark])
224 bookmarks.write(self.repo)
225 destmarks.write()
225
226
226 def hascommit(self, rev):
227 def hascommit(self, rev):
227 if rev not in self.repo and self.clonebranches:
228 if rev not in self.repo and self.clonebranches:
@@ -144,7 +144,6 b' except ImportError:'
144 import pickle
144 import pickle
145 import os
145 import os
146
146
147 from mercurial import bookmarks
148 from mercurial import cmdutil
147 from mercurial import cmdutil
149 from mercurial import discovery
148 from mercurial import discovery
150 from mercurial import error
149 from mercurial import error
@@ -740,12 +739,13 b' def movebookmarks(ui, repo, mapping, old'
740 # nothing to move
739 # nothing to move
741 moves.append((bk, new[-1]))
740 moves.append((bk, new[-1]))
742 if moves:
741 if moves:
742 marks = repo._bookmarks
743 for mark, new in moves:
743 for mark, new in moves:
744 old = repo._bookmarks[mark]
744 old = marks[mark]
745 ui.note(_('histedit: moving bookmarks %s from %s to %s\n')
745 ui.note(_('histedit: moving bookmarks %s from %s to %s\n')
746 % (mark, node.short(old), node.short(new)))
746 % (mark, node.short(old), node.short(new)))
747 repo._bookmarks[mark] = new
747 marks[mark] = new
748 bookmarks.write(repo)
748 marks.write()
749
749
750 def cleanupnode(ui, repo, name, nodes):
750 def cleanupnode(ui, repo, name, nodes):
751 """strip a group of nodes from the repository
751 """strip a group of nodes from the repository
@@ -63,7 +63,7 b' from mercurial.i18n import _'
63 from mercurial.node import bin, hex, short, nullid, nullrev
63 from mercurial.node import bin, hex, short, nullid, nullrev
64 from mercurial.lock import release
64 from mercurial.lock import release
65 from mercurial import commands, cmdutil, hg, scmutil, util, revset
65 from mercurial import commands, cmdutil, hg, scmutil, util, revset
66 from mercurial import repair, extensions, error, phases, bookmarks
66 from mercurial import repair, extensions, error, phases
67 from mercurial import patch as patchmod
67 from mercurial import patch as patchmod
68 import os, re, errno, shutil
68 import os, re, errno, shutil
69
69
@@ -1675,9 +1675,10 b' class queue(object):'
1675 patchf.write(chunk)
1675 patchf.write(chunk)
1676 patchf.close()
1676 patchf.close()
1677
1677
1678 marks = repo._bookmarks
1678 for bm in bmlist:
1679 for bm in bmlist:
1679 repo._bookmarks[bm] = n
1680 marks[bm] = n
1680 bookmarks.write(repo)
1681 marks.write()
1681
1682
1682 self.applied.append(statusentry(n, patchfn))
1683 self.applied.append(statusentry(n, patchfn))
1683 except: # re-raises
1684 except: # re-raises
@@ -2999,7 +3000,7 b' def strip(ui, repo, *revs, **opts):'
2999 revs.update(set(rsrevs))
3000 revs.update(set(rsrevs))
3000 if not revs:
3001 if not revs:
3001 del marks[mark]
3002 del marks[mark]
3002 repo._writebookmarks(mark)
3003 marks.write()
3003 ui.write(_("bookmark '%s' deleted\n") % mark)
3004 ui.write(_("bookmark '%s' deleted\n") % mark)
3004
3005
3005 if not revs:
3006 if not revs:
@@ -3049,7 +3050,7 b' def strip(ui, repo, *revs, **opts):'
3049
3050
3050 if opts.get('bookmark'):
3051 if opts.get('bookmark'):
3051 del marks[mark]
3052 del marks[mark]
3052 repo._writebookmarks(marks)
3053 marks.write()
3053 ui.write(_("bookmark '%s' deleted\n") % mark)
3054 ui.write(_("bookmark '%s' deleted\n") % mark)
3054
3055
3055 repo.mq.strip(repo, revs, backup=backup, update=update,
3056 repo.mq.strip(repo, revs, backup=backup, update=update,
@@ -479,13 +479,14 b' def updatemq(repo, state, skipped, **opt'
479
479
480 def updatebookmarks(repo, nstate, originalbookmarks, **opts):
480 def updatebookmarks(repo, nstate, originalbookmarks, **opts):
481 'Move bookmarks to their correct changesets'
481 'Move bookmarks to their correct changesets'
482 marks = repo._bookmarks
482 for k, v in originalbookmarks.iteritems():
483 for k, v in originalbookmarks.iteritems():
483 if v in nstate:
484 if v in nstate:
484 if nstate[v] != nullmerge:
485 if nstate[v] != nullmerge:
485 # update the bookmarks for revs that have moved
486 # update the bookmarks for revs that have moved
486 repo._bookmarks[k] = nstate[v]
487 marks[k] = nstate[v]
487
488
488 bookmarks.write(repo)
489 marks.write()
489
490
490 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
491 def storestatus(repo, originalwd, target, state, collapse, keep, keepbranches,
491 external):
492 external):
@@ -10,32 +10,72 b' from mercurial.node import hex'
10 from mercurial import encoding, error, util, obsolete
10 from mercurial import encoding, error, util, obsolete
11 import errno, os
11 import errno, os
12
12
13 def read(repo):
13 class bmstore(dict):
14 '''Parse .hg/bookmarks file and return a dictionary
14 """Storage for bookmarks.
15
16 This object should do all bookmark reads and writes, so that it's
17 fairly simple to replace the storage underlying bookmarks without
18 having to clone the logic surrounding bookmarks.
19
20 This particular bmstore implementation stores bookmarks as
21 {hash}\s{name}\n (the same format as localtags) in
22 .hg/bookmarks. The mapping is stored as {name: nodeid}.
23
24 This class does NOT handle the "current" bookmark state at this
25 time.
26 """
15
27
16 Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
28 def __init__(self, repo):
17 in the .hg/bookmarks file.
29 dict.__init__(self)
18 Read the file and return a (name=>nodeid) dictionary
30 self._repo = repo
19 '''
31 try:
20 bookmarks = {}
32 for line in repo.vfs('bookmarks'):
21 try:
33 line = line.strip()
22 for line in repo.opener('bookmarks'):
34 if not line:
23 line = line.strip()
35 continue
24 if not line:
36 if ' ' not in line:
25 continue
37 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n')
26 if ' ' not in line:
38 % line)
27 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n') % line)
39 continue
28 continue
40 sha, refspec = line.split(' ', 1)
29 sha, refspec = line.split(' ', 1)
41 refspec = encoding.tolocal(refspec)
30 refspec = encoding.tolocal(refspec)
42 try:
43 self[refspec] = repo.changelog.lookup(sha)
44 except LookupError:
45 pass
46 except IOError, inst:
47 if inst.errno != errno.ENOENT:
48 raise
49
50 def write(self):
51 '''Write bookmarks
52
53 Write the given bookmark => hash dictionary to the .hg/bookmarks file
54 in a format equal to those of localtags.
55
56 We also store a backup of the previous state in undo.bookmarks that
57 can be copied back on rollback.
58 '''
59 repo = self._repo
60 if repo._bookmarkcurrent not in self:
61 setcurrent(repo, None)
62
63 wlock = repo.wlock()
64 try:
65
66 file = repo.vfs('bookmarks', 'w', atomictemp=True)
67 for name, node in self.iteritems():
68 file.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
69 file.close()
70
71 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
31 try:
72 try:
32 bookmarks[refspec] = repo.changelog.lookup(sha)
73 os.utime(repo.sjoin('00changelog.i'), None)
33 except LookupError:
74 except OSError:
34 pass
75 pass
35 except IOError, inst:
76
36 if inst.errno != errno.ENOENT:
77 finally:
37 raise
78 wlock.release()
38 return bookmarks
39
79
40 def readcurrent(repo):
80 def readcurrent(repo):
41 '''Get the current bookmark
81 '''Get the current bookmark
@@ -60,37 +100,6 b' def readcurrent(repo):'
60 file.close()
100 file.close()
61 return mark
101 return mark
62
102
63 def write(repo):
64 '''Write bookmarks
65
66 Write the given bookmark => hash dictionary to the .hg/bookmarks file
67 in a format equal to those of localtags.
68
69 We also store a backup of the previous state in undo.bookmarks that
70 can be copied back on rollback.
71 '''
72 refs = repo._bookmarks
73
74 if repo._bookmarkcurrent not in refs:
75 setcurrent(repo, None)
76
77 wlock = repo.wlock()
78 try:
79
80 file = repo.opener('bookmarks', 'w', atomictemp=True)
81 for refspec, node in refs.iteritems():
82 file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec)))
83 file.close()
84
85 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
86 try:
87 os.utime(repo.sjoin('00changelog.i'), None)
88 except OSError:
89 pass
90
91 finally:
92 wlock.release()
93
94 def setcurrent(repo, mark):
103 def setcurrent(repo, mark):
95 '''Set the name of the bookmark that we are currently on
104 '''Set the name of the bookmark that we are currently on
96
105
@@ -152,7 +161,7 b' def update(repo, parents, node):'
152 if mark != cur:
161 if mark != cur:
153 del marks[mark]
162 del marks[mark]
154 if update:
163 if update:
155 repo._writebookmarks(marks)
164 marks.write()
156 return update
165 return update
157
166
158 def listbookmarks(repo):
167 def listbookmarks(repo):
@@ -179,7 +188,7 b' def pushbookmark(repo, key, old, new):'
179 if new not in repo:
188 if new not in repo:
180 return False
189 return False
181 marks[key] = repo[new].node()
190 marks[key] = repo[new].node()
182 write(repo)
191 marks.write()
183 return True
192 return True
184 finally:
193 finally:
185 w.release()
194 w.release()
@@ -188,16 +197,17 b' def updatefromremote(ui, repo, remote, p'
188 ui.debug("checking for updated bookmarks\n")
197 ui.debug("checking for updated bookmarks\n")
189 rb = remote.listkeys('bookmarks')
198 rb = remote.listkeys('bookmarks')
190 changed = False
199 changed = False
200 localmarks = repo._bookmarks
191 for k in rb.keys():
201 for k in rb.keys():
192 if k in repo._bookmarks:
202 if k in localmarks:
193 nr, nl = rb[k], repo._bookmarks[k]
203 nr, nl = rb[k], localmarks[k]
194 if nr in repo:
204 if nr in repo:
195 cr = repo[nr]
205 cr = repo[nr]
196 cl = repo[nl]
206 cl = repo[nl]
197 if cl.rev() >= cr.rev():
207 if cl.rev() >= cr.rev():
198 continue
208 continue
199 if validdest(repo, cl, cr):
209 if validdest(repo, cl, cr):
200 repo._bookmarks[k] = cr.node()
210 localmarks[k] = cr.node()
201 changed = True
211 changed = True
202 ui.status(_("updating bookmark %s\n") % k)
212 ui.status(_("updating bookmark %s\n") % k)
203 else:
213 else:
@@ -208,7 +218,7 b' def updatefromremote(ui, repo, remote, p'
208 # find a unique @ suffix
218 # find a unique @ suffix
209 for x in range(1, 100):
219 for x in range(1, 100):
210 n = '%s@%d' % (kd, x)
220 n = '%s@%d' % (kd, x)
211 if n not in repo._bookmarks:
221 if n not in localmarks:
212 break
222 break
213 # try to use an @pathalias suffix
223 # try to use an @pathalias suffix
214 # if an @pathalias already exists, we overwrite (update) it
224 # if an @pathalias already exists, we overwrite (update) it
@@ -216,17 +226,17 b' def updatefromremote(ui, repo, remote, p'
216 if path == u:
226 if path == u:
217 n = '%s@%s' % (kd, p)
227 n = '%s@%s' % (kd, p)
218
228
219 repo._bookmarks[n] = cr.node()
229 localmarks[n] = cr.node()
220 changed = True
230 changed = True
221 ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n))
231 ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n))
222 elif rb[k] in repo:
232 elif rb[k] in repo:
223 # add remote bookmarks for changes we already have
233 # add remote bookmarks for changes we already have
224 repo._bookmarks[k] = repo[rb[k]].node()
234 localmarks[k] = repo[rb[k]].node()
225 changed = True
235 changed = True
226 ui.status(_("adding remote bookmark %s\n") % k)
236 ui.status(_("adding remote bookmark %s\n") % k)
227
237
228 if changed:
238 if changed:
229 write(repo)
239 localmarks.write()
230
240
231 def diff(ui, dst, src):
241 def diff(ui, dst, src):
232 ui.status(_("searching for changed bookmarks\n"))
242 ui.status(_("searching for changed bookmarks\n"))
@@ -10,7 +10,7 b' from i18n import _'
10 import os, sys, errno, re, tempfile
10 import os, sys, errno, re, tempfile
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
11 import util, scmutil, templater, patch, error, templatekw, revlog, copies
12 import match as matchmod
12 import match as matchmod
13 import subrepo, context, repair, bookmarks, graphmod, revset, phases, obsolete
13 import subrepo, context, repair, graphmod, revset, phases, obsolete
14 import changelog
14 import changelog
15 import lock as lockmod
15 import lock as lockmod
16
16
@@ -1756,9 +1756,10 b' def amend(ui, repo, commitfunc, old, ext'
1756 # Move bookmarks from old parent to amend commit
1756 # Move bookmarks from old parent to amend commit
1757 bms = repo.nodebookmarks(old.node())
1757 bms = repo.nodebookmarks(old.node())
1758 if bms:
1758 if bms:
1759 marks = repo._bookmarks
1759 for bm in bms:
1760 for bm in bms:
1760 repo._bookmarks[bm] = newid
1761 marks[bm] = newid
1761 bookmarks.write(repo)
1762 marks.write()
1762 #commit the whole amend process
1763 #commit the whole amend process
1763 if obsolete._enabled and newid != old.node():
1764 if obsolete._enabled and newid != old.node():
1764 # mark the new changeset as successor of the rewritten one
1765 # mark the new changeset as successor of the rewritten one
@@ -821,7 +821,7 b' def bookmark(ui, repo, mark=None, rev=No'
821 if mark == repo._bookmarkcurrent:
821 if mark == repo._bookmarkcurrent:
822 bookmarks.setcurrent(repo, None)
822 bookmarks.setcurrent(repo, None)
823 del marks[mark]
823 del marks[mark]
824 bookmarks.write(repo)
824 marks.write()
825
825
826 elif rename:
826 elif rename:
827 if mark is None:
827 if mark is None:
@@ -834,7 +834,7 b' def bookmark(ui, repo, mark=None, rev=No'
834 if repo._bookmarkcurrent == rename and not inactive:
834 if repo._bookmarkcurrent == rename and not inactive:
835 bookmarks.setcurrent(repo, mark)
835 bookmarks.setcurrent(repo, mark)
836 del marks[rename]
836 del marks[rename]
837 bookmarks.write(repo)
837 marks.write()
838
838
839 elif mark is not None:
839 elif mark is not None:
840 mark = checkformat(mark)
840 mark = checkformat(mark)
@@ -848,7 +848,7 b' def bookmark(ui, repo, mark=None, rev=No'
848 marks[mark] = cur
848 marks[mark] = cur
849 if not inactive and cur == marks[mark]:
849 if not inactive and cur == marks[mark]:
850 bookmarks.setcurrent(repo, mark)
850 bookmarks.setcurrent(repo, mark)
851 bookmarks.write(repo)
851 marks.write()
852
852
853 # Same message whether trying to deactivate the current bookmark (-i
853 # Same message whether trying to deactivate the current bookmark (-i
854 # with no NAME) or listing bookmarks
854 # with no NAME) or listing bookmarks
@@ -1321,11 +1321,12 b' def commit(ui, repo, *pats, **opts):'
1321 elif marks:
1321 elif marks:
1322 ui.debug('moving bookmarks %r from %s to %s\n' %
1322 ui.debug('moving bookmarks %r from %s to %s\n' %
1323 (marks, old.hex(), hex(node)))
1323 (marks, old.hex(), hex(node)))
1324 newmarks = repo._bookmarks
1324 for bm in marks:
1325 for bm in marks:
1325 repo._bookmarks[bm] = node
1326 newmarks[bm] = node
1326 if bm == current:
1327 if bm == current:
1327 bookmarks.setcurrent(repo, bm)
1328 bookmarks.setcurrent(repo, bm)
1328 bookmarks.write(repo)
1329 newmarks.write()
1329 else:
1330 else:
1330 e = cmdutil.commiteditor
1331 e = cmdutil.commiteditor
1331 if opts.get('force_editor'):
1332 if opts.get('force_editor'):
@@ -4673,11 +4674,12 b' def pull(ui, repo, source="default", **o'
4673
4674
4674 # update specified bookmarks
4675 # update specified bookmarks
4675 if opts.get('bookmark'):
4676 if opts.get('bookmark'):
4677 marks = repo._bookmarks
4676 for b in opts['bookmark']:
4678 for b in opts['bookmark']:
4677 # explicit pull overrides local bookmark if any
4679 # explicit pull overrides local bookmark if any
4678 ui.status(_("importing bookmark %s\n") % b)
4680 ui.status(_("importing bookmark %s\n") % b)
4679 repo._bookmarks[b] = repo[rb[b]].node()
4681 marks[b] = repo[rb[b]].node()
4680 bookmarks.write(repo)
4682 marks.write()
4681
4683
4682 return ret
4684 return ret
4683
4685
@@ -391,14 +391,15 b' def clone(ui, peeropts, source, dest=Non'
391 destrepo = destpeer.local()
391 destrepo = destpeer.local()
392 if destrepo and srcpeer.capable("pushkey"):
392 if destrepo and srcpeer.capable("pushkey"):
393 rb = srcpeer.listkeys('bookmarks')
393 rb = srcpeer.listkeys('bookmarks')
394 marks = destrepo._bookmarks
394 for k, n in rb.iteritems():
395 for k, n in rb.iteritems():
395 try:
396 try:
396 m = destrepo.lookup(n)
397 m = destrepo.lookup(n)
397 destrepo._bookmarks[k] = m
398 marks[k] = m
398 except error.RepoLookupError:
399 except error.RepoLookupError:
399 pass
400 pass
400 if rb:
401 if rb:
401 bookmarks.write(destrepo)
402 marks.write()
402 elif srcrepo and destpeer.capable("pushkey"):
403 elif srcrepo and destpeer.capable("pushkey"):
403 for k, n in srcrepo._bookmarks.iteritems():
404 for k, n in srcrepo._bookmarks.iteritems():
404 destpeer.pushkey('bookmarks', k, '', hex(n))
405 destpeer.pushkey('bookmarks', k, '', hex(n))
@@ -265,15 +265,12 b' class localrepository(object):'
265
265
266 @filecache('bookmarks')
266 @filecache('bookmarks')
267 def _bookmarks(self):
267 def _bookmarks(self):
268 return bookmarks.read(self)
268 return bookmarks.bmstore(self)
269
269
270 @filecache('bookmarks.current')
270 @filecache('bookmarks.current')
271 def _bookmarkcurrent(self):
271 def _bookmarkcurrent(self):
272 return bookmarks.readcurrent(self)
272 return bookmarks.readcurrent(self)
273
273
274 def _writebookmarks(self, marks):
275 bookmarks.write(self)
276
277 def bookmarkheads(self, bookmark):
274 def bookmarkheads(self, bookmark):
278 name = bookmark.split('@', 1)[0]
275 name = bookmark.split('@', 1)[0]
279 heads = []
276 heads = []
@@ -6,7 +6,7 b''
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from mercurial import changegroup, bookmarks
9 from mercurial import changegroup
10 from mercurial.node import short
10 from mercurial.node import short
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12 import os
12 import os
@@ -181,7 +181,7 b' def strip(ui, repo, nodelist, backup="al'
181
181
182 for m in updatebm:
182 for m in updatebm:
183 bm[m] = repo[newbmtarget].node()
183 bm[m] = repo[newbmtarget].node()
184 bookmarks.write(repo)
184 bm.write()
185 except: # re-raises
185 except: # re-raises
186 if backupfile:
186 if backupfile:
187 ui.warn(_("strip failed, full bundle stored in '%s'\n")
187 ui.warn(_("strip failed, full bundle stored in '%s'\n")
General Comments 0
You need to be logged in to leave comments. Login now