##// END OF EJS Templates
bookmarks: update and updatecurrentbookmark return status...
Kevin Bullock -
r15621:01368835 default
parent child Browse files
Show More
@@ -1,228 +1,229 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
10 from mercurial import encoding, error, util
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 error.RepoLookupError:
39 except error.RepoLookupError:
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 posixfile_nt, reading everything is cheap
61 # No readline() in posixfile_nt, 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 updatecurrentbookmark(repo, oldnode, curbranch):
129 def updatecurrentbookmark(repo, oldnode, curbranch):
130 try:
130 try:
131 update(repo, oldnode, repo.branchtags()[curbranch])
131 return update(repo, oldnode, repo.branchtags()[curbranch])
132 except KeyError:
132 except KeyError:
133 if curbranch == "default": # no default branch!
133 if curbranch == "default": # no default branch!
134 update(repo, oldnode, repo.lookup("tip"))
134 return update(repo, oldnode, repo.lookup("tip"))
135 else:
135 else:
136 raise util.Abort(_("branch %s not found") % curbranch)
136 raise util.Abort(_("branch %s not found") % curbranch)
137
137
138 def update(repo, parents, node):
138 def update(repo, parents, node):
139 marks = repo._bookmarks
139 marks = repo._bookmarks
140 update = False
140 update = False
141 mark = repo._bookmarkcurrent
141 mark = repo._bookmarkcurrent
142 if mark and marks[mark] in parents:
142 if mark and marks[mark] in parents:
143 old = repo[marks[mark]]
143 old = repo[marks[mark]]
144 new = repo[node]
144 new = repo[node]
145 if new in old.descendants():
145 if new in old.descendants():
146 marks[mark] = new.node()
146 marks[mark] = new.node()
147 update = True
147 update = True
148 if update:
148 if update:
149 repo._writebookmarks(marks)
149 repo._writebookmarks(marks)
150 return update
150
151
151 def listbookmarks(repo):
152 def listbookmarks(repo):
152 # We may try to list bookmarks on a repo type that does not
153 # We may try to list bookmarks on a repo type that does not
153 # support it (e.g., statichttprepository).
154 # support it (e.g., statichttprepository).
154 marks = getattr(repo, '_bookmarks', {})
155 marks = getattr(repo, '_bookmarks', {})
155
156
156 d = {}
157 d = {}
157 for k, v in marks.iteritems():
158 for k, v in marks.iteritems():
158 # don't expose local divergent bookmarks
159 # don't expose local divergent bookmarks
159 if '@' not in k and not k.endswith('@'):
160 if '@' not in k and not k.endswith('@'):
160 d[k] = hex(v)
161 d[k] = hex(v)
161 return d
162 return d
162
163
163 def pushbookmark(repo, key, old, new):
164 def pushbookmark(repo, key, old, new):
164 w = repo.wlock()
165 w = repo.wlock()
165 try:
166 try:
166 marks = repo._bookmarks
167 marks = repo._bookmarks
167 if hex(marks.get(key, '')) != old:
168 if hex(marks.get(key, '')) != old:
168 return False
169 return False
169 if new == '':
170 if new == '':
170 del marks[key]
171 del marks[key]
171 else:
172 else:
172 if new not in repo:
173 if new not in repo:
173 return False
174 return False
174 marks[key] = repo[new].node()
175 marks[key] = repo[new].node()
175 write(repo)
176 write(repo)
176 return True
177 return True
177 finally:
178 finally:
178 w.release()
179 w.release()
179
180
180 def updatefromremote(ui, repo, remote, path):
181 def updatefromremote(ui, repo, remote, path):
181 ui.debug("checking for updated bookmarks\n")
182 ui.debug("checking for updated bookmarks\n")
182 rb = remote.listkeys('bookmarks')
183 rb = remote.listkeys('bookmarks')
183 changed = False
184 changed = False
184 for k in rb.keys():
185 for k in rb.keys():
185 if k in repo._bookmarks:
186 if k in repo._bookmarks:
186 nr, nl = rb[k], repo._bookmarks[k]
187 nr, nl = rb[k], repo._bookmarks[k]
187 if nr in repo:
188 if nr in repo:
188 cr = repo[nr]
189 cr = repo[nr]
189 cl = repo[nl]
190 cl = repo[nl]
190 if cl.rev() >= cr.rev():
191 if cl.rev() >= cr.rev():
191 continue
192 continue
192 if cr in cl.descendants():
193 if cr in cl.descendants():
193 repo._bookmarks[k] = cr.node()
194 repo._bookmarks[k] = cr.node()
194 changed = True
195 changed = True
195 ui.status(_("updating bookmark %s\n") % k)
196 ui.status(_("updating bookmark %s\n") % k)
196 else:
197 else:
197 # find a unique @ suffix
198 # find a unique @ suffix
198 for x in range(1, 100):
199 for x in range(1, 100):
199 n = '%s@%d' % (k, x)
200 n = '%s@%d' % (k, x)
200 if n not in repo._bookmarks:
201 if n not in repo._bookmarks:
201 break
202 break
202 # try to use an @pathalias suffix
203 # try to use an @pathalias suffix
203 # if an @pathalias already exists, we overwrite (update) it
204 # if an @pathalias already exists, we overwrite (update) it
204 for p, u in ui.configitems("paths"):
205 for p, u in ui.configitems("paths"):
205 if path == u:
206 if path == u:
206 n = '%s@%s' % (k, p)
207 n = '%s@%s' % (k, p)
207
208
208 repo._bookmarks[n] = cr.node()
209 repo._bookmarks[n] = cr.node()
209 changed = True
210 changed = True
210 ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n))
211 ui.warn(_("divergent bookmark %s stored as %s\n") % (k, n))
211
212
212 if changed:
213 if changed:
213 write(repo)
214 write(repo)
214
215
215 def diff(ui, repo, remote):
216 def diff(ui, repo, remote):
216 ui.status(_("searching for changed bookmarks\n"))
217 ui.status(_("searching for changed bookmarks\n"))
217
218
218 lmarks = repo.listkeys('bookmarks')
219 lmarks = repo.listkeys('bookmarks')
219 rmarks = remote.listkeys('bookmarks')
220 rmarks = remote.listkeys('bookmarks')
220
221
221 diff = sorted(set(rmarks) - set(lmarks))
222 diff = sorted(set(rmarks) - set(lmarks))
222 for k in diff:
223 for k in diff:
223 ui.write(" %-25s %s\n" % (k, rmarks[k][:12]))
224 ui.write(" %-25s %s\n" % (k, rmarks[k][:12]))
224
225
225 if len(diff) <= 0:
226 if len(diff) <= 0:
226 ui.status(_("no changed bookmarks found\n"))
227 ui.status(_("no changed bookmarks found\n"))
227 return 1
228 return 1
228 return 0
229 return 0
General Comments 0
You need to be logged in to leave comments. Login now