##// END OF EJS Templates
bookmarks: Avoid long lines
Joel Rosdahl -
r7252:104a8324 default
parent child Browse files
Show More
@@ -1,220 +1,224
1 # Mercurial extension to provide the 'hg bookmark' command
1 # Mercurial extension to provide the 'hg bookmark' command
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
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7 '''mercurial bookmarks
8 '''mercurial bookmarks
8
9
9 Mercurial bookmarks are local moveable pointers to changesets. Every bookmark
10 Mercurial bookmarks are local moveable pointers to changesets. Every
10 points to a changeset identified by its hash. If you commit a changeset
11 bookmark points to a changeset identified by its hash. If you commit a
11 that is based on a changeset that has a bookmark on it, the bookmark is forwarded
12 changeset that is based on a changeset that has a bookmark on it, the
12 to the new changeset.
13 bookmark is forwarded to the new changeset.
13
14
14 It is possible to use bookmark names in every revision lookup (e.g. hg merge, hg update)
15 It is possible to use bookmark names in every revision lookup (e.g. hg
16 merge, hg update).
15 '''
17 '''
18
16 from mercurial.commands import templateopts, hex, short
19 from mercurial.commands import templateopts, hex, short
17 from mercurial.i18n import _
20 from mercurial.i18n import _
18 from mercurial import cmdutil, util, commands, changelog
21 from mercurial import cmdutil, util, commands, changelog
19 from mercurial.node import nullrev
22 from mercurial.node import nullrev
20 from mercurial.repo import RepoError
23 from mercurial.repo import RepoError
21 import mercurial, mercurial.localrepo, mercurial.repair, os
24 import mercurial, mercurial.localrepo, mercurial.repair, os
22
25
23
24 def parse(repo):
26 def parse(repo):
25 '''Parse .hg/bookmarks file and return a dictionary
27 '''Parse .hg/bookmarks file and return a dictionary
26
28
27 Bookmarks are stored as {HASH}\s{NAME}\n (localtags format)
29 Bookmarks are stored as {HASH}\s{NAME}\n (localtags format) values
28 values in the .hg/bookmarks file.
30 in the .hg/bookmarks file. They are read by the parse() method and
29 They are read by the parse() method and returned as a dictionary with
31 returned as a dictionary with name => hash values.
30 name => hash values.
31
32
32 The parsed dictionary is cached until a write() operation is done.
33 The parsed dictionary is cached until a write() operation is done.
33 '''
34 '''
34 try:
35 try:
35 if repo._bookmarks:
36 if repo._bookmarks:
36 return repo._bookmarks
37 return repo._bookmarks
37 repo._bookmarks = {}
38 repo._bookmarks = {}
38 for line in repo.opener('bookmarks'):
39 for line in repo.opener('bookmarks'):
39 sha, refspec = line.strip().split(' ', 1)
40 sha, refspec = line.strip().split(' ', 1)
40 repo._bookmarks[refspec] = repo.lookup(sha)
41 repo._bookmarks[refspec] = repo.lookup(sha)
41 except:
42 except:
42 pass
43 pass
43 return repo._bookmarks
44 return repo._bookmarks
44
45
45 def write(repo, refs):
46 def write(repo, refs):
46 '''Write bookmarks
47 '''Write bookmarks
47
48
48 Write the given bookmark => hash dictionary to the .hg/bookmarks file
49 Write the given bookmark => hash dictionary to the .hg/bookmarks file
49 in a format equal to those of localtags.
50 in a format equal to those of localtags.
50
51
51 We also store a backup of the previous state in undo.bookmarks that
52 We also store a backup of the previous state in undo.bookmarks that
52 can be copied back on rollback.
53 can be copied back on rollback.
53 '''
54 '''
54 util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks'))
55 util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks'))
55 file = repo.opener('bookmarks', 'w+')
56 file = repo.opener('bookmarks', 'w+')
56 for refspec, node in refs.items():
57 for refspec, node in refs.items():
57 file.write("%s %s\n" % (hex(node), refspec))
58 file.write("%s %s\n" % (hex(node), refspec))
58 file.close()
59 file.close()
59
60
60 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, move=None):
61 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, move=None):
61 '''mercurial bookmarks
62 '''mercurial bookmarks
62
63
63 Bookmarks are pointers to certain commits that move when commiting.
64 Bookmarks are pointers to certain commits that move when
64 Bookmarks are local. They can be renamed, copied and deleted.
65 commiting. Bookmarks are local. They can be renamed, copied and
65 It is possible to use bookmark names in 'hg merge' and 'hg update' to
66 deleted. It is possible to use bookmark names in 'hg merge' and 'hg
66 update to a given bookmark.
67 update' to update to a given bookmark.
67
68
68 You can use 'hg bookmark [NAME]' to set a bookmark on the current tip
69 You can use 'hg bookmark [NAME]' to set a bookmark on the current tip
69 with the given name. If you specify a second [NAME] the bookmark is
70 with the given name. If you specify a second [NAME] the bookmark is
70 set to the bookmark that has that name. You can also pass revision
71 set to the bookmark that has that name. You can also pass revision
71 identifiers to set bookmarks too.
72 identifiers to set bookmarks too.
72 '''
73 '''
73 hexfn = ui.debugflag and hex or short
74 hexfn = ui.debugflag and hex or short
74 marks = parse(repo)
75 marks = parse(repo)
75 cur = repo.changectx('.').node()
76 cur = repo.changectx('.').node()
76
77
77 if move:
78 if move:
78 if move not in marks:
79 if move not in marks:
79 raise util.Abort(_("a bookmark of this name does not exist"))
80 raise util.Abort(_("a bookmark of this name does not exist"))
80 if mark in marks and not force:
81 if mark in marks and not force:
81 raise util.Abort(_("a bookmark of the same name already exists"))
82 raise util.Abort(_("a bookmark of the same name already exists"))
82 marks[mark] = marks[move]
83 marks[mark] = marks[move]
83 del marks[move]
84 del marks[move]
84 write(repo, marks)
85 write(repo, marks)
85 return
86 return
86
87
87 if delete:
88 if delete:
88 if mark == None:
89 if mark == None:
89 raise util.Abort(_("bookmark name required"))
90 raise util.Abort(_("bookmark name required"))
90 if mark not in marks:
91 if mark not in marks:
91 raise util.Abort(_("a bookmark of this name does not exist"))
92 raise util.Abort(_("a bookmark of this name does not exist"))
92 del marks[mark]
93 del marks[mark]
93 write(repo, marks)
94 write(repo, marks)
94 return
95 return
95
96
96 if mark != None:
97 if mark != None:
97 if mark.strip().count("\n") > 0:
98 if mark.strip().count("\n") > 0:
98 raise Exception("bookmark cannot contain newlines")
99 raise Exception("bookmark cannot contain newlines")
99 if mark in marks and not force:
100 if mark in marks and not force:
100 raise util.Abort(_("a bookmark of the same name already exists"))
101 raise util.Abort(_("a bookmark of the same name already exists"))
101 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
102 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
102 and not force):
103 and not force):
103 raise util.Abort(_("a bookmark cannot have the name of an existing branch"))
104 raise util.Abort(
105 _("a bookmark cannot have the name of an existing branch"))
104 if rev:
106 if rev:
105 marks[mark] = repo.lookup(rev)
107 marks[mark] = repo.lookup(rev)
106 else:
108 else:
107 marks[mark] = repo.changectx('.').node()
109 marks[mark] = repo.changectx('.').node()
108 write(repo, marks)
110 write(repo, marks)
109 return
111 return
110
112
111 if mark == None:
113 if mark == None:
112 if len(marks) == 0:
114 if len(marks) == 0:
113 ui.status("no bookmarks set\n")
115 ui.status("no bookmarks set\n")
114 else:
116 else:
115 for bmark, n in marks.iteritems():
117 for bmark, n in marks.iteritems():
116 prefix = (n == cur) and '*' or ' '
118 prefix = (n == cur) and '*' or ' '
117 ui.write(" %s %-25s %d:%s\n" % (prefix, bmark, repo.changelog.rev(n), hexfn(n)))
119 ui.write(" %s %-25s %d:%s\n" % (
120 prefix, bmark, repo.changelog.rev(n), hexfn(n)))
118 return
121 return
119
122
120 def _revstostrip(changelog, node):
123 def _revstostrip(changelog, node):
121 srev = changelog.rev(node)
124 srev = changelog.rev(node)
122 tostrip = [srev]
125 tostrip = [srev]
123 saveheads = []
126 saveheads = []
124 for r in xrange(srev, changelog.rev(changelog.tip()) + 1):
127 for r in xrange(srev, changelog.rev(changelog.tip()) + 1):
125 parents = changelog.parentrevs(r)
128 parents = changelog.parentrevs(r)
126 if parents[0] in tostrip or parents[1] in tostrip:
129 if parents[0] in tostrip or parents[1] in tostrip:
127 tostrip.append(r)
130 tostrip.append(r)
128 if parents[1] != nullrev:
131 if parents[1] != nullrev:
129 for p in parents:
132 for p in parents:
130 if p not in tostrip and p > striprev:
133 if p not in tostrip and p > striprev:
131 saveheads.append(p)
134 saveheads.append(p)
132 return [r for r in tostrip if r not in saveheads]
135 return [r for r in tostrip if r not in saveheads]
133
136
134 def strip(ui, repo, node, backup="all"):
137 def strip(ui, repo, node, backup="all"):
135 """Strip bookmarks if revisions are stripped using
138 """Strip bookmarks if revisions are stripped using
136 the mercurial.strip method. This usually happens during
139 the mercurial.strip method. This usually happens during
137 qpush and qpop"""
140 qpush and qpop"""
138 revisions = _revstostrip(repo.changelog, node)
141 revisions = _revstostrip(repo.changelog, node)
139 marks = parse(repo)
142 marks = parse(repo)
140 update = []
143 update = []
141 for mark, n in marks.items():
144 for mark, n in marks.items():
142 if repo.changelog.rev(n) in revisions:
145 if repo.changelog.rev(n) in revisions:
143 update.append(mark)
146 update.append(mark)
144 result = oldstrip(ui, repo, node, backup)
147 result = oldstrip(ui, repo, node, backup)
145 if len(update) > 0:
148 if len(update) > 0:
146 for m in update:
149 for m in update:
147 marks[m] = repo.changectx('.').node()
150 marks[m] = repo.changectx('.').node()
148 write(repo, marks)
151 write(repo, marks)
149
152
150 oldstrip = mercurial.repair.strip
153 oldstrip = mercurial.repair.strip
151 mercurial.repair.strip = strip
154 mercurial.repair.strip = strip
152
155
153 def reposetup(ui, repo):
156 def reposetup(ui, repo):
154 if not isinstance(repo, mercurial.localrepo.localrepository):
157 if not isinstance(repo, mercurial.localrepo.localrepository):
155 return
158 return
156
159
157 # init a bookmark cache as otherwise we would get a infinite reading
160 # init a bookmark cache as otherwise we would get a infinite reading
158 # in lookup()
161 # in lookup()
159 repo._bookmarks = None
162 repo._bookmarks = None
160
163
161 class bookmark_repo(repo.__class__):
164 class bookmark_repo(repo.__class__):
162 def rollback(self):
165 def rollback(self):
163 if os.path.exists(self.join('undo.bookmarks')):
166 if os.path.exists(self.join('undo.bookmarks')):
164 util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
167 util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
165 return super(bookmark_repo, self).rollback()
168 return super(bookmark_repo, self).rollback()
166
169
167 def lookup(self, key):
170 def lookup(self, key):
168 if self._bookmarks is None:
171 if self._bookmarks is None:
169 self._bookmarks = parse(self)
172 self._bookmarks = parse(self)
170 if key in self._bookmarks:
173 if key in self._bookmarks:
171 key = self._bookmarks[key]
174 key = self._bookmarks[key]
172 return super(bookmark_repo, self).lookup(key)
175 return super(bookmark_repo, self).lookup(key)
173
176
174 def commit(self, *k, **kw):
177 def commit(self, *k, **kw):
175 """Add a revision to the repository and
178 """Add a revision to the repository and
176 move the bookmark"""
179 move the bookmark"""
177 node = super(bookmark_repo, self).commit(*k, **kw)
180 node = super(bookmark_repo, self).commit(*k, **kw)
178 parents = repo.changelog.parents(node)
181 parents = repo.changelog.parents(node)
179 marks = parse(repo)
182 marks = parse(repo)
180 update = False
183 update = False
181 for mark, n in marks.items():
184 for mark, n in marks.items():
182 if n in parents:
185 if n in parents:
183 marks[mark] = node
186 marks[mark] = node
184 update = True
187 update = True
185 if update:
188 if update:
186 write(repo, marks)
189 write(repo, marks)
187 return node
190 return node
188
191
189 def addchangegroup(self, source, srctype, url, emptyok=False):
192 def addchangegroup(self, source, srctype, url, emptyok=False):
190 try:
193 try:
191 onode = repo.changectx('.').node()
194 onode = repo.changectx('.').node()
192 except RepoError, inst:
195 except RepoError, inst:
193 pass
196 pass
194
197
195 result = super(bookmark_repo, self).addchangegroup(source, srctype, url, emptyok)
198 result = super(bookmark_repo, self).addchangegroup(
199 source, srctype, url, emptyok)
196 if result > 1:
200 if result > 1:
197 # We have more heads than before
201 # We have more heads than before
198 return result
202 return result
199 node = repo.changelog.tip()
203 node = repo.changelog.tip()
200 marks = parse(repo)
204 marks = parse(repo)
201 update = False
205 update = False
202 for mark, n in marks.items():
206 for mark, n in marks.items():
203 if n == onode:
207 if n == onode:
204 marks[mark] = node
208 marks[mark] = node
205 update = True
209 update = True
206 if update:
210 if update:
207 write(repo, marks)
211 write(repo, marks)
208 return result
212 return result
209
213
210 repo.__class__ = bookmark_repo
214 repo.__class__ = bookmark_repo
211
215
212 cmdtable = {
216 cmdtable = {
213 "bookmarks":
217 "bookmarks":
214 (bookmark,
218 (bookmark,
215 [('f', 'force', False, _('force')),
219 [('f', 'force', False, _('force')),
216 ('r', 'rev', '', _('revision')),
220 ('r', 'rev', '', _('revision')),
217 ('d', 'delete', False, _('delete a given bookmark')),
221 ('d', 'delete', False, _('delete a given bookmark')),
218 ('m', 'move', '', _('move a given bookmark'))],
222 ('m', 'move', '', _('move a given bookmark'))],
219 _('hg bookmarks [-d] [-m NAME] [-r NAME] [NAME]')),
223 _('hg bookmarks [-d] [-m NAME] [-r NAME] [NAME]')),
220 }
224 }
General Comments 0
You need to be logged in to leave comments. Login now