##// END OF EJS Templates
bookmarks: remove API limitation in setcurrent...
David Soria Parra -
r13647:c0c59970 default
parent child Browse files
Show More
@@ -1,201 +1,195 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 nullid, nullrev, bin, hex, short
9 from mercurial.node import nullid, nullrev, bin, hex, short
10 from mercurial import encoding, util
10 from mercurial import encoding, util
11 import os
11 import os
12
12
13 def valid(mark):
13 def valid(mark):
14 for c in (':', '\0', '\n', '\r'):
14 for c in (':', '\0', '\n', '\r'):
15 if c in mark:
15 if c in mark:
16 return False
16 return False
17 return True
17 return True
18
18
19 def read(repo):
19 def read(repo):
20 '''Parse .hg/bookmarks file and return a dictionary
20 '''Parse .hg/bookmarks file and return a dictionary
21
21
22 Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
22 Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
23 in the .hg/bookmarks file.
23 in the .hg/bookmarks file.
24 Read the file and return a (name=>nodeid) dictionary
24 Read the file and return a (name=>nodeid) dictionary
25 '''
25 '''
26 try:
26 try:
27 bookmarks = {}
27 bookmarks = {}
28 for line in repo.opener('bookmarks'):
28 for line in repo.opener('bookmarks'):
29 sha, refspec = line.strip().split(' ', 1)
29 sha, refspec = line.strip().split(' ', 1)
30 refspec = encoding.tolocal(refspec)
30 refspec = encoding.tolocal(refspec)
31 bookmarks[refspec] = repo.changelog.lookup(sha)
31 bookmarks[refspec] = repo.changelog.lookup(sha)
32 except:
32 except:
33 pass
33 pass
34 return bookmarks
34 return bookmarks
35
35
36 def readcurrent(repo):
36 def readcurrent(repo):
37 '''Get the current bookmark
37 '''Get the current bookmark
38
38
39 If we use gittishsh branches we have a current bookmark that
39 If we use gittishsh branches we have a current bookmark that
40 we are on. This function returns the name of the bookmark. It
40 we are on. This function returns the name of the bookmark. It
41 is stored in .hg/bookmarks.current
41 is stored in .hg/bookmarks.current
42 '''
42 '''
43 mark = None
43 mark = None
44 if os.path.exists(repo.join('bookmarks.current')):
44 if os.path.exists(repo.join('bookmarks.current')):
45 file = repo.opener('bookmarks.current')
45 file = repo.opener('bookmarks.current')
46 # No readline() in posixfile_nt, reading everything is cheap
46 # No readline() in posixfile_nt, reading everything is cheap
47 mark = encoding.tolocal((file.readlines() or [''])[0])
47 mark = encoding.tolocal((file.readlines() or [''])[0])
48 if mark == '' or mark not in repo._bookmarks:
48 if mark == '' or mark not in repo._bookmarks:
49 mark = None
49 mark = None
50 file.close()
50 file.close()
51 return mark
51 return mark
52
52
53 def write(repo):
53 def write(repo):
54 '''Write bookmarks
54 '''Write bookmarks
55
55
56 Write the given bookmark => hash dictionary to the .hg/bookmarks file
56 Write the given bookmark => hash dictionary to the .hg/bookmarks file
57 in a format equal to those of localtags.
57 in a format equal to those of localtags.
58
58
59 We also store a backup of the previous state in undo.bookmarks that
59 We also store a backup of the previous state in undo.bookmarks that
60 can be copied back on rollback.
60 can be copied back on rollback.
61 '''
61 '''
62 refs = repo._bookmarks
62 refs = repo._bookmarks
63
63
64 try:
64 try:
65 bms = repo.opener('bookmarks').read()
65 bms = repo.opener('bookmarks').read()
66 except IOError:
66 except IOError:
67 bms = ''
67 bms = ''
68 repo.opener('undo.bookmarks', 'w').write(bms)
68 repo.opener('undo.bookmarks', 'w').write(bms)
69
69
70 if repo._bookmarkcurrent not in refs:
70 if repo._bookmarkcurrent not in refs:
71 setcurrent(repo, None)
71 setcurrent(repo, None)
72 for mark in refs.keys():
72 for mark in refs.keys():
73 if not valid(mark):
73 if not valid(mark):
74 raise util.Abort(_("bookmark '%s' contains illegal "
74 raise util.Abort(_("bookmark '%s' contains illegal "
75 "character" % mark))
75 "character" % mark))
76
76
77 wlock = repo.wlock()
77 wlock = repo.wlock()
78 try:
78 try:
79
79
80 file = repo.opener('bookmarks', 'w', atomictemp=True)
80 file = repo.opener('bookmarks', 'w', atomictemp=True)
81 for refspec, node in refs.iteritems():
81 for refspec, node in refs.iteritems():
82 file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec)))
82 file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec)))
83 file.rename()
83 file.rename()
84
84
85 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
85 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
86 try:
86 try:
87 os.utime(repo.sjoin('00changelog.i'), None)
87 os.utime(repo.sjoin('00changelog.i'), None)
88 except OSError:
88 except OSError:
89 pass
89 pass
90
90
91 finally:
91 finally:
92 wlock.release()
92 wlock.release()
93
93
94 def setcurrent(repo, mark):
94 def setcurrent(repo, mark):
95 '''Set the name of the bookmark that we are currently on
95 '''Set the name of the bookmark that we are currently on
96
96
97 Set the name of the bookmark that we are on (hg update <bookmark>).
97 Set the name of the bookmark that we are on (hg update <bookmark>).
98 The name is recorded in .hg/bookmarks.current
98 The name is recorded in .hg/bookmarks.current
99 '''
99 '''
100 current = repo._bookmarkcurrent
100 current = repo._bookmarkcurrent
101 if current == mark:
101 if current == mark:
102 return
102 return
103
103
104 refs = repo._bookmarks
104 if mark not in repo._bookmarks:
105
106 # do not update if we do update to a rev equal to the current bookmark
107 if (mark and mark not in refs and
108 current and refs[current] == repo.changectx('.').node()):
109 return
110 if mark not in refs:
111 mark = ''
105 mark = ''
112 if not valid(mark):
106 if not valid(mark):
113 raise util.Abort(_("bookmark '%s' contains illegal "
107 raise util.Abort(_("bookmark '%s' contains illegal "
114 "character" % mark))
108 "character" % mark))
115
109
116 wlock = repo.wlock()
110 wlock = repo.wlock()
117 try:
111 try:
118 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
112 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
119 file.write(mark)
113 file.write(mark)
120 file.rename()
114 file.rename()
121 finally:
115 finally:
122 wlock.release()
116 wlock.release()
123 repo._bookmarkcurrent = mark
117 repo._bookmarkcurrent = mark
124
118
125 def update(repo, parents, node):
119 def update(repo, parents, node):
126 marks = repo._bookmarks
120 marks = repo._bookmarks
127 update = False
121 update = False
128 mark = repo._bookmarkcurrent
122 mark = repo._bookmarkcurrent
129 if mark and marks[mark] in parents:
123 if mark and marks[mark] in parents:
130 old = repo[marks[mark]]
124 old = repo[marks[mark]]
131 new = repo[node]
125 new = repo[node]
132 if new in old.descendants():
126 if new in old.descendants():
133 marks[mark] = new.node()
127 marks[mark] = new.node()
134 update = True
128 update = True
135 if update:
129 if update:
136 write(repo)
130 write(repo)
137
131
138 def listbookmarks(repo):
132 def listbookmarks(repo):
139 # We may try to list bookmarks on a repo type that does not
133 # We may try to list bookmarks on a repo type that does not
140 # support it (e.g., statichttprepository).
134 # support it (e.g., statichttprepository).
141 if not hasattr(repo, '_bookmarks'):
135 if not hasattr(repo, '_bookmarks'):
142 return {}
136 return {}
143
137
144 d = {}
138 d = {}
145 for k, v in repo._bookmarks.iteritems():
139 for k, v in repo._bookmarks.iteritems():
146 d[k] = hex(v)
140 d[k] = hex(v)
147 return d
141 return d
148
142
149 def pushbookmark(repo, key, old, new):
143 def pushbookmark(repo, key, old, new):
150 w = repo.wlock()
144 w = repo.wlock()
151 try:
145 try:
152 marks = repo._bookmarks
146 marks = repo._bookmarks
153 if hex(marks.get(key, '')) != old:
147 if hex(marks.get(key, '')) != old:
154 return False
148 return False
155 if new == '':
149 if new == '':
156 del marks[key]
150 del marks[key]
157 else:
151 else:
158 if new not in repo:
152 if new not in repo:
159 return False
153 return False
160 marks[key] = repo[new].node()
154 marks[key] = repo[new].node()
161 write(repo)
155 write(repo)
162 return True
156 return True
163 finally:
157 finally:
164 w.release()
158 w.release()
165
159
166 def updatefromremote(ui, repo, remote):
160 def updatefromremote(ui, repo, remote):
167 ui.debug("checking for updated bookmarks\n")
161 ui.debug("checking for updated bookmarks\n")
168 rb = remote.listkeys('bookmarks')
162 rb = remote.listkeys('bookmarks')
169 changed = False
163 changed = False
170 for k in rb.keys():
164 for k in rb.keys():
171 if k in repo._bookmarks:
165 if k in repo._bookmarks:
172 nr, nl = rb[k], repo._bookmarks[k]
166 nr, nl = rb[k], repo._bookmarks[k]
173 if nr in repo:
167 if nr in repo:
174 cr = repo[nr]
168 cr = repo[nr]
175 cl = repo[nl]
169 cl = repo[nl]
176 if cl.rev() >= cr.rev():
170 if cl.rev() >= cr.rev():
177 continue
171 continue
178 if cr in cl.descendants():
172 if cr in cl.descendants():
179 repo._bookmarks[k] = cr.node()
173 repo._bookmarks[k] = cr.node()
180 changed = True
174 changed = True
181 ui.status(_("updating bookmark %s\n") % k)
175 ui.status(_("updating bookmark %s\n") % k)
182 else:
176 else:
183 ui.warn(_("not updating divergent"
177 ui.warn(_("not updating divergent"
184 " bookmark %s\n") % k)
178 " bookmark %s\n") % k)
185 if changed:
179 if changed:
186 write(repo)
180 write(repo)
187
181
188 def diff(ui, repo, remote):
182 def diff(ui, repo, remote):
189 ui.status(_("searching for changed bookmarks\n"))
183 ui.status(_("searching for changed bookmarks\n"))
190
184
191 lmarks = repo.listkeys('bookmarks')
185 lmarks = repo.listkeys('bookmarks')
192 rmarks = remote.listkeys('bookmarks')
186 rmarks = remote.listkeys('bookmarks')
193
187
194 diff = sorted(set(rmarks) - set(lmarks))
188 diff = sorted(set(rmarks) - set(lmarks))
195 for k in diff:
189 for k in diff:
196 ui.write(" %-25s %s\n" % (k, rmarks[k][:12]))
190 ui.write(" %-25s %s\n" % (k, rmarks[k][:12]))
197
191
198 if len(diff) <= 0:
192 if len(diff) <= 0:
199 ui.status(_("no changed bookmarks found\n"))
193 ui.status(_("no changed bookmarks found\n"))
200 return 1
194 return 1
201 return 0
195 return 0
General Comments 0
You need to be logged in to leave comments. Login now