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