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