##// END OF EJS Templates
bookmarks: rename arguments/variables for source code readability...
FUJIWARA Katsunori -
r17667:2b6a795f default
parent child Browse files
Show More
@@ -1,284 +1,284 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
10 from mercurial import encoding, error, util, obsolete, phases
10 from mercurial import encoding, error, util, obsolete, phases
11 import errno, 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 bookmarks = {}
27 try:
27 try:
28 for line in repo.opener('bookmarks'):
28 for line in repo.opener('bookmarks'):
29 line = line.strip()
29 line = line.strip()
30 if not line:
30 if not line:
31 continue
31 continue
32 if ' ' not in line:
32 if ' ' not in line:
33 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n') % line)
33 repo.ui.warn(_('malformed line in .hg/bookmarks: %r\n') % line)
34 continue
34 continue
35 sha, refspec = line.split(' ', 1)
35 sha, refspec = line.split(' ', 1)
36 refspec = encoding.tolocal(refspec)
36 refspec = encoding.tolocal(refspec)
37 try:
37 try:
38 bookmarks[refspec] = repo.changelog.lookup(sha)
38 bookmarks[refspec] = repo.changelog.lookup(sha)
39 except LookupError:
39 except LookupError:
40 pass
40 pass
41 except IOError, inst:
41 except IOError, inst:
42 if inst.errno != errno.ENOENT:
42 if inst.errno != errno.ENOENT:
43 raise
43 raise
44 return bookmarks
44 return bookmarks
45
45
46 def readcurrent(repo):
46 def readcurrent(repo):
47 '''Get the current bookmark
47 '''Get the current bookmark
48
48
49 If we use gittishsh branches we have a current bookmark that
49 If we use gittishsh branches we have a current bookmark that
50 we are on. This function returns the name of the bookmark. It
50 we are on. This function returns the name of the bookmark. It
51 is stored in .hg/bookmarks.current
51 is stored in .hg/bookmarks.current
52 '''
52 '''
53 mark = None
53 mark = None
54 try:
54 try:
55 file = repo.opener('bookmarks.current')
55 file = repo.opener('bookmarks.current')
56 except IOError, inst:
56 except IOError, inst:
57 if inst.errno != errno.ENOENT:
57 if inst.errno != errno.ENOENT:
58 raise
58 raise
59 return None
59 return None
60 try:
60 try:
61 # No readline() in osutil.posixfile, reading everything is cheap
61 # No readline() in osutil.posixfile, reading everything is cheap
62 mark = encoding.tolocal((file.readlines() or [''])[0])
62 mark = encoding.tolocal((file.readlines() or [''])[0])
63 if mark == '' or mark not in repo._bookmarks:
63 if mark == '' or mark not in repo._bookmarks:
64 mark = None
64 mark = None
65 finally:
65 finally:
66 file.close()
66 file.close()
67 return mark
67 return mark
68
68
69 def write(repo):
69 def write(repo):
70 '''Write bookmarks
70 '''Write bookmarks
71
71
72 Write the given bookmark => hash dictionary to the .hg/bookmarks file
72 Write the given bookmark => hash dictionary to the .hg/bookmarks file
73 in a format equal to those of localtags.
73 in a format equal to those of localtags.
74
74
75 We also store a backup of the previous state in undo.bookmarks that
75 We also store a backup of the previous state in undo.bookmarks that
76 can be copied back on rollback.
76 can be copied back on rollback.
77 '''
77 '''
78 refs = repo._bookmarks
78 refs = repo._bookmarks
79
79
80 if repo._bookmarkcurrent not in refs:
80 if repo._bookmarkcurrent not in refs:
81 setcurrent(repo, None)
81 setcurrent(repo, None)
82 for mark in refs.keys():
82 for mark in refs.keys():
83 if not valid(mark):
83 if not valid(mark):
84 raise util.Abort(_("bookmark '%s' contains illegal "
84 raise util.Abort(_("bookmark '%s' contains illegal "
85 "character" % mark))
85 "character" % mark))
86
86
87 wlock = repo.wlock()
87 wlock = repo.wlock()
88 try:
88 try:
89
89
90 file = repo.opener('bookmarks', 'w', atomictemp=True)
90 file = repo.opener('bookmarks', 'w', atomictemp=True)
91 for refspec, node in refs.iteritems():
91 for refspec, node in refs.iteritems():
92 file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec)))
92 file.write("%s %s\n" % (hex(node), encoding.fromlocal(refspec)))
93 file.close()
93 file.close()
94
94
95 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
95 # touch 00changelog.i so hgweb reloads bookmarks (no lock needed)
96 try:
96 try:
97 os.utime(repo.sjoin('00changelog.i'), None)
97 os.utime(repo.sjoin('00changelog.i'), None)
98 except OSError:
98 except OSError:
99 pass
99 pass
100
100
101 finally:
101 finally:
102 wlock.release()
102 wlock.release()
103
103
104 def setcurrent(repo, mark):
104 def setcurrent(repo, mark):
105 '''Set the name of the bookmark that we are currently on
105 '''Set the name of the bookmark that we are currently on
106
106
107 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>).
108 The name is recorded in .hg/bookmarks.current
108 The name is recorded in .hg/bookmarks.current
109 '''
109 '''
110 current = repo._bookmarkcurrent
110 current = repo._bookmarkcurrent
111 if current == mark:
111 if current == mark:
112 return
112 return
113
113
114 if mark not in repo._bookmarks:
114 if mark not in repo._bookmarks:
115 mark = ''
115 mark = ''
116 if not valid(mark):
116 if not valid(mark):
117 raise util.Abort(_("bookmark '%s' contains illegal "
117 raise util.Abort(_("bookmark '%s' contains illegal "
118 "character" % mark))
118 "character" % mark))
119
119
120 wlock = repo.wlock()
120 wlock = repo.wlock()
121 try:
121 try:
122 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
122 file = repo.opener('bookmarks.current', 'w', atomictemp=True)
123 file.write(encoding.fromlocal(mark))
123 file.write(encoding.fromlocal(mark))
124 file.close()
124 file.close()
125 finally:
125 finally:
126 wlock.release()
126 wlock.release()
127 repo._bookmarkcurrent = mark
127 repo._bookmarkcurrent = mark
128
128
129 def unsetcurrent(repo):
129 def unsetcurrent(repo):
130 wlock = repo.wlock()
130 wlock = repo.wlock()
131 try:
131 try:
132 try:
132 try:
133 util.unlink(repo.join('bookmarks.current'))
133 util.unlink(repo.join('bookmarks.current'))
134 repo._bookmarkcurrent = None
134 repo._bookmarkcurrent = None
135 except OSError, inst:
135 except OSError, inst:
136 if inst.errno != errno.ENOENT:
136 if inst.errno != errno.ENOENT:
137 raise
137 raise
138 finally:
138 finally:
139 wlock.release()
139 wlock.release()
140
140
141 def updatecurrentbookmark(repo, oldnode, curbranch):
141 def updatecurrentbookmark(repo, oldnode, curbranch):
142 try:
142 try:
143 return update(repo, oldnode, repo.branchtip(curbranch))
143 return update(repo, oldnode, repo.branchtip(curbranch))
144 except error.RepoLookupError:
144 except error.RepoLookupError:
145 if curbranch == "default": # no default branch!
145 if curbranch == "default": # no default branch!
146 return update(repo, oldnode, repo.lookup("tip"))
146 return update(repo, oldnode, repo.lookup("tip"))
147 else:
147 else:
148 raise util.Abort(_("branch %s not found") % curbranch)
148 raise util.Abort(_("branch %s not found") % curbranch)
149
149
150 def update(repo, parents, node):
150 def update(repo, parents, node):
151 marks = repo._bookmarks
151 marks = repo._bookmarks
152 update = False
152 update = False
153 cur = repo._bookmarkcurrent
153 cur = repo._bookmarkcurrent
154 if not cur:
154 if not cur:
155 return False
155 return False
156
156
157 toupdate = [b for b in marks if b.split('@', 1)[0] == cur.split('@', 1)[0]]
157 toupdate = [b for b in marks if b.split('@', 1)[0] == cur.split('@', 1)[0]]
158 for mark in toupdate:
158 for mark in toupdate:
159 if mark and marks[mark] in parents:
159 if mark and marks[mark] in parents:
160 old = repo[marks[mark]]
160 old = repo[marks[mark]]
161 new = repo[node]
161 new = repo[node]
162 if old.descendant(new) and mark == cur:
162 if old.descendant(new) and mark == cur:
163 marks[cur] = new.node()
163 marks[cur] = new.node()
164 update = True
164 update = True
165 if mark != cur:
165 if mark != cur:
166 del marks[mark]
166 del marks[mark]
167 if update:
167 if update:
168 repo._writebookmarks(marks)
168 repo._writebookmarks(marks)
169 return update
169 return update
170
170
171 def listbookmarks(repo):
171 def listbookmarks(repo):
172 # We may try to list bookmarks on a repo type that does not
172 # We may try to list bookmarks on a repo type that does not
173 # support it (e.g., statichttprepository).
173 # support it (e.g., statichttprepository).
174 marks = getattr(repo, '_bookmarks', {})
174 marks = getattr(repo, '_bookmarks', {})
175
175
176 d = {}
176 d = {}
177 for k, v in marks.iteritems():
177 for k, v in marks.iteritems():
178 # don't expose local divergent bookmarks
178 # don't expose local divergent bookmarks
179 if '@' not in k or k.endswith('@'):
179 if '@' not in k or k.endswith('@'):
180 d[k] = hex(v)
180 d[k] = hex(v)
181 return d
181 return d
182
182
183 def pushbookmark(repo, key, old, new):
183 def pushbookmark(repo, key, old, new):
184 w = repo.wlock()
184 w = repo.wlock()
185 try:
185 try:
186 marks = repo._bookmarks
186 marks = repo._bookmarks
187 if hex(marks.get(key, '')) != old:
187 if hex(marks.get(key, '')) != old:
188 return False
188 return False
189 if new == '':
189 if new == '':
190 del marks[key]
190 del marks[key]
191 else:
191 else:
192 if new not in repo:
192 if new not in repo:
193 return False
193 return False
194 marks[key] = repo[new].node()
194 marks[key] = repo[new].node()
195 write(repo)
195 write(repo)
196 return True
196 return True
197 finally:
197 finally:
198 w.release()
198 w.release()
199
199
200 def updatefromremote(ui, repo, remote, path):
200 def updatefromremote(ui, repo, remote, path):
201 ui.debug("checking for updated bookmarks\n")
201 ui.debug("checking for updated bookmarks\n")
202 rb = remote.listkeys('bookmarks')
202 rb = remote.listkeys('bookmarks')
203 changed = False
203 changed = False
204 for k in rb.keys():
204 for k in rb.keys():
205 if k in repo._bookmarks:
205 if k in repo._bookmarks:
206 nr, nl = rb[k], repo._bookmarks[k]
206 nr, nl = rb[k], repo._bookmarks[k]
207 if nr in repo:
207 if nr in repo:
208 cr = repo[nr]
208 cr = repo[nr]
209 cl = repo[nl]
209 cl = repo[nl]
210 if cl.rev() >= cr.rev():
210 if cl.rev() >= cr.rev():
211 continue
211 continue
212 if validdest(repo, cl, cr):
212 if validdest(repo, cl, cr):
213 repo._bookmarks[k] = cr.node()
213 repo._bookmarks[k] = cr.node()
214 changed = True
214 changed = True
215 ui.status(_("updating bookmark %s\n") % k)
215 ui.status(_("updating bookmark %s\n") % k)
216 else:
216 else:
217 # find a unique @ suffix
217 # find a unique @ suffix
218 for x in range(1, 100):
218 for x in range(1, 100):
219 n = '%s@%d' % (k, x)
219 n = '%s@%d' % (k, x)
220 if n not in repo._bookmarks:
220 if n not in repo._bookmarks:
221 break
221 break
222 # try to use an @pathalias suffix
222 # try to use an @pathalias suffix
223 # if an @pathalias already exists, we overwrite (update) it
223 # if an @pathalias already exists, we overwrite (update) it
224 for p, u in ui.configitems("paths"):
224 for p, u in ui.configitems("paths"):
225 if path == u:
225 if path == u:
226 n = '%s@%s' % (k, p)
226 n = '%s@%s' % (k, p)
227
227
228 repo._bookmarks[n] = cr.node()
228 repo._bookmarks[n] = cr.node()
229 changed = True
229 changed = True
230 ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n))
230 ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n))
231 elif rb[k] in repo:
231 elif rb[k] in repo:
232 # add remote bookmarks for changes we already have
232 # add remote bookmarks for changes we already have
233 repo._bookmarks[k] = repo[rb[k]].node()
233 repo._bookmarks[k] = repo[rb[k]].node()
234 changed = True
234 changed = True
235 ui.status(_("adding remote bookmark %s\n") % k)
235 ui.status(_("adding remote bookmark %s\n") % k)
236
236
237 if changed:
237 if changed:
238 write(repo)
238 write(repo)
239
239
240 def diff(ui, repo, remote):
240 def diff(ui, dst, src):
241 ui.status(_("searching for changed bookmarks\n"))
241 ui.status(_("searching for changed bookmarks\n"))
242
242
243 lmarks = repo.listkeys('bookmarks')
243 smarks = src.listkeys('bookmarks')
244 rmarks = remote.listkeys('bookmarks')
244 dmarks = dst.listkeys('bookmarks')
245
245
246 diff = sorted(set(rmarks) - set(lmarks))
246 diff = sorted(set(smarks) - set(dmarks))
247 for k in diff:
247 for k in diff:
248 mark = ui.debugflag and rmarks[k] or rmarks[k][:12]
248 mark = ui.debugflag and smarks[k] or smarks[k][:12]
249 ui.write(" %-25s %s\n" % (k, mark))
249 ui.write(" %-25s %s\n" % (k, mark))
250
250
251 if len(diff) <= 0:
251 if len(diff) <= 0:
252 ui.status(_("no changed bookmarks found\n"))
252 ui.status(_("no changed bookmarks found\n"))
253 return 1
253 return 1
254 return 0
254 return 0
255
255
256 def validdest(repo, old, new):
256 def validdest(repo, old, new):
257 """Is the new bookmark destination a valid update from the old one"""
257 """Is the new bookmark destination a valid update from the old one"""
258 if old == new:
258 if old == new:
259 # Old == new -> nothing to update.
259 # Old == new -> nothing to update.
260 return False
260 return False
261 elif not old:
261 elif not old:
262 # old is nullrev, anything is valid.
262 # old is nullrev, anything is valid.
263 # (new != nullrev has been excluded by the previous check)
263 # (new != nullrev has been excluded by the previous check)
264 return True
264 return True
265 elif repo.obsstore:
265 elif repo.obsstore:
266 # We only need this complicated logic if there is obsolescence
266 # We only need this complicated logic if there is obsolescence
267 # XXX will probably deserve an optimised rset.
267 # XXX will probably deserve an optimised rset.
268
268
269 validdests = set([old])
269 validdests = set([old])
270 plen = -1
270 plen = -1
271 # compute the whole set of successors or descendants
271 # compute the whole set of successors or descendants
272 while len(validdests) != plen:
272 while len(validdests) != plen:
273 plen = len(validdests)
273 plen = len(validdests)
274 succs = set(c.node() for c in validdests)
274 succs = set(c.node() for c in validdests)
275 for c in validdests:
275 for c in validdests:
276 if c.phase() > phases.public:
276 if c.phase() > phases.public:
277 # obsolescence marker does not apply to public changeset
277 # obsolescence marker does not apply to public changeset
278 succs.update(obsolete.anysuccessors(repo.obsstore,
278 succs.update(obsolete.anysuccessors(repo.obsstore,
279 c.node()))
279 c.node()))
280 validdests = set(repo.set('%ln::', succs))
280 validdests = set(repo.set('%ln::', succs))
281 validdests.remove(old)
281 validdests.remove(old)
282 return new in validdests
282 return new in validdests
283 else:
283 else:
284 return old.descendant(new)
284 return old.descendant(new)
General Comments 0
You need to be logged in to leave comments. Login now