##// END OF EJS Templates
mq: remove unneeded local variable in delete
Martin Geisler -
r11216:1abd9442 default
parent child Browse files
Show More
@@ -1,2851 +1,2850
1 # mq.py - patch queues for mercurial
1 # mq.py - patch queues for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
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 '''manage a stack of patches
8 '''manage a stack of patches
9
9
10 This extension lets you work with a stack of patches in a Mercurial
10 This extension lets you work with a stack of patches in a Mercurial
11 repository. It manages two stacks of patches - all known patches, and
11 repository. It manages two stacks of patches - all known patches, and
12 applied patches (subset of known patches).
12 applied patches (subset of known patches).
13
13
14 Known patches are represented as patch files in the .hg/patches
14 Known patches are represented as patch files in the .hg/patches
15 directory. Applied patches are both patch files and changesets.
15 directory. Applied patches are both patch files and changesets.
16
16
17 Common tasks (use :hg:`help command` for more details)::
17 Common tasks (use :hg:`help command` for more details)::
18
18
19 create new patch qnew
19 create new patch qnew
20 import existing patch qimport
20 import existing patch qimport
21
21
22 print patch series qseries
22 print patch series qseries
23 print applied patches qapplied
23 print applied patches qapplied
24
24
25 add known patch to applied stack qpush
25 add known patch to applied stack qpush
26 remove patch from applied stack qpop
26 remove patch from applied stack qpop
27 refresh contents of top applied patch qrefresh
27 refresh contents of top applied patch qrefresh
28
28
29 By default, mq will automatically use git patches when required to
29 By default, mq will automatically use git patches when required to
30 avoid losing file mode changes, copy records, binary files or empty
30 avoid losing file mode changes, copy records, binary files or empty
31 files creations or deletions. This behaviour can be configured with::
31 files creations or deletions. This behaviour can be configured with::
32
32
33 [mq]
33 [mq]
34 git = auto/keep/yes/no
34 git = auto/keep/yes/no
35
35
36 If set to 'keep', mq will obey the [diff] section configuration while
36 If set to 'keep', mq will obey the [diff] section configuration while
37 preserving existing git patches upon qrefresh. If set to 'yes' or
37 preserving existing git patches upon qrefresh. If set to 'yes' or
38 'no', mq will override the [diff] section and always generate git or
38 'no', mq will override the [diff] section and always generate git or
39 regular patches, possibly losing data in the second case.
39 regular patches, possibly losing data in the second case.
40 '''
40 '''
41
41
42 from mercurial.i18n import _
42 from mercurial.i18n import _
43 from mercurial.node import bin, hex, short, nullid, nullrev
43 from mercurial.node import bin, hex, short, nullid, nullrev
44 from mercurial.lock import release
44 from mercurial.lock import release
45 from mercurial import commands, cmdutil, hg, patch, util
45 from mercurial import commands, cmdutil, hg, patch, util
46 from mercurial import repair, extensions, url, error
46 from mercurial import repair, extensions, url, error
47 import os, sys, re, errno
47 import os, sys, re, errno
48
48
49 commands.norepo += " qclone"
49 commands.norepo += " qclone"
50
50
51 # Patch names looks like unix-file names.
51 # Patch names looks like unix-file names.
52 # They must be joinable with queue directory and result in the patch path.
52 # They must be joinable with queue directory and result in the patch path.
53 normname = util.normpath
53 normname = util.normpath
54
54
55 class statusentry(object):
55 class statusentry(object):
56 def __init__(self, node, name):
56 def __init__(self, node, name):
57 self.node, self.name = node, name
57 self.node, self.name = node, name
58
58
59 def __str__(self):
59 def __str__(self):
60 return hex(self.node) + ':' + self.name
60 return hex(self.node) + ':' + self.name
61
61
62 class patchheader(object):
62 class patchheader(object):
63 def __init__(self, pf, plainmode=False):
63 def __init__(self, pf, plainmode=False):
64 def eatdiff(lines):
64 def eatdiff(lines):
65 while lines:
65 while lines:
66 l = lines[-1]
66 l = lines[-1]
67 if (l.startswith("diff -") or
67 if (l.startswith("diff -") or
68 l.startswith("Index:") or
68 l.startswith("Index:") or
69 l.startswith("===========")):
69 l.startswith("===========")):
70 del lines[-1]
70 del lines[-1]
71 else:
71 else:
72 break
72 break
73 def eatempty(lines):
73 def eatempty(lines):
74 while lines:
74 while lines:
75 if not lines[-1].strip():
75 if not lines[-1].strip():
76 del lines[-1]
76 del lines[-1]
77 else:
77 else:
78 break
78 break
79
79
80 message = []
80 message = []
81 comments = []
81 comments = []
82 user = None
82 user = None
83 date = None
83 date = None
84 parent = None
84 parent = None
85 format = None
85 format = None
86 subject = None
86 subject = None
87 diffstart = 0
87 diffstart = 0
88
88
89 for line in file(pf):
89 for line in file(pf):
90 line = line.rstrip()
90 line = line.rstrip()
91 if (line.startswith('diff --git')
91 if (line.startswith('diff --git')
92 or (diffstart and line.startswith('+++ '))):
92 or (diffstart and line.startswith('+++ '))):
93 diffstart = 2
93 diffstart = 2
94 break
94 break
95 diffstart = 0 # reset
95 diffstart = 0 # reset
96 if line.startswith("--- "):
96 if line.startswith("--- "):
97 diffstart = 1
97 diffstart = 1
98 continue
98 continue
99 elif format == "hgpatch":
99 elif format == "hgpatch":
100 # parse values when importing the result of an hg export
100 # parse values when importing the result of an hg export
101 if line.startswith("# User "):
101 if line.startswith("# User "):
102 user = line[7:]
102 user = line[7:]
103 elif line.startswith("# Date "):
103 elif line.startswith("# Date "):
104 date = line[7:]
104 date = line[7:]
105 elif line.startswith("# Parent "):
105 elif line.startswith("# Parent "):
106 parent = line[9:]
106 parent = line[9:]
107 elif not line.startswith("# ") and line:
107 elif not line.startswith("# ") and line:
108 message.append(line)
108 message.append(line)
109 format = None
109 format = None
110 elif line == '# HG changeset patch':
110 elif line == '# HG changeset patch':
111 message = []
111 message = []
112 format = "hgpatch"
112 format = "hgpatch"
113 elif (format != "tagdone" and (line.startswith("Subject: ") or
113 elif (format != "tagdone" and (line.startswith("Subject: ") or
114 line.startswith("subject: "))):
114 line.startswith("subject: "))):
115 subject = line[9:]
115 subject = line[9:]
116 format = "tag"
116 format = "tag"
117 elif (format != "tagdone" and (line.startswith("From: ") or
117 elif (format != "tagdone" and (line.startswith("From: ") or
118 line.startswith("from: "))):
118 line.startswith("from: "))):
119 user = line[6:]
119 user = line[6:]
120 format = "tag"
120 format = "tag"
121 elif (format != "tagdone" and (line.startswith("Date: ") or
121 elif (format != "tagdone" and (line.startswith("Date: ") or
122 line.startswith("date: "))):
122 line.startswith("date: "))):
123 date = line[6:]
123 date = line[6:]
124 format = "tag"
124 format = "tag"
125 elif format == "tag" and line == "":
125 elif format == "tag" and line == "":
126 # when looking for tags (subject: from: etc) they
126 # when looking for tags (subject: from: etc) they
127 # end once you find a blank line in the source
127 # end once you find a blank line in the source
128 format = "tagdone"
128 format = "tagdone"
129 elif message or line:
129 elif message or line:
130 message.append(line)
130 message.append(line)
131 comments.append(line)
131 comments.append(line)
132
132
133 eatdiff(message)
133 eatdiff(message)
134 eatdiff(comments)
134 eatdiff(comments)
135 eatempty(message)
135 eatempty(message)
136 eatempty(comments)
136 eatempty(comments)
137
137
138 # make sure message isn't empty
138 # make sure message isn't empty
139 if format and format.startswith("tag") and subject:
139 if format and format.startswith("tag") and subject:
140 message.insert(0, "")
140 message.insert(0, "")
141 message.insert(0, subject)
141 message.insert(0, subject)
142
142
143 self.message = message
143 self.message = message
144 self.comments = comments
144 self.comments = comments
145 self.user = user
145 self.user = user
146 self.date = date
146 self.date = date
147 self.parent = parent
147 self.parent = parent
148 self.haspatch = diffstart > 1
148 self.haspatch = diffstart > 1
149 self.plainmode = plainmode
149 self.plainmode = plainmode
150
150
151 def setuser(self, user):
151 def setuser(self, user):
152 if not self.updateheader(['From: ', '# User '], user):
152 if not self.updateheader(['From: ', '# User '], user):
153 try:
153 try:
154 patchheaderat = self.comments.index('# HG changeset patch')
154 patchheaderat = self.comments.index('# HG changeset patch')
155 self.comments.insert(patchheaderat + 1, '# User ' + user)
155 self.comments.insert(patchheaderat + 1, '# User ' + user)
156 except ValueError:
156 except ValueError:
157 if self.plainmode or self._hasheader(['Date: ']):
157 if self.plainmode or self._hasheader(['Date: ']):
158 self.comments = ['From: ' + user] + self.comments
158 self.comments = ['From: ' + user] + self.comments
159 else:
159 else:
160 tmp = ['# HG changeset patch', '# User ' + user, '']
160 tmp = ['# HG changeset patch', '# User ' + user, '']
161 self.comments = tmp + self.comments
161 self.comments = tmp + self.comments
162 self.user = user
162 self.user = user
163
163
164 def setdate(self, date):
164 def setdate(self, date):
165 if not self.updateheader(['Date: ', '# Date '], date):
165 if not self.updateheader(['Date: ', '# Date '], date):
166 try:
166 try:
167 patchheaderat = self.comments.index('# HG changeset patch')
167 patchheaderat = self.comments.index('# HG changeset patch')
168 self.comments.insert(patchheaderat + 1, '# Date ' + date)
168 self.comments.insert(patchheaderat + 1, '# Date ' + date)
169 except ValueError:
169 except ValueError:
170 if self.plainmode or self._hasheader(['From: ']):
170 if self.plainmode or self._hasheader(['From: ']):
171 self.comments = ['Date: ' + date] + self.comments
171 self.comments = ['Date: ' + date] + self.comments
172 else:
172 else:
173 tmp = ['# HG changeset patch', '# Date ' + date, '']
173 tmp = ['# HG changeset patch', '# Date ' + date, '']
174 self.comments = tmp + self.comments
174 self.comments = tmp + self.comments
175 self.date = date
175 self.date = date
176
176
177 def setparent(self, parent):
177 def setparent(self, parent):
178 if not self.updateheader(['# Parent '], parent):
178 if not self.updateheader(['# Parent '], parent):
179 try:
179 try:
180 patchheaderat = self.comments.index('# HG changeset patch')
180 patchheaderat = self.comments.index('# HG changeset patch')
181 self.comments.insert(patchheaderat + 1, '# Parent ' + parent)
181 self.comments.insert(patchheaderat + 1, '# Parent ' + parent)
182 except ValueError:
182 except ValueError:
183 pass
183 pass
184 self.parent = parent
184 self.parent = parent
185
185
186 def setmessage(self, message):
186 def setmessage(self, message):
187 if self.comments:
187 if self.comments:
188 self._delmsg()
188 self._delmsg()
189 self.message = [message]
189 self.message = [message]
190 self.comments += self.message
190 self.comments += self.message
191
191
192 def updateheader(self, prefixes, new):
192 def updateheader(self, prefixes, new):
193 '''Update all references to a field in the patch header.
193 '''Update all references to a field in the patch header.
194 Return whether the field is present.'''
194 Return whether the field is present.'''
195 res = False
195 res = False
196 for prefix in prefixes:
196 for prefix in prefixes:
197 for i in xrange(len(self.comments)):
197 for i in xrange(len(self.comments)):
198 if self.comments[i].startswith(prefix):
198 if self.comments[i].startswith(prefix):
199 self.comments[i] = prefix + new
199 self.comments[i] = prefix + new
200 res = True
200 res = True
201 break
201 break
202 return res
202 return res
203
203
204 def _hasheader(self, prefixes):
204 def _hasheader(self, prefixes):
205 '''Check if a header starts with any of the given prefixes.'''
205 '''Check if a header starts with any of the given prefixes.'''
206 for prefix in prefixes:
206 for prefix in prefixes:
207 for comment in self.comments:
207 for comment in self.comments:
208 if comment.startswith(prefix):
208 if comment.startswith(prefix):
209 return True
209 return True
210 return False
210 return False
211
211
212 def __str__(self):
212 def __str__(self):
213 if not self.comments:
213 if not self.comments:
214 return ''
214 return ''
215 return '\n'.join(self.comments) + '\n\n'
215 return '\n'.join(self.comments) + '\n\n'
216
216
217 def _delmsg(self):
217 def _delmsg(self):
218 '''Remove existing message, keeping the rest of the comments fields.
218 '''Remove existing message, keeping the rest of the comments fields.
219 If comments contains 'subject: ', message will prepend
219 If comments contains 'subject: ', message will prepend
220 the field and a blank line.'''
220 the field and a blank line.'''
221 if self.message:
221 if self.message:
222 subj = 'subject: ' + self.message[0].lower()
222 subj = 'subject: ' + self.message[0].lower()
223 for i in xrange(len(self.comments)):
223 for i in xrange(len(self.comments)):
224 if subj == self.comments[i].lower():
224 if subj == self.comments[i].lower():
225 del self.comments[i]
225 del self.comments[i]
226 self.message = self.message[2:]
226 self.message = self.message[2:]
227 break
227 break
228 ci = 0
228 ci = 0
229 for mi in self.message:
229 for mi in self.message:
230 while mi != self.comments[ci]:
230 while mi != self.comments[ci]:
231 ci += 1
231 ci += 1
232 del self.comments[ci]
232 del self.comments[ci]
233
233
234 class queue(object):
234 class queue(object):
235 def __init__(self, ui, path, patchdir=None):
235 def __init__(self, ui, path, patchdir=None):
236 self.basepath = path
236 self.basepath = path
237 self.path = patchdir or os.path.join(path, "patches")
237 self.path = patchdir or os.path.join(path, "patches")
238 self.opener = util.opener(self.path)
238 self.opener = util.opener(self.path)
239 self.ui = ui
239 self.ui = ui
240 self.applied_dirty = 0
240 self.applied_dirty = 0
241 self.series_dirty = 0
241 self.series_dirty = 0
242 self.series_path = "series"
242 self.series_path = "series"
243 self.status_path = "status"
243 self.status_path = "status"
244 self.guards_path = "guards"
244 self.guards_path = "guards"
245 self.active_guards = None
245 self.active_guards = None
246 self.guards_dirty = False
246 self.guards_dirty = False
247 # Handle mq.git as a bool with extended values
247 # Handle mq.git as a bool with extended values
248 try:
248 try:
249 gitmode = ui.configbool('mq', 'git', None)
249 gitmode = ui.configbool('mq', 'git', None)
250 if gitmode is None:
250 if gitmode is None:
251 raise error.ConfigError()
251 raise error.ConfigError()
252 self.gitmode = gitmode and 'yes' or 'no'
252 self.gitmode = gitmode and 'yes' or 'no'
253 except error.ConfigError:
253 except error.ConfigError:
254 self.gitmode = ui.config('mq', 'git', 'auto').lower()
254 self.gitmode = ui.config('mq', 'git', 'auto').lower()
255 self.plainmode = ui.configbool('mq', 'plain', False)
255 self.plainmode = ui.configbool('mq', 'plain', False)
256
256
257 @util.propertycache
257 @util.propertycache
258 def applied(self):
258 def applied(self):
259 if os.path.exists(self.join(self.status_path)):
259 if os.path.exists(self.join(self.status_path)):
260 def parse(l):
260 def parse(l):
261 n, name = l.split(':', 1)
261 n, name = l.split(':', 1)
262 return statusentry(bin(n), name)
262 return statusentry(bin(n), name)
263 lines = self.opener(self.status_path).read().splitlines()
263 lines = self.opener(self.status_path).read().splitlines()
264 return [parse(l) for l in lines]
264 return [parse(l) for l in lines]
265 return []
265 return []
266
266
267 @util.propertycache
267 @util.propertycache
268 def full_series(self):
268 def full_series(self):
269 if os.path.exists(self.join(self.series_path)):
269 if os.path.exists(self.join(self.series_path)):
270 return self.opener(self.series_path).read().splitlines()
270 return self.opener(self.series_path).read().splitlines()
271 return []
271 return []
272
272
273 @util.propertycache
273 @util.propertycache
274 def series(self):
274 def series(self):
275 self.parse_series()
275 self.parse_series()
276 return self.series
276 return self.series
277
277
278 @util.propertycache
278 @util.propertycache
279 def series_guards(self):
279 def series_guards(self):
280 self.parse_series()
280 self.parse_series()
281 return self.series_guards
281 return self.series_guards
282
282
283 def invalidate(self):
283 def invalidate(self):
284 for a in 'applied full_series series series_guards'.split():
284 for a in 'applied full_series series series_guards'.split():
285 if a in self.__dict__:
285 if a in self.__dict__:
286 delattr(self, a)
286 delattr(self, a)
287 self.applied_dirty = 0
287 self.applied_dirty = 0
288 self.series_dirty = 0
288 self.series_dirty = 0
289 self.guards_dirty = False
289 self.guards_dirty = False
290 self.active_guards = None
290 self.active_guards = None
291
291
292 def diffopts(self, opts={}, patchfn=None):
292 def diffopts(self, opts={}, patchfn=None):
293 diffopts = patch.diffopts(self.ui, opts)
293 diffopts = patch.diffopts(self.ui, opts)
294 if self.gitmode == 'auto':
294 if self.gitmode == 'auto':
295 diffopts.upgrade = True
295 diffopts.upgrade = True
296 elif self.gitmode == 'keep':
296 elif self.gitmode == 'keep':
297 pass
297 pass
298 elif self.gitmode in ('yes', 'no'):
298 elif self.gitmode in ('yes', 'no'):
299 diffopts.git = self.gitmode == 'yes'
299 diffopts.git = self.gitmode == 'yes'
300 else:
300 else:
301 raise util.Abort(_('mq.git option can be auto/keep/yes/no'
301 raise util.Abort(_('mq.git option can be auto/keep/yes/no'
302 ' got %s') % self.gitmode)
302 ' got %s') % self.gitmode)
303 if patchfn:
303 if patchfn:
304 diffopts = self.patchopts(diffopts, patchfn)
304 diffopts = self.patchopts(diffopts, patchfn)
305 return diffopts
305 return diffopts
306
306
307 def patchopts(self, diffopts, *patches):
307 def patchopts(self, diffopts, *patches):
308 """Return a copy of input diff options with git set to true if
308 """Return a copy of input diff options with git set to true if
309 referenced patch is a git patch and should be preserved as such.
309 referenced patch is a git patch and should be preserved as such.
310 """
310 """
311 diffopts = diffopts.copy()
311 diffopts = diffopts.copy()
312 if not diffopts.git and self.gitmode == 'keep':
312 if not diffopts.git and self.gitmode == 'keep':
313 for patchfn in patches:
313 for patchfn in patches:
314 patchf = self.opener(patchfn, 'r')
314 patchf = self.opener(patchfn, 'r')
315 # if the patch was a git patch, refresh it as a git patch
315 # if the patch was a git patch, refresh it as a git patch
316 for line in patchf:
316 for line in patchf:
317 if line.startswith('diff --git'):
317 if line.startswith('diff --git'):
318 diffopts.git = True
318 diffopts.git = True
319 break
319 break
320 patchf.close()
320 patchf.close()
321 return diffopts
321 return diffopts
322
322
323 def join(self, *p):
323 def join(self, *p):
324 return os.path.join(self.path, *p)
324 return os.path.join(self.path, *p)
325
325
326 def find_series(self, patch):
326 def find_series(self, patch):
327 def matchpatch(l):
327 def matchpatch(l):
328 l = l.split('#', 1)[0]
328 l = l.split('#', 1)[0]
329 return l.strip() == patch
329 return l.strip() == patch
330 for index, l in enumerate(self.full_series):
330 for index, l in enumerate(self.full_series):
331 if matchpatch(l):
331 if matchpatch(l):
332 return index
332 return index
333 return None
333 return None
334
334
335 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
335 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
336
336
337 def parse_series(self):
337 def parse_series(self):
338 self.series = []
338 self.series = []
339 self.series_guards = []
339 self.series_guards = []
340 for l in self.full_series:
340 for l in self.full_series:
341 h = l.find('#')
341 h = l.find('#')
342 if h == -1:
342 if h == -1:
343 patch = l
343 patch = l
344 comment = ''
344 comment = ''
345 elif h == 0:
345 elif h == 0:
346 continue
346 continue
347 else:
347 else:
348 patch = l[:h]
348 patch = l[:h]
349 comment = l[h:]
349 comment = l[h:]
350 patch = patch.strip()
350 patch = patch.strip()
351 if patch:
351 if patch:
352 if patch in self.series:
352 if patch in self.series:
353 raise util.Abort(_('%s appears more than once in %s') %
353 raise util.Abort(_('%s appears more than once in %s') %
354 (patch, self.join(self.series_path)))
354 (patch, self.join(self.series_path)))
355 self.series.append(patch)
355 self.series.append(patch)
356 self.series_guards.append(self.guard_re.findall(comment))
356 self.series_guards.append(self.guard_re.findall(comment))
357
357
358 def check_guard(self, guard):
358 def check_guard(self, guard):
359 if not guard:
359 if not guard:
360 return _('guard cannot be an empty string')
360 return _('guard cannot be an empty string')
361 bad_chars = '# \t\r\n\f'
361 bad_chars = '# \t\r\n\f'
362 first = guard[0]
362 first = guard[0]
363 if first in '-+':
363 if first in '-+':
364 return (_('guard %r starts with invalid character: %r') %
364 return (_('guard %r starts with invalid character: %r') %
365 (guard, first))
365 (guard, first))
366 for c in bad_chars:
366 for c in bad_chars:
367 if c in guard:
367 if c in guard:
368 return _('invalid character in guard %r: %r') % (guard, c)
368 return _('invalid character in guard %r: %r') % (guard, c)
369
369
370 def set_active(self, guards):
370 def set_active(self, guards):
371 for guard in guards:
371 for guard in guards:
372 bad = self.check_guard(guard)
372 bad = self.check_guard(guard)
373 if bad:
373 if bad:
374 raise util.Abort(bad)
374 raise util.Abort(bad)
375 guards = sorted(set(guards))
375 guards = sorted(set(guards))
376 self.ui.debug('active guards: %s\n' % ' '.join(guards))
376 self.ui.debug('active guards: %s\n' % ' '.join(guards))
377 self.active_guards = guards
377 self.active_guards = guards
378 self.guards_dirty = True
378 self.guards_dirty = True
379
379
380 def active(self):
380 def active(self):
381 if self.active_guards is None:
381 if self.active_guards is None:
382 self.active_guards = []
382 self.active_guards = []
383 try:
383 try:
384 guards = self.opener(self.guards_path).read().split()
384 guards = self.opener(self.guards_path).read().split()
385 except IOError, err:
385 except IOError, err:
386 if err.errno != errno.ENOENT:
386 if err.errno != errno.ENOENT:
387 raise
387 raise
388 guards = []
388 guards = []
389 for i, guard in enumerate(guards):
389 for i, guard in enumerate(guards):
390 bad = self.check_guard(guard)
390 bad = self.check_guard(guard)
391 if bad:
391 if bad:
392 self.ui.warn('%s:%d: %s\n' %
392 self.ui.warn('%s:%d: %s\n' %
393 (self.join(self.guards_path), i + 1, bad))
393 (self.join(self.guards_path), i + 1, bad))
394 else:
394 else:
395 self.active_guards.append(guard)
395 self.active_guards.append(guard)
396 return self.active_guards
396 return self.active_guards
397
397
398 def set_guards(self, idx, guards):
398 def set_guards(self, idx, guards):
399 for g in guards:
399 for g in guards:
400 if len(g) < 2:
400 if len(g) < 2:
401 raise util.Abort(_('guard %r too short') % g)
401 raise util.Abort(_('guard %r too short') % g)
402 if g[0] not in '-+':
402 if g[0] not in '-+':
403 raise util.Abort(_('guard %r starts with invalid char') % g)
403 raise util.Abort(_('guard %r starts with invalid char') % g)
404 bad = self.check_guard(g[1:])
404 bad = self.check_guard(g[1:])
405 if bad:
405 if bad:
406 raise util.Abort(bad)
406 raise util.Abort(bad)
407 drop = self.guard_re.sub('', self.full_series[idx])
407 drop = self.guard_re.sub('', self.full_series[idx])
408 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
408 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
409 self.parse_series()
409 self.parse_series()
410 self.series_dirty = True
410 self.series_dirty = True
411
411
412 def pushable(self, idx):
412 def pushable(self, idx):
413 if isinstance(idx, str):
413 if isinstance(idx, str):
414 idx = self.series.index(idx)
414 idx = self.series.index(idx)
415 patchguards = self.series_guards[idx]
415 patchguards = self.series_guards[idx]
416 if not patchguards:
416 if not patchguards:
417 return True, None
417 return True, None
418 guards = self.active()
418 guards = self.active()
419 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
419 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
420 if exactneg:
420 if exactneg:
421 return False, exactneg[0]
421 return False, exactneg[0]
422 pos = [g for g in patchguards if g[0] == '+']
422 pos = [g for g in patchguards if g[0] == '+']
423 exactpos = [g for g in pos if g[1:] in guards]
423 exactpos = [g for g in pos if g[1:] in guards]
424 if pos:
424 if pos:
425 if exactpos:
425 if exactpos:
426 return True, exactpos[0]
426 return True, exactpos[0]
427 return False, pos
427 return False, pos
428 return True, ''
428 return True, ''
429
429
430 def explain_pushable(self, idx, all_patches=False):
430 def explain_pushable(self, idx, all_patches=False):
431 write = all_patches and self.ui.write or self.ui.warn
431 write = all_patches and self.ui.write or self.ui.warn
432 if all_patches or self.ui.verbose:
432 if all_patches or self.ui.verbose:
433 if isinstance(idx, str):
433 if isinstance(idx, str):
434 idx = self.series.index(idx)
434 idx = self.series.index(idx)
435 pushable, why = self.pushable(idx)
435 pushable, why = self.pushable(idx)
436 if all_patches and pushable:
436 if all_patches and pushable:
437 if why is None:
437 if why is None:
438 write(_('allowing %s - no guards in effect\n') %
438 write(_('allowing %s - no guards in effect\n') %
439 self.series[idx])
439 self.series[idx])
440 else:
440 else:
441 if not why:
441 if not why:
442 write(_('allowing %s - no matching negative guards\n') %
442 write(_('allowing %s - no matching negative guards\n') %
443 self.series[idx])
443 self.series[idx])
444 else:
444 else:
445 write(_('allowing %s - guarded by %r\n') %
445 write(_('allowing %s - guarded by %r\n') %
446 (self.series[idx], why))
446 (self.series[idx], why))
447 if not pushable:
447 if not pushable:
448 if why:
448 if why:
449 write(_('skipping %s - guarded by %r\n') %
449 write(_('skipping %s - guarded by %r\n') %
450 (self.series[idx], why))
450 (self.series[idx], why))
451 else:
451 else:
452 write(_('skipping %s - no matching guards\n') %
452 write(_('skipping %s - no matching guards\n') %
453 self.series[idx])
453 self.series[idx])
454
454
455 def save_dirty(self):
455 def save_dirty(self):
456 def write_list(items, path):
456 def write_list(items, path):
457 fp = self.opener(path, 'w')
457 fp = self.opener(path, 'w')
458 for i in items:
458 for i in items:
459 fp.write("%s\n" % i)
459 fp.write("%s\n" % i)
460 fp.close()
460 fp.close()
461 if self.applied_dirty:
461 if self.applied_dirty:
462 write_list(map(str, self.applied), self.status_path)
462 write_list(map(str, self.applied), self.status_path)
463 if self.series_dirty:
463 if self.series_dirty:
464 write_list(self.full_series, self.series_path)
464 write_list(self.full_series, self.series_path)
465 if self.guards_dirty:
465 if self.guards_dirty:
466 write_list(self.active_guards, self.guards_path)
466 write_list(self.active_guards, self.guards_path)
467
467
468 def removeundo(self, repo):
468 def removeundo(self, repo):
469 undo = repo.sjoin('undo')
469 undo = repo.sjoin('undo')
470 if not os.path.exists(undo):
470 if not os.path.exists(undo):
471 return
471 return
472 try:
472 try:
473 os.unlink(undo)
473 os.unlink(undo)
474 except OSError, inst:
474 except OSError, inst:
475 self.ui.warn(_('error removing undo: %s\n') % str(inst))
475 self.ui.warn(_('error removing undo: %s\n') % str(inst))
476
476
477 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
477 def printdiff(self, repo, diffopts, node1, node2=None, files=None,
478 fp=None, changes=None, opts={}):
478 fp=None, changes=None, opts={}):
479 stat = opts.get('stat')
479 stat = opts.get('stat')
480 m = cmdutil.match(repo, files, opts)
480 m = cmdutil.match(repo, files, opts)
481 cmdutil.diffordiffstat(self.ui, repo, diffopts, node1, node2, m,
481 cmdutil.diffordiffstat(self.ui, repo, diffopts, node1, node2, m,
482 changes, stat, fp)
482 changes, stat, fp)
483
483
484 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
484 def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
485 # first try just applying the patch
485 # first try just applying the patch
486 (err, n) = self.apply(repo, [patch], update_status=False,
486 (err, n) = self.apply(repo, [patch], update_status=False,
487 strict=True, merge=rev)
487 strict=True, merge=rev)
488
488
489 if err == 0:
489 if err == 0:
490 return (err, n)
490 return (err, n)
491
491
492 if n is None:
492 if n is None:
493 raise util.Abort(_("apply failed for patch %s") % patch)
493 raise util.Abort(_("apply failed for patch %s") % patch)
494
494
495 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
495 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
496
496
497 # apply failed, strip away that rev and merge.
497 # apply failed, strip away that rev and merge.
498 hg.clean(repo, head)
498 hg.clean(repo, head)
499 self.strip(repo, n, update=False, backup='strip')
499 self.strip(repo, n, update=False, backup='strip')
500
500
501 ctx = repo[rev]
501 ctx = repo[rev]
502 ret = hg.merge(repo, rev)
502 ret = hg.merge(repo, rev)
503 if ret:
503 if ret:
504 raise util.Abort(_("update returned %d") % ret)
504 raise util.Abort(_("update returned %d") % ret)
505 n = repo.commit(ctx.description(), ctx.user(), force=True)
505 n = repo.commit(ctx.description(), ctx.user(), force=True)
506 if n is None:
506 if n is None:
507 raise util.Abort(_("repo commit failed"))
507 raise util.Abort(_("repo commit failed"))
508 try:
508 try:
509 ph = patchheader(mergeq.join(patch), self.plainmode)
509 ph = patchheader(mergeq.join(patch), self.plainmode)
510 except:
510 except:
511 raise util.Abort(_("unable to read %s") % patch)
511 raise util.Abort(_("unable to read %s") % patch)
512
512
513 diffopts = self.patchopts(diffopts, patch)
513 diffopts = self.patchopts(diffopts, patch)
514 patchf = self.opener(patch, "w")
514 patchf = self.opener(patch, "w")
515 comments = str(ph)
515 comments = str(ph)
516 if comments:
516 if comments:
517 patchf.write(comments)
517 patchf.write(comments)
518 self.printdiff(repo, diffopts, head, n, fp=patchf)
518 self.printdiff(repo, diffopts, head, n, fp=patchf)
519 patchf.close()
519 patchf.close()
520 self.removeundo(repo)
520 self.removeundo(repo)
521 return (0, n)
521 return (0, n)
522
522
523 def qparents(self, repo, rev=None):
523 def qparents(self, repo, rev=None):
524 if rev is None:
524 if rev is None:
525 (p1, p2) = repo.dirstate.parents()
525 (p1, p2) = repo.dirstate.parents()
526 if p2 == nullid:
526 if p2 == nullid:
527 return p1
527 return p1
528 if not self.applied:
528 if not self.applied:
529 return None
529 return None
530 return self.applied[-1].node
530 return self.applied[-1].node
531 p1, p2 = repo.changelog.parents(rev)
531 p1, p2 = repo.changelog.parents(rev)
532 if p2 != nullid and p2 in [x.node for x in self.applied]:
532 if p2 != nullid and p2 in [x.node for x in self.applied]:
533 return p2
533 return p2
534 return p1
534 return p1
535
535
536 def mergepatch(self, repo, mergeq, series, diffopts):
536 def mergepatch(self, repo, mergeq, series, diffopts):
537 if not self.applied:
537 if not self.applied:
538 # each of the patches merged in will have two parents. This
538 # each of the patches merged in will have two parents. This
539 # can confuse the qrefresh, qdiff, and strip code because it
539 # can confuse the qrefresh, qdiff, and strip code because it
540 # needs to know which parent is actually in the patch queue.
540 # needs to know which parent is actually in the patch queue.
541 # so, we insert a merge marker with only one parent. This way
541 # so, we insert a merge marker with only one parent. This way
542 # the first patch in the queue is never a merge patch
542 # the first patch in the queue is never a merge patch
543 #
543 #
544 pname = ".hg.patches.merge.marker"
544 pname = ".hg.patches.merge.marker"
545 n = repo.commit('[mq]: merge marker', force=True)
545 n = repo.commit('[mq]: merge marker', force=True)
546 self.removeundo(repo)
546 self.removeundo(repo)
547 self.applied.append(statusentry(n, pname))
547 self.applied.append(statusentry(n, pname))
548 self.applied_dirty = 1
548 self.applied_dirty = 1
549
549
550 head = self.qparents(repo)
550 head = self.qparents(repo)
551
551
552 for patch in series:
552 for patch in series:
553 patch = mergeq.lookup(patch, strict=True)
553 patch = mergeq.lookup(patch, strict=True)
554 if not patch:
554 if not patch:
555 self.ui.warn(_("patch %s does not exist\n") % patch)
555 self.ui.warn(_("patch %s does not exist\n") % patch)
556 return (1, None)
556 return (1, None)
557 pushable, reason = self.pushable(patch)
557 pushable, reason = self.pushable(patch)
558 if not pushable:
558 if not pushable:
559 self.explain_pushable(patch, all_patches=True)
559 self.explain_pushable(patch, all_patches=True)
560 continue
560 continue
561 info = mergeq.isapplied(patch)
561 info = mergeq.isapplied(patch)
562 if not info:
562 if not info:
563 self.ui.warn(_("patch %s is not applied\n") % patch)
563 self.ui.warn(_("patch %s is not applied\n") % patch)
564 return (1, None)
564 return (1, None)
565 rev = info[1]
565 rev = info[1]
566 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
566 err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts)
567 if head:
567 if head:
568 self.applied.append(statusentry(head, patch))
568 self.applied.append(statusentry(head, patch))
569 self.applied_dirty = 1
569 self.applied_dirty = 1
570 if err:
570 if err:
571 return (err, head)
571 return (err, head)
572 self.save_dirty()
572 self.save_dirty()
573 return (0, head)
573 return (0, head)
574
574
575 def patch(self, repo, patchfile):
575 def patch(self, repo, patchfile):
576 '''Apply patchfile to the working directory.
576 '''Apply patchfile to the working directory.
577 patchfile: name of patch file'''
577 patchfile: name of patch file'''
578 files = {}
578 files = {}
579 try:
579 try:
580 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
580 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
581 files=files, eolmode=None)
581 files=files, eolmode=None)
582 except Exception, inst:
582 except Exception, inst:
583 self.ui.note(str(inst) + '\n')
583 self.ui.note(str(inst) + '\n')
584 if not self.ui.verbose:
584 if not self.ui.verbose:
585 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
585 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
586 return (False, files, False)
586 return (False, files, False)
587
587
588 return (True, files, fuzz)
588 return (True, files, fuzz)
589
589
590 def apply(self, repo, series, list=False, update_status=True,
590 def apply(self, repo, series, list=False, update_status=True,
591 strict=False, patchdir=None, merge=None, all_files=None):
591 strict=False, patchdir=None, merge=None, all_files=None):
592 wlock = lock = tr = None
592 wlock = lock = tr = None
593 try:
593 try:
594 wlock = repo.wlock()
594 wlock = repo.wlock()
595 lock = repo.lock()
595 lock = repo.lock()
596 tr = repo.transaction("qpush")
596 tr = repo.transaction("qpush")
597 try:
597 try:
598 ret = self._apply(repo, series, list, update_status,
598 ret = self._apply(repo, series, list, update_status,
599 strict, patchdir, merge, all_files=all_files)
599 strict, patchdir, merge, all_files=all_files)
600 tr.close()
600 tr.close()
601 self.save_dirty()
601 self.save_dirty()
602 return ret
602 return ret
603 except:
603 except:
604 try:
604 try:
605 tr.abort()
605 tr.abort()
606 finally:
606 finally:
607 repo.invalidate()
607 repo.invalidate()
608 repo.dirstate.invalidate()
608 repo.dirstate.invalidate()
609 raise
609 raise
610 finally:
610 finally:
611 del tr
611 del tr
612 release(lock, wlock)
612 release(lock, wlock)
613 self.removeundo(repo)
613 self.removeundo(repo)
614
614
615 def _apply(self, repo, series, list=False, update_status=True,
615 def _apply(self, repo, series, list=False, update_status=True,
616 strict=False, patchdir=None, merge=None, all_files=None):
616 strict=False, patchdir=None, merge=None, all_files=None):
617 '''returns (error, hash)
617 '''returns (error, hash)
618 error = 1 for unable to read, 2 for patch failed, 3 for patch fuzz'''
618 error = 1 for unable to read, 2 for patch failed, 3 for patch fuzz'''
619 # TODO unify with commands.py
619 # TODO unify with commands.py
620 if not patchdir:
620 if not patchdir:
621 patchdir = self.path
621 patchdir = self.path
622 err = 0
622 err = 0
623 n = None
623 n = None
624 for patchname in series:
624 for patchname in series:
625 pushable, reason = self.pushable(patchname)
625 pushable, reason = self.pushable(patchname)
626 if not pushable:
626 if not pushable:
627 self.explain_pushable(patchname, all_patches=True)
627 self.explain_pushable(patchname, all_patches=True)
628 continue
628 continue
629 self.ui.status(_("applying %s\n") % patchname)
629 self.ui.status(_("applying %s\n") % patchname)
630 pf = os.path.join(patchdir, patchname)
630 pf = os.path.join(patchdir, patchname)
631
631
632 try:
632 try:
633 ph = patchheader(self.join(patchname), self.plainmode)
633 ph = patchheader(self.join(patchname), self.plainmode)
634 except:
634 except:
635 self.ui.warn(_("unable to read %s\n") % patchname)
635 self.ui.warn(_("unable to read %s\n") % patchname)
636 err = 1
636 err = 1
637 break
637 break
638
638
639 message = ph.message
639 message = ph.message
640 if not message:
640 if not message:
641 message = "imported patch %s\n" % patchname
641 message = "imported patch %s\n" % patchname
642 else:
642 else:
643 if list:
643 if list:
644 message.append("\nimported patch %s" % patchname)
644 message.append("\nimported patch %s" % patchname)
645 message = '\n'.join(message)
645 message = '\n'.join(message)
646
646
647 if ph.haspatch:
647 if ph.haspatch:
648 (patcherr, files, fuzz) = self.patch(repo, pf)
648 (patcherr, files, fuzz) = self.patch(repo, pf)
649 if all_files is not None:
649 if all_files is not None:
650 all_files.update(files)
650 all_files.update(files)
651 patcherr = not patcherr
651 patcherr = not patcherr
652 else:
652 else:
653 self.ui.warn(_("patch %s is empty\n") % patchname)
653 self.ui.warn(_("patch %s is empty\n") % patchname)
654 patcherr, files, fuzz = 0, [], 0
654 patcherr, files, fuzz = 0, [], 0
655
655
656 if merge and files:
656 if merge and files:
657 # Mark as removed/merged and update dirstate parent info
657 # Mark as removed/merged and update dirstate parent info
658 removed = []
658 removed = []
659 merged = []
659 merged = []
660 for f in files:
660 for f in files:
661 if os.path.exists(repo.wjoin(f)):
661 if os.path.exists(repo.wjoin(f)):
662 merged.append(f)
662 merged.append(f)
663 else:
663 else:
664 removed.append(f)
664 removed.append(f)
665 for f in removed:
665 for f in removed:
666 repo.dirstate.remove(f)
666 repo.dirstate.remove(f)
667 for f in merged:
667 for f in merged:
668 repo.dirstate.merge(f)
668 repo.dirstate.merge(f)
669 p1, p2 = repo.dirstate.parents()
669 p1, p2 = repo.dirstate.parents()
670 repo.dirstate.setparents(p1, merge)
670 repo.dirstate.setparents(p1, merge)
671
671
672 files = patch.updatedir(self.ui, repo, files)
672 files = patch.updatedir(self.ui, repo, files)
673 match = cmdutil.matchfiles(repo, files or [])
673 match = cmdutil.matchfiles(repo, files or [])
674 n = repo.commit(message, ph.user, ph.date, match=match, force=True)
674 n = repo.commit(message, ph.user, ph.date, match=match, force=True)
675
675
676 if n is None:
676 if n is None:
677 raise util.Abort(_("repo commit failed"))
677 raise util.Abort(_("repo commit failed"))
678
678
679 if update_status:
679 if update_status:
680 self.applied.append(statusentry(n, patchname))
680 self.applied.append(statusentry(n, patchname))
681
681
682 if patcherr:
682 if patcherr:
683 self.ui.warn(_("patch failed, rejects left in working dir\n"))
683 self.ui.warn(_("patch failed, rejects left in working dir\n"))
684 err = 2
684 err = 2
685 break
685 break
686
686
687 if fuzz and strict:
687 if fuzz and strict:
688 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
688 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
689 err = 3
689 err = 3
690 break
690 break
691 return (err, n)
691 return (err, n)
692
692
693 def _cleanup(self, patches, numrevs, keep=False):
693 def _cleanup(self, patches, numrevs, keep=False):
694 if not keep:
694 if not keep:
695 r = self.qrepo()
695 r = self.qrepo()
696 if r:
696 if r:
697 r.remove(patches, True)
697 r.remove(patches, True)
698 else:
698 else:
699 for p in patches:
699 for p in patches:
700 os.unlink(self.join(p))
700 os.unlink(self.join(p))
701
701
702 if numrevs:
702 if numrevs:
703 del self.applied[:numrevs]
703 del self.applied[:numrevs]
704 self.applied_dirty = 1
704 self.applied_dirty = 1
705
705
706 for i in sorted([self.find_series(p) for p in patches], reverse=True):
706 for i in sorted([self.find_series(p) for p in patches], reverse=True):
707 del self.full_series[i]
707 del self.full_series[i]
708 self.parse_series()
708 self.parse_series()
709 self.series_dirty = 1
709 self.series_dirty = 1
710
710
711 def _revpatches(self, repo, revs):
711 def _revpatches(self, repo, revs):
712 firstrev = repo[self.applied[0].node].rev()
712 firstrev = repo[self.applied[0].node].rev()
713 patches = []
713 patches = []
714 for i, rev in enumerate(revs):
714 for i, rev in enumerate(revs):
715
715
716 if rev < firstrev:
716 if rev < firstrev:
717 raise util.Abort(_('revision %d is not managed') % rev)
717 raise util.Abort(_('revision %d is not managed') % rev)
718
718
719 ctx = repo[rev]
719 ctx = repo[rev]
720 base = self.applied[i].node
720 base = self.applied[i].node
721 if ctx.node() != base:
721 if ctx.node() != base:
722 msg = _('cannot delete revision %d above applied patches')
722 msg = _('cannot delete revision %d above applied patches')
723 raise util.Abort(msg % rev)
723 raise util.Abort(msg % rev)
724
724
725 patch = self.applied[i].name
725 patch = self.applied[i].name
726 for fmt in ('[mq]: %s', 'imported patch %s'):
726 for fmt in ('[mq]: %s', 'imported patch %s'):
727 if ctx.description() == fmt % patch:
727 if ctx.description() == fmt % patch:
728 msg = _('patch %s finalized without changeset message\n')
728 msg = _('patch %s finalized without changeset message\n')
729 repo.ui.status(msg % patch)
729 repo.ui.status(msg % patch)
730 break
730 break
731
731
732 patches.append(patch)
732 patches.append(patch)
733 return patches
733 return patches
734
734
735 def finish(self, repo, revs):
735 def finish(self, repo, revs):
736 patches = self._revpatches(repo, sorted(revs))
736 patches = self._revpatches(repo, sorted(revs))
737 self._cleanup(patches, len(patches))
737 self._cleanup(patches, len(patches))
738
738
739 def delete(self, repo, patches, opts):
739 def delete(self, repo, patches, opts):
740 if not patches and not opts.get('rev'):
740 if not patches and not opts.get('rev'):
741 raise util.Abort(_('qdelete requires at least one revision or '
741 raise util.Abort(_('qdelete requires at least one revision or '
742 'patch name'))
742 'patch name'))
743
743
744 realpatches = []
745 for patch in patches:
744 for patch in patches:
746 patch = self.lookup(patch, strict=True)
745 patch = self.lookup(patch, strict=True)
747 info = self.isapplied(patch)
746 info = self.isapplied(patch)
748 if info:
747 if info:
749 raise util.Abort(_("cannot delete applied patch %s") % patch)
748 raise util.Abort(_("cannot delete applied patch %s") % patch)
750 if patch not in self.series:
749 if patch not in self.series:
751 raise util.Abort(_("patch %s not in series file") % patch)
750 raise util.Abort(_("patch %s not in series file") % patch)
752 realpatches.append(patch)
753
751
752 patches = list(patches)
754 numrevs = 0
753 numrevs = 0
755 if opts.get('rev'):
754 if opts.get('rev'):
756 if not self.applied:
755 if not self.applied:
757 raise util.Abort(_('no patches applied'))
756 raise util.Abort(_('no patches applied'))
758 revs = cmdutil.revrange(repo, opts['rev'])
757 revs = cmdutil.revrange(repo, opts['rev'])
759 if len(revs) > 1 and revs[0] > revs[1]:
758 if len(revs) > 1 and revs[0] > revs[1]:
760 revs.reverse()
759 revs.reverse()
761 revpatches = self._revpatches(repo, revs)
760 revpatches = self._revpatches(repo, revs)
762 realpatches += revpatches
761 patches += revpatches
763 numrevs = len(revpatches)
762 numrevs = len(revpatches)
764
763
765 self._cleanup(realpatches, numrevs, opts.get('keep'))
764 self._cleanup(patches, numrevs, opts.get('keep'))
766
765
767 def check_toppatch(self, repo):
766 def check_toppatch(self, repo):
768 if self.applied:
767 if self.applied:
769 top = self.applied[-1].node
768 top = self.applied[-1].node
770 patch = self.applied[-1].name
769 patch = self.applied[-1].name
771 pp = repo.dirstate.parents()
770 pp = repo.dirstate.parents()
772 if top not in pp:
771 if top not in pp:
773 raise util.Abort(_("working directory revision is not qtip"))
772 raise util.Abort(_("working directory revision is not qtip"))
774 return top, patch
773 return top, patch
775 return None, None
774 return None, None
776
775
777 def check_localchanges(self, repo, force=False, refresh=True):
776 def check_localchanges(self, repo, force=False, refresh=True):
778 m, a, r, d = repo.status()[:4]
777 m, a, r, d = repo.status()[:4]
779 if (m or a or r or d) and not force:
778 if (m or a or r or d) and not force:
780 if refresh:
779 if refresh:
781 raise util.Abort(_("local changes found, refresh first"))
780 raise util.Abort(_("local changes found, refresh first"))
782 else:
781 else:
783 raise util.Abort(_("local changes found"))
782 raise util.Abort(_("local changes found"))
784 return m, a, r, d
783 return m, a, r, d
785
784
786 _reserved = ('series', 'status', 'guards')
785 _reserved = ('series', 'status', 'guards')
787 def check_reserved_name(self, name):
786 def check_reserved_name(self, name):
788 if (name in self._reserved or name.startswith('.hg')
787 if (name in self._reserved or name.startswith('.hg')
789 or name.startswith('.mq') or '#' in name or ':' in name):
788 or name.startswith('.mq') or '#' in name or ':' in name):
790 raise util.Abort(_('"%s" cannot be used as the name of a patch')
789 raise util.Abort(_('"%s" cannot be used as the name of a patch')
791 % name)
790 % name)
792
791
793 def new(self, repo, patchfn, *pats, **opts):
792 def new(self, repo, patchfn, *pats, **opts):
794 """options:
793 """options:
795 msg: a string or a no-argument function returning a string
794 msg: a string or a no-argument function returning a string
796 """
795 """
797 msg = opts.get('msg')
796 msg = opts.get('msg')
798 user = opts.get('user')
797 user = opts.get('user')
799 date = opts.get('date')
798 date = opts.get('date')
800 if date:
799 if date:
801 date = util.parsedate(date)
800 date = util.parsedate(date)
802 diffopts = self.diffopts({'git': opts.get('git')})
801 diffopts = self.diffopts({'git': opts.get('git')})
803 self.check_reserved_name(patchfn)
802 self.check_reserved_name(patchfn)
804 if os.path.exists(self.join(patchfn)):
803 if os.path.exists(self.join(patchfn)):
805 raise util.Abort(_('patch "%s" already exists') % patchfn)
804 raise util.Abort(_('patch "%s" already exists') % patchfn)
806 if opts.get('include') or opts.get('exclude') or pats:
805 if opts.get('include') or opts.get('exclude') or pats:
807 match = cmdutil.match(repo, pats, opts)
806 match = cmdutil.match(repo, pats, opts)
808 # detect missing files in pats
807 # detect missing files in pats
809 def badfn(f, msg):
808 def badfn(f, msg):
810 raise util.Abort('%s: %s' % (f, msg))
809 raise util.Abort('%s: %s' % (f, msg))
811 match.bad = badfn
810 match.bad = badfn
812 m, a, r, d = repo.status(match=match)[:4]
811 m, a, r, d = repo.status(match=match)[:4]
813 else:
812 else:
814 m, a, r, d = self.check_localchanges(repo, force=True)
813 m, a, r, d = self.check_localchanges(repo, force=True)
815 match = cmdutil.matchfiles(repo, m + a + r)
814 match = cmdutil.matchfiles(repo, m + a + r)
816 if len(repo[None].parents()) > 1:
815 if len(repo[None].parents()) > 1:
817 raise util.Abort(_('cannot manage merge changesets'))
816 raise util.Abort(_('cannot manage merge changesets'))
818 commitfiles = m + a + r
817 commitfiles = m + a + r
819 self.check_toppatch(repo)
818 self.check_toppatch(repo)
820 insert = self.full_series_end()
819 insert = self.full_series_end()
821 wlock = repo.wlock()
820 wlock = repo.wlock()
822 try:
821 try:
823 # if patch file write fails, abort early
822 # if patch file write fails, abort early
824 p = self.opener(patchfn, "w")
823 p = self.opener(patchfn, "w")
825 try:
824 try:
826 if self.plainmode:
825 if self.plainmode:
827 if user:
826 if user:
828 p.write("From: " + user + "\n")
827 p.write("From: " + user + "\n")
829 if not date:
828 if not date:
830 p.write("\n")
829 p.write("\n")
831 if date:
830 if date:
832 p.write("Date: %d %d\n\n" % date)
831 p.write("Date: %d %d\n\n" % date)
833 else:
832 else:
834 p.write("# HG changeset patch\n")
833 p.write("# HG changeset patch\n")
835 p.write("# Parent "
834 p.write("# Parent "
836 + hex(repo[None].parents()[0].node()) + "\n")
835 + hex(repo[None].parents()[0].node()) + "\n")
837 if user:
836 if user:
838 p.write("# User " + user + "\n")
837 p.write("# User " + user + "\n")
839 if date:
838 if date:
840 p.write("# Date %s %s\n\n" % date)
839 p.write("# Date %s %s\n\n" % date)
841 if hasattr(msg, '__call__'):
840 if hasattr(msg, '__call__'):
842 msg = msg()
841 msg = msg()
843 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
842 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
844 n = repo.commit(commitmsg, user, date, match=match, force=True)
843 n = repo.commit(commitmsg, user, date, match=match, force=True)
845 if n is None:
844 if n is None:
846 raise util.Abort(_("repo commit failed"))
845 raise util.Abort(_("repo commit failed"))
847 try:
846 try:
848 self.full_series[insert:insert] = [patchfn]
847 self.full_series[insert:insert] = [patchfn]
849 self.applied.append(statusentry(n, patchfn))
848 self.applied.append(statusentry(n, patchfn))
850 self.parse_series()
849 self.parse_series()
851 self.series_dirty = 1
850 self.series_dirty = 1
852 self.applied_dirty = 1
851 self.applied_dirty = 1
853 if msg:
852 if msg:
854 msg = msg + "\n\n"
853 msg = msg + "\n\n"
855 p.write(msg)
854 p.write(msg)
856 if commitfiles:
855 if commitfiles:
857 parent = self.qparents(repo, n)
856 parent = self.qparents(repo, n)
858 chunks = patch.diff(repo, node1=parent, node2=n,
857 chunks = patch.diff(repo, node1=parent, node2=n,
859 match=match, opts=diffopts)
858 match=match, opts=diffopts)
860 for chunk in chunks:
859 for chunk in chunks:
861 p.write(chunk)
860 p.write(chunk)
862 p.close()
861 p.close()
863 wlock.release()
862 wlock.release()
864 wlock = None
863 wlock = None
865 r = self.qrepo()
864 r = self.qrepo()
866 if r:
865 if r:
867 r.add([patchfn])
866 r.add([patchfn])
868 except:
867 except:
869 repo.rollback()
868 repo.rollback()
870 raise
869 raise
871 except Exception:
870 except Exception:
872 patchpath = self.join(patchfn)
871 patchpath = self.join(patchfn)
873 try:
872 try:
874 os.unlink(patchpath)
873 os.unlink(patchpath)
875 except:
874 except:
876 self.ui.warn(_('error unlinking %s\n') % patchpath)
875 self.ui.warn(_('error unlinking %s\n') % patchpath)
877 raise
876 raise
878 self.removeundo(repo)
877 self.removeundo(repo)
879 finally:
878 finally:
880 release(wlock)
879 release(wlock)
881
880
882 def strip(self, repo, rev, update=True, backup="all", force=None):
881 def strip(self, repo, rev, update=True, backup="all", force=None):
883 wlock = lock = None
882 wlock = lock = None
884 try:
883 try:
885 wlock = repo.wlock()
884 wlock = repo.wlock()
886 lock = repo.lock()
885 lock = repo.lock()
887
886
888 if update:
887 if update:
889 self.check_localchanges(repo, force=force, refresh=False)
888 self.check_localchanges(repo, force=force, refresh=False)
890 urev = self.qparents(repo, rev)
889 urev = self.qparents(repo, rev)
891 hg.clean(repo, urev)
890 hg.clean(repo, urev)
892 repo.dirstate.write()
891 repo.dirstate.write()
893
892
894 self.removeundo(repo)
893 self.removeundo(repo)
895 repair.strip(self.ui, repo, rev, backup)
894 repair.strip(self.ui, repo, rev, backup)
896 # strip may have unbundled a set of backed up revisions after
895 # strip may have unbundled a set of backed up revisions after
897 # the actual strip
896 # the actual strip
898 self.removeundo(repo)
897 self.removeundo(repo)
899 finally:
898 finally:
900 release(lock, wlock)
899 release(lock, wlock)
901
900
902 def isapplied(self, patch):
901 def isapplied(self, patch):
903 """returns (index, rev, patch)"""
902 """returns (index, rev, patch)"""
904 for i, a in enumerate(self.applied):
903 for i, a in enumerate(self.applied):
905 if a.name == patch:
904 if a.name == patch:
906 return (i, a.node, a.name)
905 return (i, a.node, a.name)
907 return None
906 return None
908
907
909 # if the exact patch name does not exist, we try a few
908 # if the exact patch name does not exist, we try a few
910 # variations. If strict is passed, we try only #1
909 # variations. If strict is passed, we try only #1
911 #
910 #
912 # 1) a number to indicate an offset in the series file
911 # 1) a number to indicate an offset in the series file
913 # 2) a unique substring of the patch name was given
912 # 2) a unique substring of the patch name was given
914 # 3) patchname[-+]num to indicate an offset in the series file
913 # 3) patchname[-+]num to indicate an offset in the series file
915 def lookup(self, patch, strict=False):
914 def lookup(self, patch, strict=False):
916 patch = patch and str(patch)
915 patch = patch and str(patch)
917
916
918 def partial_name(s):
917 def partial_name(s):
919 if s in self.series:
918 if s in self.series:
920 return s
919 return s
921 matches = [x for x in self.series if s in x]
920 matches = [x for x in self.series if s in x]
922 if len(matches) > 1:
921 if len(matches) > 1:
923 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
922 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
924 for m in matches:
923 for m in matches:
925 self.ui.warn(' %s\n' % m)
924 self.ui.warn(' %s\n' % m)
926 return None
925 return None
927 if matches:
926 if matches:
928 return matches[0]
927 return matches[0]
929 if self.series and self.applied:
928 if self.series and self.applied:
930 if s == 'qtip':
929 if s == 'qtip':
931 return self.series[self.series_end(True)-1]
930 return self.series[self.series_end(True)-1]
932 if s == 'qbase':
931 if s == 'qbase':
933 return self.series[0]
932 return self.series[0]
934 return None
933 return None
935
934
936 if patch is None:
935 if patch is None:
937 return None
936 return None
938 if patch in self.series:
937 if patch in self.series:
939 return patch
938 return patch
940
939
941 if not os.path.isfile(self.join(patch)):
940 if not os.path.isfile(self.join(patch)):
942 try:
941 try:
943 sno = int(patch)
942 sno = int(patch)
944 except (ValueError, OverflowError):
943 except (ValueError, OverflowError):
945 pass
944 pass
946 else:
945 else:
947 if -len(self.series) <= sno < len(self.series):
946 if -len(self.series) <= sno < len(self.series):
948 return self.series[sno]
947 return self.series[sno]
949
948
950 if not strict:
949 if not strict:
951 res = partial_name(patch)
950 res = partial_name(patch)
952 if res:
951 if res:
953 return res
952 return res
954 minus = patch.rfind('-')
953 minus = patch.rfind('-')
955 if minus >= 0:
954 if minus >= 0:
956 res = partial_name(patch[:minus])
955 res = partial_name(patch[:minus])
957 if res:
956 if res:
958 i = self.series.index(res)
957 i = self.series.index(res)
959 try:
958 try:
960 off = int(patch[minus + 1:] or 1)
959 off = int(patch[minus + 1:] or 1)
961 except (ValueError, OverflowError):
960 except (ValueError, OverflowError):
962 pass
961 pass
963 else:
962 else:
964 if i - off >= 0:
963 if i - off >= 0:
965 return self.series[i - off]
964 return self.series[i - off]
966 plus = patch.rfind('+')
965 plus = patch.rfind('+')
967 if plus >= 0:
966 if plus >= 0:
968 res = partial_name(patch[:plus])
967 res = partial_name(patch[:plus])
969 if res:
968 if res:
970 i = self.series.index(res)
969 i = self.series.index(res)
971 try:
970 try:
972 off = int(patch[plus + 1:] or 1)
971 off = int(patch[plus + 1:] or 1)
973 except (ValueError, OverflowError):
972 except (ValueError, OverflowError):
974 pass
973 pass
975 else:
974 else:
976 if i + off < len(self.series):
975 if i + off < len(self.series):
977 return self.series[i + off]
976 return self.series[i + off]
978 raise util.Abort(_("patch %s not in series") % patch)
977 raise util.Abort(_("patch %s not in series") % patch)
979
978
980 def push(self, repo, patch=None, force=False, list=False,
979 def push(self, repo, patch=None, force=False, list=False,
981 mergeq=None, all=False, move=False):
980 mergeq=None, all=False, move=False):
982 diffopts = self.diffopts()
981 diffopts = self.diffopts()
983 wlock = repo.wlock()
982 wlock = repo.wlock()
984 try:
983 try:
985 heads = []
984 heads = []
986 for b, ls in repo.branchmap().iteritems():
985 for b, ls in repo.branchmap().iteritems():
987 heads += ls
986 heads += ls
988 if not heads:
987 if not heads:
989 heads = [nullid]
988 heads = [nullid]
990 if repo.dirstate.parents()[0] not in heads:
989 if repo.dirstate.parents()[0] not in heads:
991 self.ui.status(_("(working directory not at a head)\n"))
990 self.ui.status(_("(working directory not at a head)\n"))
992
991
993 if not self.series:
992 if not self.series:
994 self.ui.warn(_('no patches in series\n'))
993 self.ui.warn(_('no patches in series\n'))
995 return 0
994 return 0
996
995
997 patch = self.lookup(patch)
996 patch = self.lookup(patch)
998 # Suppose our series file is: A B C and the current 'top'
997 # Suppose our series file is: A B C and the current 'top'
999 # patch is B. qpush C should be performed (moving forward)
998 # patch is B. qpush C should be performed (moving forward)
1000 # qpush B is a NOP (no change) qpush A is an error (can't
999 # qpush B is a NOP (no change) qpush A is an error (can't
1001 # go backwards with qpush)
1000 # go backwards with qpush)
1002 if patch:
1001 if patch:
1003 info = self.isapplied(patch)
1002 info = self.isapplied(patch)
1004 if info:
1003 if info:
1005 if info[0] < len(self.applied) - 1:
1004 if info[0] < len(self.applied) - 1:
1006 raise util.Abort(
1005 raise util.Abort(
1007 _("cannot push to a previous patch: %s") % patch)
1006 _("cannot push to a previous patch: %s") % patch)
1008 self.ui.warn(
1007 self.ui.warn(
1009 _('qpush: %s is already at the top\n') % patch)
1008 _('qpush: %s is already at the top\n') % patch)
1010 return
1009 return
1011 pushable, reason = self.pushable(patch)
1010 pushable, reason = self.pushable(patch)
1012 if not pushable:
1011 if not pushable:
1013 if reason:
1012 if reason:
1014 reason = _('guarded by %r') % reason
1013 reason = _('guarded by %r') % reason
1015 else:
1014 else:
1016 reason = _('no matching guards')
1015 reason = _('no matching guards')
1017 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1016 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1018 return 1
1017 return 1
1019 elif all:
1018 elif all:
1020 patch = self.series[-1]
1019 patch = self.series[-1]
1021 if self.isapplied(patch):
1020 if self.isapplied(patch):
1022 self.ui.warn(_('all patches are currently applied\n'))
1021 self.ui.warn(_('all patches are currently applied\n'))
1023 return 0
1022 return 0
1024
1023
1025 # Following the above example, starting at 'top' of B:
1024 # Following the above example, starting at 'top' of B:
1026 # qpush should be performed (pushes C), but a subsequent
1025 # qpush should be performed (pushes C), but a subsequent
1027 # qpush without an argument is an error (nothing to
1026 # qpush without an argument is an error (nothing to
1028 # apply). This allows a loop of "...while hg qpush..." to
1027 # apply). This allows a loop of "...while hg qpush..." to
1029 # work as it detects an error when done
1028 # work as it detects an error when done
1030 start = self.series_end()
1029 start = self.series_end()
1031 if start == len(self.series):
1030 if start == len(self.series):
1032 self.ui.warn(_('patch series already fully applied\n'))
1031 self.ui.warn(_('patch series already fully applied\n'))
1033 return 1
1032 return 1
1034 if not force:
1033 if not force:
1035 self.check_localchanges(repo)
1034 self.check_localchanges(repo)
1036
1035
1037 if move:
1036 if move:
1038 try:
1037 try:
1039 del self.full_series[self.full_series.index(patch, start)]
1038 del self.full_series[self.full_series.index(patch, start)]
1040 except ValueError:
1039 except ValueError:
1041 raise util.Abort(_("patch '%s' not found") % patch)
1040 raise util.Abort(_("patch '%s' not found") % patch)
1042 self.full_series.insert(start, patch)
1041 self.full_series.insert(start, patch)
1043 self.parse_series()
1042 self.parse_series()
1044 self.series_dirty = 1
1043 self.series_dirty = 1
1045
1044
1046 self.applied_dirty = 1
1045 self.applied_dirty = 1
1047 if start > 0:
1046 if start > 0:
1048 self.check_toppatch(repo)
1047 self.check_toppatch(repo)
1049 if not patch:
1048 if not patch:
1050 patch = self.series[start]
1049 patch = self.series[start]
1051 end = start + 1
1050 end = start + 1
1052 else:
1051 else:
1053 end = self.series.index(patch, start) + 1
1052 end = self.series.index(patch, start) + 1
1054
1053
1055 s = self.series[start:end]
1054 s = self.series[start:end]
1056 all_files = set()
1055 all_files = set()
1057 try:
1056 try:
1058 if mergeq:
1057 if mergeq:
1059 ret = self.mergepatch(repo, mergeq, s, diffopts)
1058 ret = self.mergepatch(repo, mergeq, s, diffopts)
1060 else:
1059 else:
1061 ret = self.apply(repo, s, list, all_files=all_files)
1060 ret = self.apply(repo, s, list, all_files=all_files)
1062 except:
1061 except:
1063 self.ui.warn(_('cleaning up working directory...'))
1062 self.ui.warn(_('cleaning up working directory...'))
1064 node = repo.dirstate.parents()[0]
1063 node = repo.dirstate.parents()[0]
1065 hg.revert(repo, node, None)
1064 hg.revert(repo, node, None)
1066 # only remove unknown files that we know we touched or
1065 # only remove unknown files that we know we touched or
1067 # created while patching
1066 # created while patching
1068 for f in all_files:
1067 for f in all_files:
1069 if f not in repo.dirstate:
1068 if f not in repo.dirstate:
1070 try:
1069 try:
1071 util.unlink(repo.wjoin(f))
1070 util.unlink(repo.wjoin(f))
1072 except OSError, inst:
1071 except OSError, inst:
1073 if inst.errno != errno.ENOENT:
1072 if inst.errno != errno.ENOENT:
1074 raise
1073 raise
1075 self.ui.warn(_('done\n'))
1074 self.ui.warn(_('done\n'))
1076 raise
1075 raise
1077
1076
1078 if not self.applied:
1077 if not self.applied:
1079 return ret[0]
1078 return ret[0]
1080 top = self.applied[-1].name
1079 top = self.applied[-1].name
1081 if ret[0] and ret[0] > 1:
1080 if ret[0] and ret[0] > 1:
1082 msg = _("errors during apply, please fix and refresh %s\n")
1081 msg = _("errors during apply, please fix and refresh %s\n")
1083 self.ui.write(msg % top)
1082 self.ui.write(msg % top)
1084 else:
1083 else:
1085 self.ui.write(_("now at: %s\n") % top)
1084 self.ui.write(_("now at: %s\n") % top)
1086 return ret[0]
1085 return ret[0]
1087
1086
1088 finally:
1087 finally:
1089 wlock.release()
1088 wlock.release()
1090
1089
1091 def pop(self, repo, patch=None, force=False, update=True, all=False):
1090 def pop(self, repo, patch=None, force=False, update=True, all=False):
1092 wlock = repo.wlock()
1091 wlock = repo.wlock()
1093 try:
1092 try:
1094 if patch:
1093 if patch:
1095 # index, rev, patch
1094 # index, rev, patch
1096 info = self.isapplied(patch)
1095 info = self.isapplied(patch)
1097 if not info:
1096 if not info:
1098 patch = self.lookup(patch)
1097 patch = self.lookup(patch)
1099 info = self.isapplied(patch)
1098 info = self.isapplied(patch)
1100 if not info:
1099 if not info:
1101 raise util.Abort(_("patch %s is not applied") % patch)
1100 raise util.Abort(_("patch %s is not applied") % patch)
1102
1101
1103 if not self.applied:
1102 if not self.applied:
1104 # Allow qpop -a to work repeatedly,
1103 # Allow qpop -a to work repeatedly,
1105 # but not qpop without an argument
1104 # but not qpop without an argument
1106 self.ui.warn(_("no patches applied\n"))
1105 self.ui.warn(_("no patches applied\n"))
1107 return not all
1106 return not all
1108
1107
1109 if all:
1108 if all:
1110 start = 0
1109 start = 0
1111 elif patch:
1110 elif patch:
1112 start = info[0] + 1
1111 start = info[0] + 1
1113 else:
1112 else:
1114 start = len(self.applied) - 1
1113 start = len(self.applied) - 1
1115
1114
1116 if start >= len(self.applied):
1115 if start >= len(self.applied):
1117 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1116 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1118 return
1117 return
1119
1118
1120 if not update:
1119 if not update:
1121 parents = repo.dirstate.parents()
1120 parents = repo.dirstate.parents()
1122 rr = [x.node for x in self.applied]
1121 rr = [x.node for x in self.applied]
1123 for p in parents:
1122 for p in parents:
1124 if p in rr:
1123 if p in rr:
1125 self.ui.warn(_("qpop: forcing dirstate update\n"))
1124 self.ui.warn(_("qpop: forcing dirstate update\n"))
1126 update = True
1125 update = True
1127 else:
1126 else:
1128 parents = [p.node() for p in repo[None].parents()]
1127 parents = [p.node() for p in repo[None].parents()]
1129 needupdate = False
1128 needupdate = False
1130 for entry in self.applied[start:]:
1129 for entry in self.applied[start:]:
1131 if entry.node in parents:
1130 if entry.node in parents:
1132 needupdate = True
1131 needupdate = True
1133 break
1132 break
1134 update = needupdate
1133 update = needupdate
1135
1134
1136 if not force and update:
1135 if not force and update:
1137 self.check_localchanges(repo)
1136 self.check_localchanges(repo)
1138
1137
1139 self.applied_dirty = 1
1138 self.applied_dirty = 1
1140 end = len(self.applied)
1139 end = len(self.applied)
1141 rev = self.applied[start].node
1140 rev = self.applied[start].node
1142 if update:
1141 if update:
1143 top = self.check_toppatch(repo)[0]
1142 top = self.check_toppatch(repo)[0]
1144
1143
1145 try:
1144 try:
1146 heads = repo.changelog.heads(rev)
1145 heads = repo.changelog.heads(rev)
1147 except error.LookupError:
1146 except error.LookupError:
1148 node = short(rev)
1147 node = short(rev)
1149 raise util.Abort(_('trying to pop unknown node %s') % node)
1148 raise util.Abort(_('trying to pop unknown node %s') % node)
1150
1149
1151 if heads != [self.applied[-1].node]:
1150 if heads != [self.applied[-1].node]:
1152 raise util.Abort(_("popping would remove a revision not "
1151 raise util.Abort(_("popping would remove a revision not "
1153 "managed by this patch queue"))
1152 "managed by this patch queue"))
1154
1153
1155 # we know there are no local changes, so we can make a simplified
1154 # we know there are no local changes, so we can make a simplified
1156 # form of hg.update.
1155 # form of hg.update.
1157 if update:
1156 if update:
1158 qp = self.qparents(repo, rev)
1157 qp = self.qparents(repo, rev)
1159 ctx = repo[qp]
1158 ctx = repo[qp]
1160 m, a, r, d = repo.status(qp, top)[:4]
1159 m, a, r, d = repo.status(qp, top)[:4]
1161 if d:
1160 if d:
1162 raise util.Abort(_("deletions found between repo revs"))
1161 raise util.Abort(_("deletions found between repo revs"))
1163 for f in a:
1162 for f in a:
1164 try:
1163 try:
1165 util.unlink(repo.wjoin(f))
1164 util.unlink(repo.wjoin(f))
1166 except OSError, e:
1165 except OSError, e:
1167 if e.errno != errno.ENOENT:
1166 if e.errno != errno.ENOENT:
1168 raise
1167 raise
1169 repo.dirstate.forget(f)
1168 repo.dirstate.forget(f)
1170 for f in m + r:
1169 for f in m + r:
1171 fctx = ctx[f]
1170 fctx = ctx[f]
1172 repo.wwrite(f, fctx.data(), fctx.flags())
1171 repo.wwrite(f, fctx.data(), fctx.flags())
1173 repo.dirstate.normal(f)
1172 repo.dirstate.normal(f)
1174 repo.dirstate.setparents(qp, nullid)
1173 repo.dirstate.setparents(qp, nullid)
1175 for patch in reversed(self.applied[start:end]):
1174 for patch in reversed(self.applied[start:end]):
1176 self.ui.status(_("popping %s\n") % patch.name)
1175 self.ui.status(_("popping %s\n") % patch.name)
1177 del self.applied[start:end]
1176 del self.applied[start:end]
1178 self.strip(repo, rev, update=False, backup='strip')
1177 self.strip(repo, rev, update=False, backup='strip')
1179 if self.applied:
1178 if self.applied:
1180 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1179 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1181 else:
1180 else:
1182 self.ui.write(_("patch queue now empty\n"))
1181 self.ui.write(_("patch queue now empty\n"))
1183 finally:
1182 finally:
1184 wlock.release()
1183 wlock.release()
1185
1184
1186 def diff(self, repo, pats, opts):
1185 def diff(self, repo, pats, opts):
1187 top, patch = self.check_toppatch(repo)
1186 top, patch = self.check_toppatch(repo)
1188 if not top:
1187 if not top:
1189 self.ui.write(_("no patches applied\n"))
1188 self.ui.write(_("no patches applied\n"))
1190 return
1189 return
1191 qp = self.qparents(repo, top)
1190 qp = self.qparents(repo, top)
1192 if opts.get('reverse'):
1191 if opts.get('reverse'):
1193 node1, node2 = None, qp
1192 node1, node2 = None, qp
1194 else:
1193 else:
1195 node1, node2 = qp, None
1194 node1, node2 = qp, None
1196 diffopts = self.diffopts(opts, patch)
1195 diffopts = self.diffopts(opts, patch)
1197 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1196 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1198
1197
1199 def refresh(self, repo, pats=None, **opts):
1198 def refresh(self, repo, pats=None, **opts):
1200 if not self.applied:
1199 if not self.applied:
1201 self.ui.write(_("no patches applied\n"))
1200 self.ui.write(_("no patches applied\n"))
1202 return 1
1201 return 1
1203 msg = opts.get('msg', '').rstrip()
1202 msg = opts.get('msg', '').rstrip()
1204 newuser = opts.get('user')
1203 newuser = opts.get('user')
1205 newdate = opts.get('date')
1204 newdate = opts.get('date')
1206 if newdate:
1205 if newdate:
1207 newdate = '%d %d' % util.parsedate(newdate)
1206 newdate = '%d %d' % util.parsedate(newdate)
1208 wlock = repo.wlock()
1207 wlock = repo.wlock()
1209
1208
1210 try:
1209 try:
1211 self.check_toppatch(repo)
1210 self.check_toppatch(repo)
1212 (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
1211 (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
1213 if repo.changelog.heads(top) != [top]:
1212 if repo.changelog.heads(top) != [top]:
1214 raise util.Abort(_("cannot refresh a revision with children"))
1213 raise util.Abort(_("cannot refresh a revision with children"))
1215
1214
1216 cparents = repo.changelog.parents(top)
1215 cparents = repo.changelog.parents(top)
1217 patchparent = self.qparents(repo, top)
1216 patchparent = self.qparents(repo, top)
1218 ph = patchheader(self.join(patchfn), self.plainmode)
1217 ph = patchheader(self.join(patchfn), self.plainmode)
1219 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1218 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1220 if msg:
1219 if msg:
1221 ph.setmessage(msg)
1220 ph.setmessage(msg)
1222 if newuser:
1221 if newuser:
1223 ph.setuser(newuser)
1222 ph.setuser(newuser)
1224 if newdate:
1223 if newdate:
1225 ph.setdate(newdate)
1224 ph.setdate(newdate)
1226 ph.setparent(hex(patchparent))
1225 ph.setparent(hex(patchparent))
1227
1226
1228 # only commit new patch when write is complete
1227 # only commit new patch when write is complete
1229 patchf = self.opener(patchfn, 'w', atomictemp=True)
1228 patchf = self.opener(patchfn, 'w', atomictemp=True)
1230
1229
1231 comments = str(ph)
1230 comments = str(ph)
1232 if comments:
1231 if comments:
1233 patchf.write(comments)
1232 patchf.write(comments)
1234
1233
1235 # update the dirstate in place, strip off the qtip commit
1234 # update the dirstate in place, strip off the qtip commit
1236 # and then commit.
1235 # and then commit.
1237 #
1236 #
1238 # this should really read:
1237 # this should really read:
1239 # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
1238 # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
1240 # but we do it backwards to take advantage of manifest/chlog
1239 # but we do it backwards to take advantage of manifest/chlog
1241 # caching against the next repo.status call
1240 # caching against the next repo.status call
1242 mm, aa, dd, aa2 = repo.status(patchparent, top)[:4]
1241 mm, aa, dd, aa2 = repo.status(patchparent, top)[:4]
1243 changes = repo.changelog.read(top)
1242 changes = repo.changelog.read(top)
1244 man = repo.manifest.read(changes[0])
1243 man = repo.manifest.read(changes[0])
1245 aaa = aa[:]
1244 aaa = aa[:]
1246 matchfn = cmdutil.match(repo, pats, opts)
1245 matchfn = cmdutil.match(repo, pats, opts)
1247 # in short mode, we only diff the files included in the
1246 # in short mode, we only diff the files included in the
1248 # patch already plus specified files
1247 # patch already plus specified files
1249 if opts.get('short'):
1248 if opts.get('short'):
1250 # if amending a patch, we start with existing
1249 # if amending a patch, we start with existing
1251 # files plus specified files - unfiltered
1250 # files plus specified files - unfiltered
1252 match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1251 match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1253 # filter with inc/exl options
1252 # filter with inc/exl options
1254 matchfn = cmdutil.match(repo, opts=opts)
1253 matchfn = cmdutil.match(repo, opts=opts)
1255 else:
1254 else:
1256 match = cmdutil.matchall(repo)
1255 match = cmdutil.matchall(repo)
1257 m, a, r, d = repo.status(match=match)[:4]
1256 m, a, r, d = repo.status(match=match)[:4]
1258
1257
1259 # we might end up with files that were added between
1258 # we might end up with files that were added between
1260 # qtip and the dirstate parent, but then changed in the
1259 # qtip and the dirstate parent, but then changed in the
1261 # local dirstate. in this case, we want them to only
1260 # local dirstate. in this case, we want them to only
1262 # show up in the added section
1261 # show up in the added section
1263 for x in m:
1262 for x in m:
1264 if x not in aa:
1263 if x not in aa:
1265 mm.append(x)
1264 mm.append(x)
1266 # we might end up with files added by the local dirstate that
1265 # we might end up with files added by the local dirstate that
1267 # were deleted by the patch. In this case, they should only
1266 # were deleted by the patch. In this case, they should only
1268 # show up in the changed section.
1267 # show up in the changed section.
1269 for x in a:
1268 for x in a:
1270 if x in dd:
1269 if x in dd:
1271 del dd[dd.index(x)]
1270 del dd[dd.index(x)]
1272 mm.append(x)
1271 mm.append(x)
1273 else:
1272 else:
1274 aa.append(x)
1273 aa.append(x)
1275 # make sure any files deleted in the local dirstate
1274 # make sure any files deleted in the local dirstate
1276 # are not in the add or change column of the patch
1275 # are not in the add or change column of the patch
1277 forget = []
1276 forget = []
1278 for x in d + r:
1277 for x in d + r:
1279 if x in aa:
1278 if x in aa:
1280 del aa[aa.index(x)]
1279 del aa[aa.index(x)]
1281 forget.append(x)
1280 forget.append(x)
1282 continue
1281 continue
1283 elif x in mm:
1282 elif x in mm:
1284 del mm[mm.index(x)]
1283 del mm[mm.index(x)]
1285 dd.append(x)
1284 dd.append(x)
1286
1285
1287 m = list(set(mm))
1286 m = list(set(mm))
1288 r = list(set(dd))
1287 r = list(set(dd))
1289 a = list(set(aa))
1288 a = list(set(aa))
1290 c = [filter(matchfn, l) for l in (m, a, r)]
1289 c = [filter(matchfn, l) for l in (m, a, r)]
1291 match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2]))
1290 match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2]))
1292 chunks = patch.diff(repo, patchparent, match=match,
1291 chunks = patch.diff(repo, patchparent, match=match,
1293 changes=c, opts=diffopts)
1292 changes=c, opts=diffopts)
1294 for chunk in chunks:
1293 for chunk in chunks:
1295 patchf.write(chunk)
1294 patchf.write(chunk)
1296
1295
1297 try:
1296 try:
1298 if diffopts.git or diffopts.upgrade:
1297 if diffopts.git or diffopts.upgrade:
1299 copies = {}
1298 copies = {}
1300 for dst in a:
1299 for dst in a:
1301 src = repo.dirstate.copied(dst)
1300 src = repo.dirstate.copied(dst)
1302 # during qfold, the source file for copies may
1301 # during qfold, the source file for copies may
1303 # be removed. Treat this as a simple add.
1302 # be removed. Treat this as a simple add.
1304 if src is not None and src in repo.dirstate:
1303 if src is not None and src in repo.dirstate:
1305 copies.setdefault(src, []).append(dst)
1304 copies.setdefault(src, []).append(dst)
1306 repo.dirstate.add(dst)
1305 repo.dirstate.add(dst)
1307 # remember the copies between patchparent and qtip
1306 # remember the copies between patchparent and qtip
1308 for dst in aaa:
1307 for dst in aaa:
1309 f = repo.file(dst)
1308 f = repo.file(dst)
1310 src = f.renamed(man[dst])
1309 src = f.renamed(man[dst])
1311 if src:
1310 if src:
1312 copies.setdefault(src[0], []).extend(
1311 copies.setdefault(src[0], []).extend(
1313 copies.get(dst, []))
1312 copies.get(dst, []))
1314 if dst in a:
1313 if dst in a:
1315 copies[src[0]].append(dst)
1314 copies[src[0]].append(dst)
1316 # we can't copy a file created by the patch itself
1315 # we can't copy a file created by the patch itself
1317 if dst in copies:
1316 if dst in copies:
1318 del copies[dst]
1317 del copies[dst]
1319 for src, dsts in copies.iteritems():
1318 for src, dsts in copies.iteritems():
1320 for dst in dsts:
1319 for dst in dsts:
1321 repo.dirstate.copy(src, dst)
1320 repo.dirstate.copy(src, dst)
1322 else:
1321 else:
1323 for dst in a:
1322 for dst in a:
1324 repo.dirstate.add(dst)
1323 repo.dirstate.add(dst)
1325 # Drop useless copy information
1324 # Drop useless copy information
1326 for f in list(repo.dirstate.copies()):
1325 for f in list(repo.dirstate.copies()):
1327 repo.dirstate.copy(None, f)
1326 repo.dirstate.copy(None, f)
1328 for f in r:
1327 for f in r:
1329 repo.dirstate.remove(f)
1328 repo.dirstate.remove(f)
1330 # if the patch excludes a modified file, mark that
1329 # if the patch excludes a modified file, mark that
1331 # file with mtime=0 so status can see it.
1330 # file with mtime=0 so status can see it.
1332 mm = []
1331 mm = []
1333 for i in xrange(len(m)-1, -1, -1):
1332 for i in xrange(len(m)-1, -1, -1):
1334 if not matchfn(m[i]):
1333 if not matchfn(m[i]):
1335 mm.append(m[i])
1334 mm.append(m[i])
1336 del m[i]
1335 del m[i]
1337 for f in m:
1336 for f in m:
1338 repo.dirstate.normal(f)
1337 repo.dirstate.normal(f)
1339 for f in mm:
1338 for f in mm:
1340 repo.dirstate.normallookup(f)
1339 repo.dirstate.normallookup(f)
1341 for f in forget:
1340 for f in forget:
1342 repo.dirstate.forget(f)
1341 repo.dirstate.forget(f)
1343
1342
1344 if not msg:
1343 if not msg:
1345 if not ph.message:
1344 if not ph.message:
1346 message = "[mq]: %s\n" % patchfn
1345 message = "[mq]: %s\n" % patchfn
1347 else:
1346 else:
1348 message = "\n".join(ph.message)
1347 message = "\n".join(ph.message)
1349 else:
1348 else:
1350 message = msg
1349 message = msg
1351
1350
1352 user = ph.user or changes[1]
1351 user = ph.user or changes[1]
1353
1352
1354 # assumes strip can roll itself back if interrupted
1353 # assumes strip can roll itself back if interrupted
1355 repo.dirstate.setparents(*cparents)
1354 repo.dirstate.setparents(*cparents)
1356 self.applied.pop()
1355 self.applied.pop()
1357 self.applied_dirty = 1
1356 self.applied_dirty = 1
1358 self.strip(repo, top, update=False,
1357 self.strip(repo, top, update=False,
1359 backup='strip')
1358 backup='strip')
1360 except:
1359 except:
1361 repo.dirstate.invalidate()
1360 repo.dirstate.invalidate()
1362 raise
1361 raise
1363
1362
1364 try:
1363 try:
1365 # might be nice to attempt to roll back strip after this
1364 # might be nice to attempt to roll back strip after this
1366 patchf.rename()
1365 patchf.rename()
1367 n = repo.commit(message, user, ph.date, match=match,
1366 n = repo.commit(message, user, ph.date, match=match,
1368 force=True)
1367 force=True)
1369 self.applied.append(statusentry(n, patchfn))
1368 self.applied.append(statusentry(n, patchfn))
1370 except:
1369 except:
1371 ctx = repo[cparents[0]]
1370 ctx = repo[cparents[0]]
1372 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1371 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1373 self.save_dirty()
1372 self.save_dirty()
1374 self.ui.warn(_('refresh interrupted while patch was popped! '
1373 self.ui.warn(_('refresh interrupted while patch was popped! '
1375 '(revert --all, qpush to recover)\n'))
1374 '(revert --all, qpush to recover)\n'))
1376 raise
1375 raise
1377 finally:
1376 finally:
1378 wlock.release()
1377 wlock.release()
1379 self.removeundo(repo)
1378 self.removeundo(repo)
1380
1379
1381 def init(self, repo, create=False):
1380 def init(self, repo, create=False):
1382 if not create and os.path.isdir(self.path):
1381 if not create and os.path.isdir(self.path):
1383 raise util.Abort(_("patch queue directory already exists"))
1382 raise util.Abort(_("patch queue directory already exists"))
1384 try:
1383 try:
1385 os.mkdir(self.path)
1384 os.mkdir(self.path)
1386 except OSError, inst:
1385 except OSError, inst:
1387 if inst.errno != errno.EEXIST or not create:
1386 if inst.errno != errno.EEXIST or not create:
1388 raise
1387 raise
1389 if create:
1388 if create:
1390 return self.qrepo(create=True)
1389 return self.qrepo(create=True)
1391
1390
1392 def unapplied(self, repo, patch=None):
1391 def unapplied(self, repo, patch=None):
1393 if patch and patch not in self.series:
1392 if patch and patch not in self.series:
1394 raise util.Abort(_("patch %s is not in series file") % patch)
1393 raise util.Abort(_("patch %s is not in series file") % patch)
1395 if not patch:
1394 if not patch:
1396 start = self.series_end()
1395 start = self.series_end()
1397 else:
1396 else:
1398 start = self.series.index(patch) + 1
1397 start = self.series.index(patch) + 1
1399 unapplied = []
1398 unapplied = []
1400 for i in xrange(start, len(self.series)):
1399 for i in xrange(start, len(self.series)):
1401 pushable, reason = self.pushable(i)
1400 pushable, reason = self.pushable(i)
1402 if pushable:
1401 if pushable:
1403 unapplied.append((i, self.series[i]))
1402 unapplied.append((i, self.series[i]))
1404 self.explain_pushable(i)
1403 self.explain_pushable(i)
1405 return unapplied
1404 return unapplied
1406
1405
1407 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1406 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1408 summary=False):
1407 summary=False):
1409 def displayname(pfx, patchname, state):
1408 def displayname(pfx, patchname, state):
1410 if pfx:
1409 if pfx:
1411 self.ui.write(pfx)
1410 self.ui.write(pfx)
1412 if summary:
1411 if summary:
1413 ph = patchheader(self.join(patchname), self.plainmode)
1412 ph = patchheader(self.join(patchname), self.plainmode)
1414 msg = ph.message and ph.message[0] or ''
1413 msg = ph.message and ph.message[0] or ''
1415 if not self.ui.plain():
1414 if not self.ui.plain():
1416 width = util.termwidth() - len(pfx) - len(patchname) - 2
1415 width = util.termwidth() - len(pfx) - len(patchname) - 2
1417 if width > 0:
1416 if width > 0:
1418 msg = util.ellipsis(msg, width)
1417 msg = util.ellipsis(msg, width)
1419 else:
1418 else:
1420 msg = ''
1419 msg = ''
1421 self.ui.write(patchname, label='qseries.' + state)
1420 self.ui.write(patchname, label='qseries.' + state)
1422 self.ui.write(': ')
1421 self.ui.write(': ')
1423 self.ui.write(msg, label='qseries.message.' + state)
1422 self.ui.write(msg, label='qseries.message.' + state)
1424 else:
1423 else:
1425 self.ui.write(patchname, label='qseries.' + state)
1424 self.ui.write(patchname, label='qseries.' + state)
1426 self.ui.write('\n')
1425 self.ui.write('\n')
1427
1426
1428 applied = set([p.name for p in self.applied])
1427 applied = set([p.name for p in self.applied])
1429 if length is None:
1428 if length is None:
1430 length = len(self.series) - start
1429 length = len(self.series) - start
1431 if not missing:
1430 if not missing:
1432 if self.ui.verbose:
1431 if self.ui.verbose:
1433 idxwidth = len(str(start + length - 1))
1432 idxwidth = len(str(start + length - 1))
1434 for i in xrange(start, start + length):
1433 for i in xrange(start, start + length):
1435 patch = self.series[i]
1434 patch = self.series[i]
1436 if patch in applied:
1435 if patch in applied:
1437 char, state = 'A', 'applied'
1436 char, state = 'A', 'applied'
1438 elif self.pushable(i)[0]:
1437 elif self.pushable(i)[0]:
1439 char, state = 'U', 'unapplied'
1438 char, state = 'U', 'unapplied'
1440 else:
1439 else:
1441 char, state = 'G', 'guarded'
1440 char, state = 'G', 'guarded'
1442 pfx = ''
1441 pfx = ''
1443 if self.ui.verbose:
1442 if self.ui.verbose:
1444 pfx = '%*d %s ' % (idxwidth, i, char)
1443 pfx = '%*d %s ' % (idxwidth, i, char)
1445 elif status and status != char:
1444 elif status and status != char:
1446 continue
1445 continue
1447 displayname(pfx, patch, state)
1446 displayname(pfx, patch, state)
1448 else:
1447 else:
1449 msng_list = []
1448 msng_list = []
1450 for root, dirs, files in os.walk(self.path):
1449 for root, dirs, files in os.walk(self.path):
1451 d = root[len(self.path) + 1:]
1450 d = root[len(self.path) + 1:]
1452 for f in files:
1451 for f in files:
1453 fl = os.path.join(d, f)
1452 fl = os.path.join(d, f)
1454 if (fl not in self.series and
1453 if (fl not in self.series and
1455 fl not in (self.status_path, self.series_path,
1454 fl not in (self.status_path, self.series_path,
1456 self.guards_path)
1455 self.guards_path)
1457 and not fl.startswith('.')):
1456 and not fl.startswith('.')):
1458 msng_list.append(fl)
1457 msng_list.append(fl)
1459 for x in sorted(msng_list):
1458 for x in sorted(msng_list):
1460 pfx = self.ui.verbose and ('D ') or ''
1459 pfx = self.ui.verbose and ('D ') or ''
1461 displayname(pfx, x, 'missing')
1460 displayname(pfx, x, 'missing')
1462
1461
1463 def issaveline(self, l):
1462 def issaveline(self, l):
1464 if l.name == '.hg.patches.save.line':
1463 if l.name == '.hg.patches.save.line':
1465 return True
1464 return True
1466
1465
1467 def qrepo(self, create=False):
1466 def qrepo(self, create=False):
1468 if create or os.path.isdir(self.join(".hg")):
1467 if create or os.path.isdir(self.join(".hg")):
1469 return hg.repository(self.ui, path=self.path, create=create)
1468 return hg.repository(self.ui, path=self.path, create=create)
1470
1469
1471 def restore(self, repo, rev, delete=None, qupdate=None):
1470 def restore(self, repo, rev, delete=None, qupdate=None):
1472 desc = repo[rev].description().strip()
1471 desc = repo[rev].description().strip()
1473 lines = desc.splitlines()
1472 lines = desc.splitlines()
1474 i = 0
1473 i = 0
1475 datastart = None
1474 datastart = None
1476 series = []
1475 series = []
1477 applied = []
1476 applied = []
1478 qpp = None
1477 qpp = None
1479 for i, line in enumerate(lines):
1478 for i, line in enumerate(lines):
1480 if line == 'Patch Data:':
1479 if line == 'Patch Data:':
1481 datastart = i + 1
1480 datastart = i + 1
1482 elif line.startswith('Dirstate:'):
1481 elif line.startswith('Dirstate:'):
1483 l = line.rstrip()
1482 l = line.rstrip()
1484 l = l[10:].split(' ')
1483 l = l[10:].split(' ')
1485 qpp = [bin(x) for x in l]
1484 qpp = [bin(x) for x in l]
1486 elif datastart != None:
1485 elif datastart != None:
1487 l = line.rstrip()
1486 l = line.rstrip()
1488 n, name = l.split(':', 1)
1487 n, name = l.split(':', 1)
1489 if n:
1488 if n:
1490 applied.append(statusentry(bin(n), name))
1489 applied.append(statusentry(bin(n), name))
1491 else:
1490 else:
1492 series.append(l)
1491 series.append(l)
1493 if datastart is None:
1492 if datastart is None:
1494 self.ui.warn(_("No saved patch data found\n"))
1493 self.ui.warn(_("No saved patch data found\n"))
1495 return 1
1494 return 1
1496 self.ui.warn(_("restoring status: %s\n") % lines[0])
1495 self.ui.warn(_("restoring status: %s\n") % lines[0])
1497 self.full_series = series
1496 self.full_series = series
1498 self.applied = applied
1497 self.applied = applied
1499 self.parse_series()
1498 self.parse_series()
1500 self.series_dirty = 1
1499 self.series_dirty = 1
1501 self.applied_dirty = 1
1500 self.applied_dirty = 1
1502 heads = repo.changelog.heads()
1501 heads = repo.changelog.heads()
1503 if delete:
1502 if delete:
1504 if rev not in heads:
1503 if rev not in heads:
1505 self.ui.warn(_("save entry has children, leaving it alone\n"))
1504 self.ui.warn(_("save entry has children, leaving it alone\n"))
1506 else:
1505 else:
1507 self.ui.warn(_("removing save entry %s\n") % short(rev))
1506 self.ui.warn(_("removing save entry %s\n") % short(rev))
1508 pp = repo.dirstate.parents()
1507 pp = repo.dirstate.parents()
1509 if rev in pp:
1508 if rev in pp:
1510 update = True
1509 update = True
1511 else:
1510 else:
1512 update = False
1511 update = False
1513 self.strip(repo, rev, update=update, backup='strip')
1512 self.strip(repo, rev, update=update, backup='strip')
1514 if qpp:
1513 if qpp:
1515 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1514 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1516 (short(qpp[0]), short(qpp[1])))
1515 (short(qpp[0]), short(qpp[1])))
1517 if qupdate:
1516 if qupdate:
1518 self.ui.status(_("queue directory updating\n"))
1517 self.ui.status(_("queue directory updating\n"))
1519 r = self.qrepo()
1518 r = self.qrepo()
1520 if not r:
1519 if not r:
1521 self.ui.warn(_("Unable to load queue repository\n"))
1520 self.ui.warn(_("Unable to load queue repository\n"))
1522 return 1
1521 return 1
1523 hg.clean(r, qpp[0])
1522 hg.clean(r, qpp[0])
1524
1523
1525 def save(self, repo, msg=None):
1524 def save(self, repo, msg=None):
1526 if not self.applied:
1525 if not self.applied:
1527 self.ui.warn(_("save: no patches applied, exiting\n"))
1526 self.ui.warn(_("save: no patches applied, exiting\n"))
1528 return 1
1527 return 1
1529 if self.issaveline(self.applied[-1]):
1528 if self.issaveline(self.applied[-1]):
1530 self.ui.warn(_("status is already saved\n"))
1529 self.ui.warn(_("status is already saved\n"))
1531 return 1
1530 return 1
1532
1531
1533 if not msg:
1532 if not msg:
1534 msg = _("hg patches saved state")
1533 msg = _("hg patches saved state")
1535 else:
1534 else:
1536 msg = "hg patches: " + msg.rstrip('\r\n')
1535 msg = "hg patches: " + msg.rstrip('\r\n')
1537 r = self.qrepo()
1536 r = self.qrepo()
1538 if r:
1537 if r:
1539 pp = r.dirstate.parents()
1538 pp = r.dirstate.parents()
1540 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1539 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1541 msg += "\n\nPatch Data:\n"
1540 msg += "\n\nPatch Data:\n"
1542 msg += ''.join('%s\n' % x for x in self.applied)
1541 msg += ''.join('%s\n' % x for x in self.applied)
1543 msg += ''.join(':%s\n' % x for x in self.full_series)
1542 msg += ''.join(':%s\n' % x for x in self.full_series)
1544 n = repo.commit(msg, force=True)
1543 n = repo.commit(msg, force=True)
1545 if not n:
1544 if not n:
1546 self.ui.warn(_("repo commit failed\n"))
1545 self.ui.warn(_("repo commit failed\n"))
1547 return 1
1546 return 1
1548 self.applied.append(statusentry(n, '.hg.patches.save.line'))
1547 self.applied.append(statusentry(n, '.hg.patches.save.line'))
1549 self.applied_dirty = 1
1548 self.applied_dirty = 1
1550 self.removeundo(repo)
1549 self.removeundo(repo)
1551
1550
1552 def full_series_end(self):
1551 def full_series_end(self):
1553 if self.applied:
1552 if self.applied:
1554 p = self.applied[-1].name
1553 p = self.applied[-1].name
1555 end = self.find_series(p)
1554 end = self.find_series(p)
1556 if end is None:
1555 if end is None:
1557 return len(self.full_series)
1556 return len(self.full_series)
1558 return end + 1
1557 return end + 1
1559 return 0
1558 return 0
1560
1559
1561 def series_end(self, all_patches=False):
1560 def series_end(self, all_patches=False):
1562 """If all_patches is False, return the index of the next pushable patch
1561 """If all_patches is False, return the index of the next pushable patch
1563 in the series, or the series length. If all_patches is True, return the
1562 in the series, or the series length. If all_patches is True, return the
1564 index of the first patch past the last applied one.
1563 index of the first patch past the last applied one.
1565 """
1564 """
1566 end = 0
1565 end = 0
1567 def next(start):
1566 def next(start):
1568 if all_patches or start >= len(self.series):
1567 if all_patches or start >= len(self.series):
1569 return start
1568 return start
1570 for i in xrange(start, len(self.series)):
1569 for i in xrange(start, len(self.series)):
1571 p, reason = self.pushable(i)
1570 p, reason = self.pushable(i)
1572 if p:
1571 if p:
1573 break
1572 break
1574 self.explain_pushable(i)
1573 self.explain_pushable(i)
1575 return i
1574 return i
1576 if self.applied:
1575 if self.applied:
1577 p = self.applied[-1].name
1576 p = self.applied[-1].name
1578 try:
1577 try:
1579 end = self.series.index(p)
1578 end = self.series.index(p)
1580 except ValueError:
1579 except ValueError:
1581 return 0
1580 return 0
1582 return next(end + 1)
1581 return next(end + 1)
1583 return next(end)
1582 return next(end)
1584
1583
1585 def appliedname(self, index):
1584 def appliedname(self, index):
1586 pname = self.applied[index].name
1585 pname = self.applied[index].name
1587 if not self.ui.verbose:
1586 if not self.ui.verbose:
1588 p = pname
1587 p = pname
1589 else:
1588 else:
1590 p = str(self.series.index(pname)) + " " + pname
1589 p = str(self.series.index(pname)) + " " + pname
1591 return p
1590 return p
1592
1591
1593 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1592 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1594 force=None, git=False):
1593 force=None, git=False):
1595 def checkseries(patchname):
1594 def checkseries(patchname):
1596 if patchname in self.series:
1595 if patchname in self.series:
1597 raise util.Abort(_('patch %s is already in the series file')
1596 raise util.Abort(_('patch %s is already in the series file')
1598 % patchname)
1597 % patchname)
1599 def checkfile(patchname):
1598 def checkfile(patchname):
1600 if not force and os.path.exists(self.join(patchname)):
1599 if not force and os.path.exists(self.join(patchname)):
1601 raise util.Abort(_('patch "%s" already exists')
1600 raise util.Abort(_('patch "%s" already exists')
1602 % patchname)
1601 % patchname)
1603
1602
1604 if rev:
1603 if rev:
1605 if files:
1604 if files:
1606 raise util.Abort(_('option "-r" not valid when importing '
1605 raise util.Abort(_('option "-r" not valid when importing '
1607 'files'))
1606 'files'))
1608 rev = cmdutil.revrange(repo, rev)
1607 rev = cmdutil.revrange(repo, rev)
1609 rev.sort(reverse=True)
1608 rev.sort(reverse=True)
1610 if (len(files) > 1 or len(rev) > 1) and patchname:
1609 if (len(files) > 1 or len(rev) > 1) and patchname:
1611 raise util.Abort(_('option "-n" not valid when importing multiple '
1610 raise util.Abort(_('option "-n" not valid when importing multiple '
1612 'patches'))
1611 'patches'))
1613 added = []
1612 added = []
1614 if rev:
1613 if rev:
1615 # If mq patches are applied, we can only import revisions
1614 # If mq patches are applied, we can only import revisions
1616 # that form a linear path to qbase.
1615 # that form a linear path to qbase.
1617 # Otherwise, they should form a linear path to a head.
1616 # Otherwise, they should form a linear path to a head.
1618 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1617 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1619 if len(heads) > 1:
1618 if len(heads) > 1:
1620 raise util.Abort(_('revision %d is the root of more than one '
1619 raise util.Abort(_('revision %d is the root of more than one '
1621 'branch') % rev[-1])
1620 'branch') % rev[-1])
1622 if self.applied:
1621 if self.applied:
1623 base = repo.changelog.node(rev[0])
1622 base = repo.changelog.node(rev[0])
1624 if base in [n.node for n in self.applied]:
1623 if base in [n.node for n in self.applied]:
1625 raise util.Abort(_('revision %d is already managed')
1624 raise util.Abort(_('revision %d is already managed')
1626 % rev[0])
1625 % rev[0])
1627 if heads != [self.applied[-1].node]:
1626 if heads != [self.applied[-1].node]:
1628 raise util.Abort(_('revision %d is not the parent of '
1627 raise util.Abort(_('revision %d is not the parent of '
1629 'the queue') % rev[0])
1628 'the queue') % rev[0])
1630 base = repo.changelog.rev(self.applied[0].node)
1629 base = repo.changelog.rev(self.applied[0].node)
1631 lastparent = repo.changelog.parentrevs(base)[0]
1630 lastparent = repo.changelog.parentrevs(base)[0]
1632 else:
1631 else:
1633 if heads != [repo.changelog.node(rev[0])]:
1632 if heads != [repo.changelog.node(rev[0])]:
1634 raise util.Abort(_('revision %d has unmanaged children')
1633 raise util.Abort(_('revision %d has unmanaged children')
1635 % rev[0])
1634 % rev[0])
1636 lastparent = None
1635 lastparent = None
1637
1636
1638 diffopts = self.diffopts({'git': git})
1637 diffopts = self.diffopts({'git': git})
1639 for r in rev:
1638 for r in rev:
1640 p1, p2 = repo.changelog.parentrevs(r)
1639 p1, p2 = repo.changelog.parentrevs(r)
1641 n = repo.changelog.node(r)
1640 n = repo.changelog.node(r)
1642 if p2 != nullrev:
1641 if p2 != nullrev:
1643 raise util.Abort(_('cannot import merge revision %d') % r)
1642 raise util.Abort(_('cannot import merge revision %d') % r)
1644 if lastparent and lastparent != r:
1643 if lastparent and lastparent != r:
1645 raise util.Abort(_('revision %d is not the parent of %d')
1644 raise util.Abort(_('revision %d is not the parent of %d')
1646 % (r, lastparent))
1645 % (r, lastparent))
1647 lastparent = p1
1646 lastparent = p1
1648
1647
1649 if not patchname:
1648 if not patchname:
1650 patchname = normname('%d.diff' % r)
1649 patchname = normname('%d.diff' % r)
1651 self.check_reserved_name(patchname)
1650 self.check_reserved_name(patchname)
1652 checkseries(patchname)
1651 checkseries(patchname)
1653 checkfile(patchname)
1652 checkfile(patchname)
1654 self.full_series.insert(0, patchname)
1653 self.full_series.insert(0, patchname)
1655
1654
1656 patchf = self.opener(patchname, "w")
1655 patchf = self.opener(patchname, "w")
1657 cmdutil.export(repo, [n], fp=patchf, opts=diffopts)
1656 cmdutil.export(repo, [n], fp=patchf, opts=diffopts)
1658 patchf.close()
1657 patchf.close()
1659
1658
1660 se = statusentry(n, patchname)
1659 se = statusentry(n, patchname)
1661 self.applied.insert(0, se)
1660 self.applied.insert(0, se)
1662
1661
1663 added.append(patchname)
1662 added.append(patchname)
1664 patchname = None
1663 patchname = None
1665 self.parse_series()
1664 self.parse_series()
1666 self.applied_dirty = 1
1665 self.applied_dirty = 1
1667
1666
1668 for i, filename in enumerate(files):
1667 for i, filename in enumerate(files):
1669 if existing:
1668 if existing:
1670 if filename == '-':
1669 if filename == '-':
1671 raise util.Abort(_('-e is incompatible with import from -'))
1670 raise util.Abort(_('-e is incompatible with import from -'))
1672 if not patchname:
1671 if not patchname:
1673 patchname = normname(filename)
1672 patchname = normname(filename)
1674 self.check_reserved_name(patchname)
1673 self.check_reserved_name(patchname)
1675 if not os.path.isfile(self.join(patchname)):
1674 if not os.path.isfile(self.join(patchname)):
1676 raise util.Abort(_("patch %s does not exist") % patchname)
1675 raise util.Abort(_("patch %s does not exist") % patchname)
1677 else:
1676 else:
1678 try:
1677 try:
1679 if filename == '-':
1678 if filename == '-':
1680 if not patchname:
1679 if not patchname:
1681 raise util.Abort(
1680 raise util.Abort(
1682 _('need --name to import a patch from -'))
1681 _('need --name to import a patch from -'))
1683 text = sys.stdin.read()
1682 text = sys.stdin.read()
1684 else:
1683 else:
1685 text = url.open(self.ui, filename).read()
1684 text = url.open(self.ui, filename).read()
1686 except (OSError, IOError):
1685 except (OSError, IOError):
1687 raise util.Abort(_("unable to read %s") % filename)
1686 raise util.Abort(_("unable to read %s") % filename)
1688 if not patchname:
1687 if not patchname:
1689 patchname = normname(os.path.basename(filename))
1688 patchname = normname(os.path.basename(filename))
1690 self.check_reserved_name(patchname)
1689 self.check_reserved_name(patchname)
1691 checkfile(patchname)
1690 checkfile(patchname)
1692 patchf = self.opener(patchname, "w")
1691 patchf = self.opener(patchname, "w")
1693 patchf.write(text)
1692 patchf.write(text)
1694 if not force:
1693 if not force:
1695 checkseries(patchname)
1694 checkseries(patchname)
1696 if patchname not in self.series:
1695 if patchname not in self.series:
1697 index = self.full_series_end() + i
1696 index = self.full_series_end() + i
1698 self.full_series[index:index] = [patchname]
1697 self.full_series[index:index] = [patchname]
1699 self.parse_series()
1698 self.parse_series()
1700 self.ui.warn(_("adding %s to series file\n") % patchname)
1699 self.ui.warn(_("adding %s to series file\n") % patchname)
1701 added.append(patchname)
1700 added.append(patchname)
1702 patchname = None
1701 patchname = None
1703 self.series_dirty = 1
1702 self.series_dirty = 1
1704 qrepo = self.qrepo()
1703 qrepo = self.qrepo()
1705 if qrepo:
1704 if qrepo:
1706 qrepo.add(added)
1705 qrepo.add(added)
1707
1706
1708 def delete(ui, repo, *patches, **opts):
1707 def delete(ui, repo, *patches, **opts):
1709 """remove patches from queue
1708 """remove patches from queue
1710
1709
1711 The patches must not be applied, and at least one patch is required. With
1710 The patches must not be applied, and at least one patch is required. With
1712 -k/--keep, the patch files are preserved in the patch directory.
1711 -k/--keep, the patch files are preserved in the patch directory.
1713
1712
1714 To stop managing a patch and move it into permanent history,
1713 To stop managing a patch and move it into permanent history,
1715 use the qfinish command."""
1714 use the qfinish command."""
1716 q = repo.mq
1715 q = repo.mq
1717 q.delete(repo, patches, opts)
1716 q.delete(repo, patches, opts)
1718 q.save_dirty()
1717 q.save_dirty()
1719 return 0
1718 return 0
1720
1719
1721 def applied(ui, repo, patch=None, **opts):
1720 def applied(ui, repo, patch=None, **opts):
1722 """print the patches already applied"""
1721 """print the patches already applied"""
1723
1722
1724 q = repo.mq
1723 q = repo.mq
1725 l = len(q.applied)
1724 l = len(q.applied)
1726
1725
1727 if patch:
1726 if patch:
1728 if patch not in q.series:
1727 if patch not in q.series:
1729 raise util.Abort(_("patch %s is not in series file") % patch)
1728 raise util.Abort(_("patch %s is not in series file") % patch)
1730 end = q.series.index(patch) + 1
1729 end = q.series.index(patch) + 1
1731 else:
1730 else:
1732 end = q.series_end(True)
1731 end = q.series_end(True)
1733
1732
1734 if opts.get('last') and not end:
1733 if opts.get('last') and not end:
1735 ui.write(_("no patches applied\n"))
1734 ui.write(_("no patches applied\n"))
1736 return 1
1735 return 1
1737 elif opts.get('last') and end == 1:
1736 elif opts.get('last') and end == 1:
1738 ui.write(_("only one patch applied\n"))
1737 ui.write(_("only one patch applied\n"))
1739 return 1
1738 return 1
1740 elif opts.get('last'):
1739 elif opts.get('last'):
1741 start = end - 2
1740 start = end - 2
1742 end = 1
1741 end = 1
1743 else:
1742 else:
1744 start = 0
1743 start = 0
1745
1744
1746 return q.qseries(repo, length=end, start=start, status='A',
1745 return q.qseries(repo, length=end, start=start, status='A',
1747 summary=opts.get('summary'))
1746 summary=opts.get('summary'))
1748
1747
1749 def unapplied(ui, repo, patch=None, **opts):
1748 def unapplied(ui, repo, patch=None, **opts):
1750 """print the patches not yet applied"""
1749 """print the patches not yet applied"""
1751
1750
1752 q = repo.mq
1751 q = repo.mq
1753 if patch:
1752 if patch:
1754 if patch not in q.series:
1753 if patch not in q.series:
1755 raise util.Abort(_("patch %s is not in series file") % patch)
1754 raise util.Abort(_("patch %s is not in series file") % patch)
1756 start = q.series.index(patch) + 1
1755 start = q.series.index(patch) + 1
1757 else:
1756 else:
1758 start = q.series_end(True)
1757 start = q.series_end(True)
1759
1758
1760 if start == len(q.series) and opts.get('first'):
1759 if start == len(q.series) and opts.get('first'):
1761 ui.write(_("all patches applied\n"))
1760 ui.write(_("all patches applied\n"))
1762 return 1
1761 return 1
1763
1762
1764 length = opts.get('first') and 1 or None
1763 length = opts.get('first') and 1 or None
1765 return q.qseries(repo, start=start, length=length, status='U',
1764 return q.qseries(repo, start=start, length=length, status='U',
1766 summary=opts.get('summary'))
1765 summary=opts.get('summary'))
1767
1766
1768 def qimport(ui, repo, *filename, **opts):
1767 def qimport(ui, repo, *filename, **opts):
1769 """import a patch
1768 """import a patch
1770
1769
1771 The patch is inserted into the series after the last applied
1770 The patch is inserted into the series after the last applied
1772 patch. If no patches have been applied, qimport prepends the patch
1771 patch. If no patches have been applied, qimport prepends the patch
1773 to the series.
1772 to the series.
1774
1773
1775 The patch will have the same name as its source file unless you
1774 The patch will have the same name as its source file unless you
1776 give it a new one with -n/--name.
1775 give it a new one with -n/--name.
1777
1776
1778 You can register an existing patch inside the patch directory with
1777 You can register an existing patch inside the patch directory with
1779 the -e/--existing flag.
1778 the -e/--existing flag.
1780
1779
1781 With -f/--force, an existing patch of the same name will be
1780 With -f/--force, an existing patch of the same name will be
1782 overwritten.
1781 overwritten.
1783
1782
1784 An existing changeset may be placed under mq control with -r/--rev
1783 An existing changeset may be placed under mq control with -r/--rev
1785 (e.g. qimport --rev tip -n patch will place tip under mq control).
1784 (e.g. qimport --rev tip -n patch will place tip under mq control).
1786 With -g/--git, patches imported with --rev will use the git diff
1785 With -g/--git, patches imported with --rev will use the git diff
1787 format. See the diffs help topic for information on why this is
1786 format. See the diffs help topic for information on why this is
1788 important for preserving rename/copy information and permission
1787 important for preserving rename/copy information and permission
1789 changes.
1788 changes.
1790
1789
1791 To import a patch from standard input, pass - as the patch file.
1790 To import a patch from standard input, pass - as the patch file.
1792 When importing from standard input, a patch name must be specified
1791 When importing from standard input, a patch name must be specified
1793 using the --name flag.
1792 using the --name flag.
1794 """
1793 """
1795 q = repo.mq
1794 q = repo.mq
1796 q.qimport(repo, filename, patchname=opts['name'],
1795 q.qimport(repo, filename, patchname=opts['name'],
1797 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1796 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1798 git=opts['git'])
1797 git=opts['git'])
1799 q.save_dirty()
1798 q.save_dirty()
1800
1799
1801 if opts.get('push') and not opts.get('rev'):
1800 if opts.get('push') and not opts.get('rev'):
1802 return q.push(repo, None)
1801 return q.push(repo, None)
1803 return 0
1802 return 0
1804
1803
1805 def qinit(ui, repo, create):
1804 def qinit(ui, repo, create):
1806 """initialize a new queue repository
1805 """initialize a new queue repository
1807
1806
1808 This command also creates a series file for ordering patches, and
1807 This command also creates a series file for ordering patches, and
1809 an mq-specific .hgignore file in the queue repository, to exclude
1808 an mq-specific .hgignore file in the queue repository, to exclude
1810 the status and guards files (these contain mostly transient state)."""
1809 the status and guards files (these contain mostly transient state)."""
1811 q = repo.mq
1810 q = repo.mq
1812 r = q.init(repo, create)
1811 r = q.init(repo, create)
1813 q.save_dirty()
1812 q.save_dirty()
1814 if r:
1813 if r:
1815 if not os.path.exists(r.wjoin('.hgignore')):
1814 if not os.path.exists(r.wjoin('.hgignore')):
1816 fp = r.wopener('.hgignore', 'w')
1815 fp = r.wopener('.hgignore', 'w')
1817 fp.write('^\\.hg\n')
1816 fp.write('^\\.hg\n')
1818 fp.write('^\\.mq\n')
1817 fp.write('^\\.mq\n')
1819 fp.write('syntax: glob\n')
1818 fp.write('syntax: glob\n')
1820 fp.write('status\n')
1819 fp.write('status\n')
1821 fp.write('guards\n')
1820 fp.write('guards\n')
1822 fp.close()
1821 fp.close()
1823 if not os.path.exists(r.wjoin('series')):
1822 if not os.path.exists(r.wjoin('series')):
1824 r.wopener('series', 'w').close()
1823 r.wopener('series', 'w').close()
1825 r.add(['.hgignore', 'series'])
1824 r.add(['.hgignore', 'series'])
1826 commands.add(ui, r)
1825 commands.add(ui, r)
1827 return 0
1826 return 0
1828
1827
1829 def init(ui, repo, **opts):
1828 def init(ui, repo, **opts):
1830 """init a new queue repository (DEPRECATED)
1829 """init a new queue repository (DEPRECATED)
1831
1830
1832 The queue repository is unversioned by default. If
1831 The queue repository is unversioned by default. If
1833 -c/--create-repo is specified, qinit will create a separate nested
1832 -c/--create-repo is specified, qinit will create a separate nested
1834 repository for patches (qinit -c may also be run later to convert
1833 repository for patches (qinit -c may also be run later to convert
1835 an unversioned patch repository into a versioned one). You can use
1834 an unversioned patch repository into a versioned one). You can use
1836 qcommit to commit changes to this queue repository.
1835 qcommit to commit changes to this queue repository.
1837
1836
1838 This command is deprecated. Without -c, it's implied by other relevant
1837 This command is deprecated. Without -c, it's implied by other relevant
1839 commands. With -c, use :hg:`init --mq` instead."""
1838 commands. With -c, use :hg:`init --mq` instead."""
1840 return qinit(ui, repo, create=opts['create_repo'])
1839 return qinit(ui, repo, create=opts['create_repo'])
1841
1840
1842 def clone(ui, source, dest=None, **opts):
1841 def clone(ui, source, dest=None, **opts):
1843 '''clone main and patch repository at same time
1842 '''clone main and patch repository at same time
1844
1843
1845 If source is local, destination will have no patches applied. If
1844 If source is local, destination will have no patches applied. If
1846 source is remote, this command can not check if patches are
1845 source is remote, this command can not check if patches are
1847 applied in source, so cannot guarantee that patches are not
1846 applied in source, so cannot guarantee that patches are not
1848 applied in destination. If you clone remote repository, be sure
1847 applied in destination. If you clone remote repository, be sure
1849 before that it has no patches applied.
1848 before that it has no patches applied.
1850
1849
1851 Source patch repository is looked for in <src>/.hg/patches by
1850 Source patch repository is looked for in <src>/.hg/patches by
1852 default. Use -p <url> to change.
1851 default. Use -p <url> to change.
1853
1852
1854 The patch directory must be a nested Mercurial repository, as
1853 The patch directory must be a nested Mercurial repository, as
1855 would be created by :hg:`init --mq`.
1854 would be created by :hg:`init --mq`.
1856 '''
1855 '''
1857 def patchdir(repo):
1856 def patchdir(repo):
1858 url = repo.url()
1857 url = repo.url()
1859 if url.endswith('/'):
1858 if url.endswith('/'):
1860 url = url[:-1]
1859 url = url[:-1]
1861 return url + '/.hg/patches'
1860 return url + '/.hg/patches'
1862 if dest is None:
1861 if dest is None:
1863 dest = hg.defaultdest(source)
1862 dest = hg.defaultdest(source)
1864 sr = hg.repository(cmdutil.remoteui(ui, opts), ui.expandpath(source))
1863 sr = hg.repository(cmdutil.remoteui(ui, opts), ui.expandpath(source))
1865 if opts['patches']:
1864 if opts['patches']:
1866 patchespath = ui.expandpath(opts['patches'])
1865 patchespath = ui.expandpath(opts['patches'])
1867 else:
1866 else:
1868 patchespath = patchdir(sr)
1867 patchespath = patchdir(sr)
1869 try:
1868 try:
1870 hg.repository(ui, patchespath)
1869 hg.repository(ui, patchespath)
1871 except error.RepoError:
1870 except error.RepoError:
1872 raise util.Abort(_('versioned patch repository not found'
1871 raise util.Abort(_('versioned patch repository not found'
1873 ' (see init --mq)'))
1872 ' (see init --mq)'))
1874 qbase, destrev = None, None
1873 qbase, destrev = None, None
1875 if sr.local():
1874 if sr.local():
1876 if sr.mq.applied:
1875 if sr.mq.applied:
1877 qbase = sr.mq.applied[0].node
1876 qbase = sr.mq.applied[0].node
1878 if not hg.islocal(dest):
1877 if not hg.islocal(dest):
1879 heads = set(sr.heads())
1878 heads = set(sr.heads())
1880 destrev = list(heads.difference(sr.heads(qbase)))
1879 destrev = list(heads.difference(sr.heads(qbase)))
1881 destrev.append(sr.changelog.parents(qbase)[0])
1880 destrev.append(sr.changelog.parents(qbase)[0])
1882 elif sr.capable('lookup'):
1881 elif sr.capable('lookup'):
1883 try:
1882 try:
1884 qbase = sr.lookup('qbase')
1883 qbase = sr.lookup('qbase')
1885 except error.RepoError:
1884 except error.RepoError:
1886 pass
1885 pass
1887 ui.note(_('cloning main repository\n'))
1886 ui.note(_('cloning main repository\n'))
1888 sr, dr = hg.clone(ui, sr.url(), dest,
1887 sr, dr = hg.clone(ui, sr.url(), dest,
1889 pull=opts['pull'],
1888 pull=opts['pull'],
1890 rev=destrev,
1889 rev=destrev,
1891 update=False,
1890 update=False,
1892 stream=opts['uncompressed'])
1891 stream=opts['uncompressed'])
1893 ui.note(_('cloning patch repository\n'))
1892 ui.note(_('cloning patch repository\n'))
1894 hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1893 hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1895 pull=opts['pull'], update=not opts['noupdate'],
1894 pull=opts['pull'], update=not opts['noupdate'],
1896 stream=opts['uncompressed'])
1895 stream=opts['uncompressed'])
1897 if dr.local():
1896 if dr.local():
1898 if qbase:
1897 if qbase:
1899 ui.note(_('stripping applied patches from destination '
1898 ui.note(_('stripping applied patches from destination '
1900 'repository\n'))
1899 'repository\n'))
1901 dr.mq.strip(dr, qbase, update=False, backup=None)
1900 dr.mq.strip(dr, qbase, update=False, backup=None)
1902 if not opts['noupdate']:
1901 if not opts['noupdate']:
1903 ui.note(_('updating destination repository\n'))
1902 ui.note(_('updating destination repository\n'))
1904 hg.update(dr, dr.changelog.tip())
1903 hg.update(dr, dr.changelog.tip())
1905
1904
1906 def commit(ui, repo, *pats, **opts):
1905 def commit(ui, repo, *pats, **opts):
1907 """commit changes in the queue repository (DEPRECATED)
1906 """commit changes in the queue repository (DEPRECATED)
1908
1907
1909 This command is deprecated; use :hg:`commit --mq` instead."""
1908 This command is deprecated; use :hg:`commit --mq` instead."""
1910 q = repo.mq
1909 q = repo.mq
1911 r = q.qrepo()
1910 r = q.qrepo()
1912 if not r:
1911 if not r:
1913 raise util.Abort('no queue repository')
1912 raise util.Abort('no queue repository')
1914 commands.commit(r.ui, r, *pats, **opts)
1913 commands.commit(r.ui, r, *pats, **opts)
1915
1914
1916 def series(ui, repo, **opts):
1915 def series(ui, repo, **opts):
1917 """print the entire series file"""
1916 """print the entire series file"""
1918 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1917 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1919 return 0
1918 return 0
1920
1919
1921 def top(ui, repo, **opts):
1920 def top(ui, repo, **opts):
1922 """print the name of the current patch"""
1921 """print the name of the current patch"""
1923 q = repo.mq
1922 q = repo.mq
1924 t = q.applied and q.series_end(True) or 0
1923 t = q.applied and q.series_end(True) or 0
1925 if t:
1924 if t:
1926 return q.qseries(repo, start=t - 1, length=1, status='A',
1925 return q.qseries(repo, start=t - 1, length=1, status='A',
1927 summary=opts.get('summary'))
1926 summary=opts.get('summary'))
1928 else:
1927 else:
1929 ui.write(_("no patches applied\n"))
1928 ui.write(_("no patches applied\n"))
1930 return 1
1929 return 1
1931
1930
1932 def next(ui, repo, **opts):
1931 def next(ui, repo, **opts):
1933 """print the name of the next patch"""
1932 """print the name of the next patch"""
1934 q = repo.mq
1933 q = repo.mq
1935 end = q.series_end()
1934 end = q.series_end()
1936 if end == len(q.series):
1935 if end == len(q.series):
1937 ui.write(_("all patches applied\n"))
1936 ui.write(_("all patches applied\n"))
1938 return 1
1937 return 1
1939 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1938 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1940
1939
1941 def prev(ui, repo, **opts):
1940 def prev(ui, repo, **opts):
1942 """print the name of the previous patch"""
1941 """print the name of the previous patch"""
1943 q = repo.mq
1942 q = repo.mq
1944 l = len(q.applied)
1943 l = len(q.applied)
1945 if l == 1:
1944 if l == 1:
1946 ui.write(_("only one patch applied\n"))
1945 ui.write(_("only one patch applied\n"))
1947 return 1
1946 return 1
1948 if not l:
1947 if not l:
1949 ui.write(_("no patches applied\n"))
1948 ui.write(_("no patches applied\n"))
1950 return 1
1949 return 1
1951 return q.qseries(repo, start=l - 2, length=1, status='A',
1950 return q.qseries(repo, start=l - 2, length=1, status='A',
1952 summary=opts.get('summary'))
1951 summary=opts.get('summary'))
1953
1952
1954 def setupheaderopts(ui, opts):
1953 def setupheaderopts(ui, opts):
1955 if not opts.get('user') and opts.get('currentuser'):
1954 if not opts.get('user') and opts.get('currentuser'):
1956 opts['user'] = ui.username()
1955 opts['user'] = ui.username()
1957 if not opts.get('date') and opts.get('currentdate'):
1956 if not opts.get('date') and opts.get('currentdate'):
1958 opts['date'] = "%d %d" % util.makedate()
1957 opts['date'] = "%d %d" % util.makedate()
1959
1958
1960 def new(ui, repo, patch, *args, **opts):
1959 def new(ui, repo, patch, *args, **opts):
1961 """create a new patch
1960 """create a new patch
1962
1961
1963 qnew creates a new patch on top of the currently-applied patch (if
1962 qnew creates a new patch on top of the currently-applied patch (if
1964 any). The patch will be initialized with any outstanding changes
1963 any). The patch will be initialized with any outstanding changes
1965 in the working directory. You may also use -I/--include,
1964 in the working directory. You may also use -I/--include,
1966 -X/--exclude, and/or a list of files after the patch name to add
1965 -X/--exclude, and/or a list of files after the patch name to add
1967 only changes to matching files to the new patch, leaving the rest
1966 only changes to matching files to the new patch, leaving the rest
1968 as uncommitted modifications.
1967 as uncommitted modifications.
1969
1968
1970 -u/--user and -d/--date can be used to set the (given) user and
1969 -u/--user and -d/--date can be used to set the (given) user and
1971 date, respectively. -U/--currentuser and -D/--currentdate set user
1970 date, respectively. -U/--currentuser and -D/--currentdate set user
1972 to current user and date to current date.
1971 to current user and date to current date.
1973
1972
1974 -e/--edit, -m/--message or -l/--logfile set the patch header as
1973 -e/--edit, -m/--message or -l/--logfile set the patch header as
1975 well as the commit message. If none is specified, the header is
1974 well as the commit message. If none is specified, the header is
1976 empty and the commit message is '[mq]: PATCH'.
1975 empty and the commit message is '[mq]: PATCH'.
1977
1976
1978 Use the -g/--git option to keep the patch in the git extended diff
1977 Use the -g/--git option to keep the patch in the git extended diff
1979 format. Read the diffs help topic for more information on why this
1978 format. Read the diffs help topic for more information on why this
1980 is important for preserving permission changes and copy/rename
1979 is important for preserving permission changes and copy/rename
1981 information.
1980 information.
1982 """
1981 """
1983 msg = cmdutil.logmessage(opts)
1982 msg = cmdutil.logmessage(opts)
1984 def getmsg():
1983 def getmsg():
1985 return ui.edit(msg, ui.username())
1984 return ui.edit(msg, ui.username())
1986 q = repo.mq
1985 q = repo.mq
1987 opts['msg'] = msg
1986 opts['msg'] = msg
1988 if opts.get('edit'):
1987 if opts.get('edit'):
1989 opts['msg'] = getmsg
1988 opts['msg'] = getmsg
1990 else:
1989 else:
1991 opts['msg'] = msg
1990 opts['msg'] = msg
1992 setupheaderopts(ui, opts)
1991 setupheaderopts(ui, opts)
1993 q.new(repo, patch, *args, **opts)
1992 q.new(repo, patch, *args, **opts)
1994 q.save_dirty()
1993 q.save_dirty()
1995 return 0
1994 return 0
1996
1995
1997 def refresh(ui, repo, *pats, **opts):
1996 def refresh(ui, repo, *pats, **opts):
1998 """update the current patch
1997 """update the current patch
1999
1998
2000 If any file patterns are provided, the refreshed patch will
1999 If any file patterns are provided, the refreshed patch will
2001 contain only the modifications that match those patterns; the
2000 contain only the modifications that match those patterns; the
2002 remaining modifications will remain in the working directory.
2001 remaining modifications will remain in the working directory.
2003
2002
2004 If -s/--short is specified, files currently included in the patch
2003 If -s/--short is specified, files currently included in the patch
2005 will be refreshed just like matched files and remain in the patch.
2004 will be refreshed just like matched files and remain in the patch.
2006
2005
2007 hg add/remove/copy/rename work as usual, though you might want to
2006 hg add/remove/copy/rename work as usual, though you might want to
2008 use git-style patches (-g/--git or [diff] git=1) to track copies
2007 use git-style patches (-g/--git or [diff] git=1) to track copies
2009 and renames. See the diffs help topic for more information on the
2008 and renames. See the diffs help topic for more information on the
2010 git diff format.
2009 git diff format.
2011 """
2010 """
2012 q = repo.mq
2011 q = repo.mq
2013 message = cmdutil.logmessage(opts)
2012 message = cmdutil.logmessage(opts)
2014 if opts['edit']:
2013 if opts['edit']:
2015 if not q.applied:
2014 if not q.applied:
2016 ui.write(_("no patches applied\n"))
2015 ui.write(_("no patches applied\n"))
2017 return 1
2016 return 1
2018 if message:
2017 if message:
2019 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2018 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2020 patch = q.applied[-1].name
2019 patch = q.applied[-1].name
2021 ph = patchheader(q.join(patch), q.plainmode)
2020 ph = patchheader(q.join(patch), q.plainmode)
2022 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
2021 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
2023 setupheaderopts(ui, opts)
2022 setupheaderopts(ui, opts)
2024 ret = q.refresh(repo, pats, msg=message, **opts)
2023 ret = q.refresh(repo, pats, msg=message, **opts)
2025 q.save_dirty()
2024 q.save_dirty()
2026 return ret
2025 return ret
2027
2026
2028 def diff(ui, repo, *pats, **opts):
2027 def diff(ui, repo, *pats, **opts):
2029 """diff of the current patch and subsequent modifications
2028 """diff of the current patch and subsequent modifications
2030
2029
2031 Shows a diff which includes the current patch as well as any
2030 Shows a diff which includes the current patch as well as any
2032 changes which have been made in the working directory since the
2031 changes which have been made in the working directory since the
2033 last refresh (thus showing what the current patch would become
2032 last refresh (thus showing what the current patch would become
2034 after a qrefresh).
2033 after a qrefresh).
2035
2034
2036 Use :hg:`diff` if you only want to see the changes made since the
2035 Use :hg:`diff` if you only want to see the changes made since the
2037 last qrefresh, or :hg:`export qtip` if you want to see changes
2036 last qrefresh, or :hg:`export qtip` if you want to see changes
2038 made by the current patch without including changes made since the
2037 made by the current patch without including changes made since the
2039 qrefresh.
2038 qrefresh.
2040 """
2039 """
2041 repo.mq.diff(repo, pats, opts)
2040 repo.mq.diff(repo, pats, opts)
2042 return 0
2041 return 0
2043
2042
2044 def fold(ui, repo, *files, **opts):
2043 def fold(ui, repo, *files, **opts):
2045 """fold the named patches into the current patch
2044 """fold the named patches into the current patch
2046
2045
2047 Patches must not yet be applied. Each patch will be successively
2046 Patches must not yet be applied. Each patch will be successively
2048 applied to the current patch in the order given. If all the
2047 applied to the current patch in the order given. If all the
2049 patches apply successfully, the current patch will be refreshed
2048 patches apply successfully, the current patch will be refreshed
2050 with the new cumulative patch, and the folded patches will be
2049 with the new cumulative patch, and the folded patches will be
2051 deleted. With -k/--keep, the folded patch files will not be
2050 deleted. With -k/--keep, the folded patch files will not be
2052 removed afterwards.
2051 removed afterwards.
2053
2052
2054 The header for each folded patch will be concatenated with the
2053 The header for each folded patch will be concatenated with the
2055 current patch header, separated by a line of '* * *'."""
2054 current patch header, separated by a line of '* * *'."""
2056
2055
2057 q = repo.mq
2056 q = repo.mq
2058
2057
2059 if not files:
2058 if not files:
2060 raise util.Abort(_('qfold requires at least one patch name'))
2059 raise util.Abort(_('qfold requires at least one patch name'))
2061 if not q.check_toppatch(repo)[0]:
2060 if not q.check_toppatch(repo)[0]:
2062 raise util.Abort(_('No patches applied'))
2061 raise util.Abort(_('No patches applied'))
2063 q.check_localchanges(repo)
2062 q.check_localchanges(repo)
2064
2063
2065 message = cmdutil.logmessage(opts)
2064 message = cmdutil.logmessage(opts)
2066 if opts['edit']:
2065 if opts['edit']:
2067 if message:
2066 if message:
2068 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2067 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2069
2068
2070 parent = q.lookup('qtip')
2069 parent = q.lookup('qtip')
2071 patches = []
2070 patches = []
2072 messages = []
2071 messages = []
2073 for f in files:
2072 for f in files:
2074 p = q.lookup(f)
2073 p = q.lookup(f)
2075 if p in patches or p == parent:
2074 if p in patches or p == parent:
2076 ui.warn(_('Skipping already folded patch %s') % p)
2075 ui.warn(_('Skipping already folded patch %s') % p)
2077 if q.isapplied(p):
2076 if q.isapplied(p):
2078 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2077 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2079 patches.append(p)
2078 patches.append(p)
2080
2079
2081 for p in patches:
2080 for p in patches:
2082 if not message:
2081 if not message:
2083 ph = patchheader(q.join(p), q.plainmode)
2082 ph = patchheader(q.join(p), q.plainmode)
2084 if ph.message:
2083 if ph.message:
2085 messages.append(ph.message)
2084 messages.append(ph.message)
2086 pf = q.join(p)
2085 pf = q.join(p)
2087 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2086 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2088 if not patchsuccess:
2087 if not patchsuccess:
2089 raise util.Abort(_('Error folding patch %s') % p)
2088 raise util.Abort(_('Error folding patch %s') % p)
2090 patch.updatedir(ui, repo, files)
2089 patch.updatedir(ui, repo, files)
2091
2090
2092 if not message:
2091 if not message:
2093 ph = patchheader(q.join(parent), q.plainmode)
2092 ph = patchheader(q.join(parent), q.plainmode)
2094 message, user = ph.message, ph.user
2093 message, user = ph.message, ph.user
2095 for msg in messages:
2094 for msg in messages:
2096 message.append('* * *')
2095 message.append('* * *')
2097 message.extend(msg)
2096 message.extend(msg)
2098 message = '\n'.join(message)
2097 message = '\n'.join(message)
2099
2098
2100 if opts['edit']:
2099 if opts['edit']:
2101 message = ui.edit(message, user or ui.username())
2100 message = ui.edit(message, user or ui.username())
2102
2101
2103 diffopts = q.patchopts(q.diffopts(), *patches)
2102 diffopts = q.patchopts(q.diffopts(), *patches)
2104 q.refresh(repo, msg=message, git=diffopts.git)
2103 q.refresh(repo, msg=message, git=diffopts.git)
2105 q.delete(repo, patches, opts)
2104 q.delete(repo, patches, opts)
2106 q.save_dirty()
2105 q.save_dirty()
2107
2106
2108 def goto(ui, repo, patch, **opts):
2107 def goto(ui, repo, patch, **opts):
2109 '''push or pop patches until named patch is at top of stack'''
2108 '''push or pop patches until named patch is at top of stack'''
2110 q = repo.mq
2109 q = repo.mq
2111 patch = q.lookup(patch)
2110 patch = q.lookup(patch)
2112 if q.isapplied(patch):
2111 if q.isapplied(patch):
2113 ret = q.pop(repo, patch, force=opts['force'])
2112 ret = q.pop(repo, patch, force=opts['force'])
2114 else:
2113 else:
2115 ret = q.push(repo, patch, force=opts['force'])
2114 ret = q.push(repo, patch, force=opts['force'])
2116 q.save_dirty()
2115 q.save_dirty()
2117 return ret
2116 return ret
2118
2117
2119 def guard(ui, repo, *args, **opts):
2118 def guard(ui, repo, *args, **opts):
2120 '''set or print guards for a patch
2119 '''set or print guards for a patch
2121
2120
2122 Guards control whether a patch can be pushed. A patch with no
2121 Guards control whether a patch can be pushed. A patch with no
2123 guards is always pushed. A patch with a positive guard ("+foo") is
2122 guards is always pushed. A patch with a positive guard ("+foo") is
2124 pushed only if the qselect command has activated it. A patch with
2123 pushed only if the qselect command has activated it. A patch with
2125 a negative guard ("-foo") is never pushed if the qselect command
2124 a negative guard ("-foo") is never pushed if the qselect command
2126 has activated it.
2125 has activated it.
2127
2126
2128 With no arguments, print the currently active guards.
2127 With no arguments, print the currently active guards.
2129 With arguments, set guards for the named patch.
2128 With arguments, set guards for the named patch.
2130 NOTE: Specifying negative guards now requires '--'.
2129 NOTE: Specifying negative guards now requires '--'.
2131
2130
2132 To set guards on another patch::
2131 To set guards on another patch::
2133
2132
2134 hg qguard other.patch -- +2.6.17 -stable
2133 hg qguard other.patch -- +2.6.17 -stable
2135 '''
2134 '''
2136 def status(idx):
2135 def status(idx):
2137 guards = q.series_guards[idx] or ['unguarded']
2136 guards = q.series_guards[idx] or ['unguarded']
2138 ui.write('%s: ' % ui.label(q.series[idx], 'qguard.patch'))
2137 ui.write('%s: ' % ui.label(q.series[idx], 'qguard.patch'))
2139 for i, guard in enumerate(guards):
2138 for i, guard in enumerate(guards):
2140 if guard.startswith('+'):
2139 if guard.startswith('+'):
2141 ui.write(guard, label='qguard.positive')
2140 ui.write(guard, label='qguard.positive')
2142 elif guard.startswith('-'):
2141 elif guard.startswith('-'):
2143 ui.write(guard, label='qguard.negative')
2142 ui.write(guard, label='qguard.negative')
2144 else:
2143 else:
2145 ui.write(guard, label='qguard.unguarded')
2144 ui.write(guard, label='qguard.unguarded')
2146 if i != len(guards) - 1:
2145 if i != len(guards) - 1:
2147 ui.write(' ')
2146 ui.write(' ')
2148 ui.write('\n')
2147 ui.write('\n')
2149 q = repo.mq
2148 q = repo.mq
2150 patch = None
2149 patch = None
2151 args = list(args)
2150 args = list(args)
2152 if opts['list']:
2151 if opts['list']:
2153 if args or opts['none']:
2152 if args or opts['none']:
2154 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2153 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2155 for i in xrange(len(q.series)):
2154 for i in xrange(len(q.series)):
2156 status(i)
2155 status(i)
2157 return
2156 return
2158 if not args or args[0][0:1] in '-+':
2157 if not args or args[0][0:1] in '-+':
2159 if not q.applied:
2158 if not q.applied:
2160 raise util.Abort(_('no patches applied'))
2159 raise util.Abort(_('no patches applied'))
2161 patch = q.applied[-1].name
2160 patch = q.applied[-1].name
2162 if patch is None and args[0][0:1] not in '-+':
2161 if patch is None and args[0][0:1] not in '-+':
2163 patch = args.pop(0)
2162 patch = args.pop(0)
2164 if patch is None:
2163 if patch is None:
2165 raise util.Abort(_('no patch to work with'))
2164 raise util.Abort(_('no patch to work with'))
2166 if args or opts['none']:
2165 if args or opts['none']:
2167 idx = q.find_series(patch)
2166 idx = q.find_series(patch)
2168 if idx is None:
2167 if idx is None:
2169 raise util.Abort(_('no patch named %s') % patch)
2168 raise util.Abort(_('no patch named %s') % patch)
2170 q.set_guards(idx, args)
2169 q.set_guards(idx, args)
2171 q.save_dirty()
2170 q.save_dirty()
2172 else:
2171 else:
2173 status(q.series.index(q.lookup(patch)))
2172 status(q.series.index(q.lookup(patch)))
2174
2173
2175 def header(ui, repo, patch=None):
2174 def header(ui, repo, patch=None):
2176 """print the header of the topmost or specified patch"""
2175 """print the header of the topmost or specified patch"""
2177 q = repo.mq
2176 q = repo.mq
2178
2177
2179 if patch:
2178 if patch:
2180 patch = q.lookup(patch)
2179 patch = q.lookup(patch)
2181 else:
2180 else:
2182 if not q.applied:
2181 if not q.applied:
2183 ui.write(_('no patches applied\n'))
2182 ui.write(_('no patches applied\n'))
2184 return 1
2183 return 1
2185 patch = q.lookup('qtip')
2184 patch = q.lookup('qtip')
2186 ph = patchheader(q.join(patch), q.plainmode)
2185 ph = patchheader(q.join(patch), q.plainmode)
2187
2186
2188 ui.write('\n'.join(ph.message) + '\n')
2187 ui.write('\n'.join(ph.message) + '\n')
2189
2188
2190 def lastsavename(path):
2189 def lastsavename(path):
2191 (directory, base) = os.path.split(path)
2190 (directory, base) = os.path.split(path)
2192 names = os.listdir(directory)
2191 names = os.listdir(directory)
2193 namere = re.compile("%s.([0-9]+)" % base)
2192 namere = re.compile("%s.([0-9]+)" % base)
2194 maxindex = None
2193 maxindex = None
2195 maxname = None
2194 maxname = None
2196 for f in names:
2195 for f in names:
2197 m = namere.match(f)
2196 m = namere.match(f)
2198 if m:
2197 if m:
2199 index = int(m.group(1))
2198 index = int(m.group(1))
2200 if maxindex is None or index > maxindex:
2199 if maxindex is None or index > maxindex:
2201 maxindex = index
2200 maxindex = index
2202 maxname = f
2201 maxname = f
2203 if maxname:
2202 if maxname:
2204 return (os.path.join(directory, maxname), maxindex)
2203 return (os.path.join(directory, maxname), maxindex)
2205 return (None, None)
2204 return (None, None)
2206
2205
2207 def savename(path):
2206 def savename(path):
2208 (last, index) = lastsavename(path)
2207 (last, index) = lastsavename(path)
2209 if last is None:
2208 if last is None:
2210 index = 0
2209 index = 0
2211 newpath = path + ".%d" % (index + 1)
2210 newpath = path + ".%d" % (index + 1)
2212 return newpath
2211 return newpath
2213
2212
2214 def push(ui, repo, patch=None, **opts):
2213 def push(ui, repo, patch=None, **opts):
2215 """push the next patch onto the stack
2214 """push the next patch onto the stack
2216
2215
2217 When -f/--force is applied, all local changes in patched files
2216 When -f/--force is applied, all local changes in patched files
2218 will be lost.
2217 will be lost.
2219 """
2218 """
2220 q = repo.mq
2219 q = repo.mq
2221 mergeq = None
2220 mergeq = None
2222
2221
2223 if opts['merge']:
2222 if opts['merge']:
2224 if opts['name']:
2223 if opts['name']:
2225 newpath = repo.join(opts['name'])
2224 newpath = repo.join(opts['name'])
2226 else:
2225 else:
2227 newpath, i = lastsavename(q.path)
2226 newpath, i = lastsavename(q.path)
2228 if not newpath:
2227 if not newpath:
2229 ui.warn(_("no saved queues found, please use -n\n"))
2228 ui.warn(_("no saved queues found, please use -n\n"))
2230 return 1
2229 return 1
2231 mergeq = queue(ui, repo.join(""), newpath)
2230 mergeq = queue(ui, repo.join(""), newpath)
2232 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2231 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2233 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2232 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2234 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'))
2233 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'))
2235 return ret
2234 return ret
2236
2235
2237 def pop(ui, repo, patch=None, **opts):
2236 def pop(ui, repo, patch=None, **opts):
2238 """pop the current patch off the stack
2237 """pop the current patch off the stack
2239
2238
2240 By default, pops off the top of the patch stack. If given a patch
2239 By default, pops off the top of the patch stack. If given a patch
2241 name, keeps popping off patches until the named patch is at the
2240 name, keeps popping off patches until the named patch is at the
2242 top of the stack.
2241 top of the stack.
2243 """
2242 """
2244 localupdate = True
2243 localupdate = True
2245 if opts['name']:
2244 if opts['name']:
2246 q = queue(ui, repo.join(""), repo.join(opts['name']))
2245 q = queue(ui, repo.join(""), repo.join(opts['name']))
2247 ui.warn(_('using patch queue: %s\n') % q.path)
2246 ui.warn(_('using patch queue: %s\n') % q.path)
2248 localupdate = False
2247 localupdate = False
2249 else:
2248 else:
2250 q = repo.mq
2249 q = repo.mq
2251 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2250 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2252 all=opts['all'])
2251 all=opts['all'])
2253 q.save_dirty()
2252 q.save_dirty()
2254 return ret
2253 return ret
2255
2254
2256 def rename(ui, repo, patch, name=None, **opts):
2255 def rename(ui, repo, patch, name=None, **opts):
2257 """rename a patch
2256 """rename a patch
2258
2257
2259 With one argument, renames the current patch to PATCH1.
2258 With one argument, renames the current patch to PATCH1.
2260 With two arguments, renames PATCH1 to PATCH2."""
2259 With two arguments, renames PATCH1 to PATCH2."""
2261
2260
2262 q = repo.mq
2261 q = repo.mq
2263
2262
2264 if not name:
2263 if not name:
2265 name = patch
2264 name = patch
2266 patch = None
2265 patch = None
2267
2266
2268 if patch:
2267 if patch:
2269 patch = q.lookup(patch)
2268 patch = q.lookup(patch)
2270 else:
2269 else:
2271 if not q.applied:
2270 if not q.applied:
2272 ui.write(_('no patches applied\n'))
2271 ui.write(_('no patches applied\n'))
2273 return
2272 return
2274 patch = q.lookup('qtip')
2273 patch = q.lookup('qtip')
2275 absdest = q.join(name)
2274 absdest = q.join(name)
2276 if os.path.isdir(absdest):
2275 if os.path.isdir(absdest):
2277 name = normname(os.path.join(name, os.path.basename(patch)))
2276 name = normname(os.path.join(name, os.path.basename(patch)))
2278 absdest = q.join(name)
2277 absdest = q.join(name)
2279 if os.path.exists(absdest):
2278 if os.path.exists(absdest):
2280 raise util.Abort(_('%s already exists') % absdest)
2279 raise util.Abort(_('%s already exists') % absdest)
2281
2280
2282 if name in q.series:
2281 if name in q.series:
2283 raise util.Abort(
2282 raise util.Abort(
2284 _('A patch named %s already exists in the series file') % name)
2283 _('A patch named %s already exists in the series file') % name)
2285
2284
2286 ui.note(_('renaming %s to %s\n') % (patch, name))
2285 ui.note(_('renaming %s to %s\n') % (patch, name))
2287 i = q.find_series(patch)
2286 i = q.find_series(patch)
2288 guards = q.guard_re.findall(q.full_series[i])
2287 guards = q.guard_re.findall(q.full_series[i])
2289 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2288 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2290 q.parse_series()
2289 q.parse_series()
2291 q.series_dirty = 1
2290 q.series_dirty = 1
2292
2291
2293 info = q.isapplied(patch)
2292 info = q.isapplied(patch)
2294 if info:
2293 if info:
2295 q.applied[info[0]] = statusentry(info[1], name)
2294 q.applied[info[0]] = statusentry(info[1], name)
2296 q.applied_dirty = 1
2295 q.applied_dirty = 1
2297
2296
2298 util.rename(q.join(patch), absdest)
2297 util.rename(q.join(patch), absdest)
2299 r = q.qrepo()
2298 r = q.qrepo()
2300 if r:
2299 if r:
2301 wlock = r.wlock()
2300 wlock = r.wlock()
2302 try:
2301 try:
2303 if r.dirstate[patch] == 'a':
2302 if r.dirstate[patch] == 'a':
2304 r.dirstate.forget(patch)
2303 r.dirstate.forget(patch)
2305 r.dirstate.add(name)
2304 r.dirstate.add(name)
2306 else:
2305 else:
2307 if r.dirstate[name] == 'r':
2306 if r.dirstate[name] == 'r':
2308 r.undelete([name])
2307 r.undelete([name])
2309 r.copy(patch, name)
2308 r.copy(patch, name)
2310 r.remove([patch], False)
2309 r.remove([patch], False)
2311 finally:
2310 finally:
2312 wlock.release()
2311 wlock.release()
2313
2312
2314 q.save_dirty()
2313 q.save_dirty()
2315
2314
2316 def restore(ui, repo, rev, **opts):
2315 def restore(ui, repo, rev, **opts):
2317 """restore the queue state saved by a revision (DEPRECATED)
2316 """restore the queue state saved by a revision (DEPRECATED)
2318
2317
2319 This command is deprecated, use rebase --mq instead."""
2318 This command is deprecated, use rebase --mq instead."""
2320 rev = repo.lookup(rev)
2319 rev = repo.lookup(rev)
2321 q = repo.mq
2320 q = repo.mq
2322 q.restore(repo, rev, delete=opts['delete'],
2321 q.restore(repo, rev, delete=opts['delete'],
2323 qupdate=opts['update'])
2322 qupdate=opts['update'])
2324 q.save_dirty()
2323 q.save_dirty()
2325 return 0
2324 return 0
2326
2325
2327 def save(ui, repo, **opts):
2326 def save(ui, repo, **opts):
2328 """save current queue state (DEPRECATED)
2327 """save current queue state (DEPRECATED)
2329
2328
2330 This command is deprecated, use rebase --mq instead."""
2329 This command is deprecated, use rebase --mq instead."""
2331 q = repo.mq
2330 q = repo.mq
2332 message = cmdutil.logmessage(opts)
2331 message = cmdutil.logmessage(opts)
2333 ret = q.save(repo, msg=message)
2332 ret = q.save(repo, msg=message)
2334 if ret:
2333 if ret:
2335 return ret
2334 return ret
2336 q.save_dirty()
2335 q.save_dirty()
2337 if opts['copy']:
2336 if opts['copy']:
2338 path = q.path
2337 path = q.path
2339 if opts['name']:
2338 if opts['name']:
2340 newpath = os.path.join(q.basepath, opts['name'])
2339 newpath = os.path.join(q.basepath, opts['name'])
2341 if os.path.exists(newpath):
2340 if os.path.exists(newpath):
2342 if not os.path.isdir(newpath):
2341 if not os.path.isdir(newpath):
2343 raise util.Abort(_('destination %s exists and is not '
2342 raise util.Abort(_('destination %s exists and is not '
2344 'a directory') % newpath)
2343 'a directory') % newpath)
2345 if not opts['force']:
2344 if not opts['force']:
2346 raise util.Abort(_('destination %s exists, '
2345 raise util.Abort(_('destination %s exists, '
2347 'use -f to force') % newpath)
2346 'use -f to force') % newpath)
2348 else:
2347 else:
2349 newpath = savename(path)
2348 newpath = savename(path)
2350 ui.warn(_("copy %s to %s\n") % (path, newpath))
2349 ui.warn(_("copy %s to %s\n") % (path, newpath))
2351 util.copyfiles(path, newpath)
2350 util.copyfiles(path, newpath)
2352 if opts['empty']:
2351 if opts['empty']:
2353 try:
2352 try:
2354 os.unlink(q.join(q.status_path))
2353 os.unlink(q.join(q.status_path))
2355 except:
2354 except:
2356 pass
2355 pass
2357 return 0
2356 return 0
2358
2357
2359 def strip(ui, repo, rev, **opts):
2358 def strip(ui, repo, rev, **opts):
2360 """strip a changeset and all its descendants from the repository
2359 """strip a changeset and all its descendants from the repository
2361
2360
2362 The strip command removes all changesets whose local revision
2361 The strip command removes all changesets whose local revision
2363 number is greater than or equal to REV, and then restores any
2362 number is greater than or equal to REV, and then restores any
2364 changesets that are not descendants of REV. If the working
2363 changesets that are not descendants of REV. If the working
2365 directory has uncommitted changes, the operation is aborted unless
2364 directory has uncommitted changes, the operation is aborted unless
2366 the --force flag is supplied.
2365 the --force flag is supplied.
2367
2366
2368 If a parent of the working directory is stripped, then the working
2367 If a parent of the working directory is stripped, then the working
2369 directory will automatically be updated to the most recent
2368 directory will automatically be updated to the most recent
2370 available ancestor of the stripped parent after the operation
2369 available ancestor of the stripped parent after the operation
2371 completes.
2370 completes.
2372
2371
2373 Any stripped changesets are stored in ``.hg/strip-backup`` as a
2372 Any stripped changesets are stored in ``.hg/strip-backup`` as a
2374 bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can
2373 bundle (see :hg:`help bundle` and :hg:`help unbundle`). They can
2375 be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`,
2374 be restored by running :hg:`unbundle .hg/strip-backup/BUNDLE`,
2376 where BUNDLE is the bundle file created by the strip. Note that
2375 where BUNDLE is the bundle file created by the strip. Note that
2377 the local revision numbers will in general be different after the
2376 the local revision numbers will in general be different after the
2378 restore.
2377 restore.
2379
2378
2380 Use the --nobackup option to discard the backup bundle once the
2379 Use the --nobackup option to discard the backup bundle once the
2381 operation completes.
2380 operation completes.
2382 """
2381 """
2383 backup = 'all'
2382 backup = 'all'
2384 if opts['backup']:
2383 if opts['backup']:
2385 backup = 'strip'
2384 backup = 'strip'
2386 elif opts['nobackup']:
2385 elif opts['nobackup']:
2387 backup = 'none'
2386 backup = 'none'
2388
2387
2389 rev = repo.lookup(rev)
2388 rev = repo.lookup(rev)
2390 p = repo.dirstate.parents()
2389 p = repo.dirstate.parents()
2391 cl = repo.changelog
2390 cl = repo.changelog
2392 update = True
2391 update = True
2393 if p[0] == nullid:
2392 if p[0] == nullid:
2394 update = False
2393 update = False
2395 elif p[1] == nullid and rev != cl.ancestor(p[0], rev):
2394 elif p[1] == nullid and rev != cl.ancestor(p[0], rev):
2396 update = False
2395 update = False
2397 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2396 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2398 update = False
2397 update = False
2399
2398
2400 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2399 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2401 return 0
2400 return 0
2402
2401
2403 def select(ui, repo, *args, **opts):
2402 def select(ui, repo, *args, **opts):
2404 '''set or print guarded patches to push
2403 '''set or print guarded patches to push
2405
2404
2406 Use the qguard command to set or print guards on patch, then use
2405 Use the qguard command to set or print guards on patch, then use
2407 qselect to tell mq which guards to use. A patch will be pushed if
2406 qselect to tell mq which guards to use. A patch will be pushed if
2408 it has no guards or any positive guards match the currently
2407 it has no guards or any positive guards match the currently
2409 selected guard, but will not be pushed if any negative guards
2408 selected guard, but will not be pushed if any negative guards
2410 match the current guard. For example::
2409 match the current guard. For example::
2411
2410
2412 qguard foo.patch -stable (negative guard)
2411 qguard foo.patch -stable (negative guard)
2413 qguard bar.patch +stable (positive guard)
2412 qguard bar.patch +stable (positive guard)
2414 qselect stable
2413 qselect stable
2415
2414
2416 This activates the "stable" guard. mq will skip foo.patch (because
2415 This activates the "stable" guard. mq will skip foo.patch (because
2417 it has a negative match) but push bar.patch (because it has a
2416 it has a negative match) but push bar.patch (because it has a
2418 positive match).
2417 positive match).
2419
2418
2420 With no arguments, prints the currently active guards.
2419 With no arguments, prints the currently active guards.
2421 With one argument, sets the active guard.
2420 With one argument, sets the active guard.
2422
2421
2423 Use -n/--none to deactivate guards (no other arguments needed).
2422 Use -n/--none to deactivate guards (no other arguments needed).
2424 When no guards are active, patches with positive guards are
2423 When no guards are active, patches with positive guards are
2425 skipped and patches with negative guards are pushed.
2424 skipped and patches with negative guards are pushed.
2426
2425
2427 qselect can change the guards on applied patches. It does not pop
2426 qselect can change the guards on applied patches. It does not pop
2428 guarded patches by default. Use --pop to pop back to the last
2427 guarded patches by default. Use --pop to pop back to the last
2429 applied patch that is not guarded. Use --reapply (which implies
2428 applied patch that is not guarded. Use --reapply (which implies
2430 --pop) to push back to the current patch afterwards, but skip
2429 --pop) to push back to the current patch afterwards, but skip
2431 guarded patches.
2430 guarded patches.
2432
2431
2433 Use -s/--series to print a list of all guards in the series file
2432 Use -s/--series to print a list of all guards in the series file
2434 (no other arguments needed). Use -v for more information.'''
2433 (no other arguments needed). Use -v for more information.'''
2435
2434
2436 q = repo.mq
2435 q = repo.mq
2437 guards = q.active()
2436 guards = q.active()
2438 if args or opts['none']:
2437 if args or opts['none']:
2439 old_unapplied = q.unapplied(repo)
2438 old_unapplied = q.unapplied(repo)
2440 old_guarded = [i for i in xrange(len(q.applied)) if
2439 old_guarded = [i for i in xrange(len(q.applied)) if
2441 not q.pushable(i)[0]]
2440 not q.pushable(i)[0]]
2442 q.set_active(args)
2441 q.set_active(args)
2443 q.save_dirty()
2442 q.save_dirty()
2444 if not args:
2443 if not args:
2445 ui.status(_('guards deactivated\n'))
2444 ui.status(_('guards deactivated\n'))
2446 if not opts['pop'] and not opts['reapply']:
2445 if not opts['pop'] and not opts['reapply']:
2447 unapplied = q.unapplied(repo)
2446 unapplied = q.unapplied(repo)
2448 guarded = [i for i in xrange(len(q.applied))
2447 guarded = [i for i in xrange(len(q.applied))
2449 if not q.pushable(i)[0]]
2448 if not q.pushable(i)[0]]
2450 if len(unapplied) != len(old_unapplied):
2449 if len(unapplied) != len(old_unapplied):
2451 ui.status(_('number of unguarded, unapplied patches has '
2450 ui.status(_('number of unguarded, unapplied patches has '
2452 'changed from %d to %d\n') %
2451 'changed from %d to %d\n') %
2453 (len(old_unapplied), len(unapplied)))
2452 (len(old_unapplied), len(unapplied)))
2454 if len(guarded) != len(old_guarded):
2453 if len(guarded) != len(old_guarded):
2455 ui.status(_('number of guarded, applied patches has changed '
2454 ui.status(_('number of guarded, applied patches has changed '
2456 'from %d to %d\n') %
2455 'from %d to %d\n') %
2457 (len(old_guarded), len(guarded)))
2456 (len(old_guarded), len(guarded)))
2458 elif opts['series']:
2457 elif opts['series']:
2459 guards = {}
2458 guards = {}
2460 noguards = 0
2459 noguards = 0
2461 for gs in q.series_guards:
2460 for gs in q.series_guards:
2462 if not gs:
2461 if not gs:
2463 noguards += 1
2462 noguards += 1
2464 for g in gs:
2463 for g in gs:
2465 guards.setdefault(g, 0)
2464 guards.setdefault(g, 0)
2466 guards[g] += 1
2465 guards[g] += 1
2467 if ui.verbose:
2466 if ui.verbose:
2468 guards['NONE'] = noguards
2467 guards['NONE'] = noguards
2469 guards = guards.items()
2468 guards = guards.items()
2470 guards.sort(key=lambda x: x[0][1:])
2469 guards.sort(key=lambda x: x[0][1:])
2471 if guards:
2470 if guards:
2472 ui.note(_('guards in series file:\n'))
2471 ui.note(_('guards in series file:\n'))
2473 for guard, count in guards:
2472 for guard, count in guards:
2474 ui.note('%2d ' % count)
2473 ui.note('%2d ' % count)
2475 ui.write(guard, '\n')
2474 ui.write(guard, '\n')
2476 else:
2475 else:
2477 ui.note(_('no guards in series file\n'))
2476 ui.note(_('no guards in series file\n'))
2478 else:
2477 else:
2479 if guards:
2478 if guards:
2480 ui.note(_('active guards:\n'))
2479 ui.note(_('active guards:\n'))
2481 for g in guards:
2480 for g in guards:
2482 ui.write(g, '\n')
2481 ui.write(g, '\n')
2483 else:
2482 else:
2484 ui.write(_('no active guards\n'))
2483 ui.write(_('no active guards\n'))
2485 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2484 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2486 popped = False
2485 popped = False
2487 if opts['pop'] or opts['reapply']:
2486 if opts['pop'] or opts['reapply']:
2488 for i in xrange(len(q.applied)):
2487 for i in xrange(len(q.applied)):
2489 pushable, reason = q.pushable(i)
2488 pushable, reason = q.pushable(i)
2490 if not pushable:
2489 if not pushable:
2491 ui.status(_('popping guarded patches\n'))
2490 ui.status(_('popping guarded patches\n'))
2492 popped = True
2491 popped = True
2493 if i == 0:
2492 if i == 0:
2494 q.pop(repo, all=True)
2493 q.pop(repo, all=True)
2495 else:
2494 else:
2496 q.pop(repo, i - 1)
2495 q.pop(repo, i - 1)
2497 break
2496 break
2498 if popped:
2497 if popped:
2499 try:
2498 try:
2500 if reapply:
2499 if reapply:
2501 ui.status(_('reapplying unguarded patches\n'))
2500 ui.status(_('reapplying unguarded patches\n'))
2502 q.push(repo, reapply)
2501 q.push(repo, reapply)
2503 finally:
2502 finally:
2504 q.save_dirty()
2503 q.save_dirty()
2505
2504
2506 def finish(ui, repo, *revrange, **opts):
2505 def finish(ui, repo, *revrange, **opts):
2507 """move applied patches into repository history
2506 """move applied patches into repository history
2508
2507
2509 Finishes the specified revisions (corresponding to applied
2508 Finishes the specified revisions (corresponding to applied
2510 patches) by moving them out of mq control into regular repository
2509 patches) by moving them out of mq control into regular repository
2511 history.
2510 history.
2512
2511
2513 Accepts a revision range or the -a/--applied option. If --applied
2512 Accepts a revision range or the -a/--applied option. If --applied
2514 is specified, all applied mq revisions are removed from mq
2513 is specified, all applied mq revisions are removed from mq
2515 control. Otherwise, the given revisions must be at the base of the
2514 control. Otherwise, the given revisions must be at the base of the
2516 stack of applied patches.
2515 stack of applied patches.
2517
2516
2518 This can be especially useful if your changes have been applied to
2517 This can be especially useful if your changes have been applied to
2519 an upstream repository, or if you are about to push your changes
2518 an upstream repository, or if you are about to push your changes
2520 to upstream.
2519 to upstream.
2521 """
2520 """
2522 if not opts['applied'] and not revrange:
2521 if not opts['applied'] and not revrange:
2523 raise util.Abort(_('no revisions specified'))
2522 raise util.Abort(_('no revisions specified'))
2524 elif opts['applied']:
2523 elif opts['applied']:
2525 revrange = ('qbase:qtip',) + revrange
2524 revrange = ('qbase:qtip',) + revrange
2526
2525
2527 q = repo.mq
2526 q = repo.mq
2528 if not q.applied:
2527 if not q.applied:
2529 ui.status(_('no patches applied\n'))
2528 ui.status(_('no patches applied\n'))
2530 return 0
2529 return 0
2531
2530
2532 revs = cmdutil.revrange(repo, revrange)
2531 revs = cmdutil.revrange(repo, revrange)
2533 q.finish(repo, revs)
2532 q.finish(repo, revs)
2534 q.save_dirty()
2533 q.save_dirty()
2535 return 0
2534 return 0
2536
2535
2537 def reposetup(ui, repo):
2536 def reposetup(ui, repo):
2538 class mqrepo(repo.__class__):
2537 class mqrepo(repo.__class__):
2539 @util.propertycache
2538 @util.propertycache
2540 def mq(self):
2539 def mq(self):
2541 return queue(self.ui, self.join(""))
2540 return queue(self.ui, self.join(""))
2542
2541
2543 def abort_if_wdir_patched(self, errmsg, force=False):
2542 def abort_if_wdir_patched(self, errmsg, force=False):
2544 if self.mq.applied and not force:
2543 if self.mq.applied and not force:
2545 parent = self.dirstate.parents()[0]
2544 parent = self.dirstate.parents()[0]
2546 if parent in [s.node for s in self.mq.applied]:
2545 if parent in [s.node for s in self.mq.applied]:
2547 raise util.Abort(errmsg)
2546 raise util.Abort(errmsg)
2548
2547
2549 def commit(self, text="", user=None, date=None, match=None,
2548 def commit(self, text="", user=None, date=None, match=None,
2550 force=False, editor=False, extra={}):
2549 force=False, editor=False, extra={}):
2551 self.abort_if_wdir_patched(
2550 self.abort_if_wdir_patched(
2552 _('cannot commit over an applied mq patch'),
2551 _('cannot commit over an applied mq patch'),
2553 force)
2552 force)
2554
2553
2555 return super(mqrepo, self).commit(text, user, date, match, force,
2554 return super(mqrepo, self).commit(text, user, date, match, force,
2556 editor, extra)
2555 editor, extra)
2557
2556
2558 def push(self, remote, force=False, revs=None, newbranch=False):
2557 def push(self, remote, force=False, revs=None, newbranch=False):
2559 if self.mq.applied and not force and not revs:
2558 if self.mq.applied and not force and not revs:
2560 raise util.Abort(_('source has mq patches applied'))
2559 raise util.Abort(_('source has mq patches applied'))
2561 return super(mqrepo, self).push(remote, force, revs, newbranch)
2560 return super(mqrepo, self).push(remote, force, revs, newbranch)
2562
2561
2563 def _findtags(self):
2562 def _findtags(self):
2564 '''augment tags from base class with patch tags'''
2563 '''augment tags from base class with patch tags'''
2565 result = super(mqrepo, self)._findtags()
2564 result = super(mqrepo, self)._findtags()
2566
2565
2567 q = self.mq
2566 q = self.mq
2568 if not q.applied:
2567 if not q.applied:
2569 return result
2568 return result
2570
2569
2571 mqtags = [(patch.node, patch.name) for patch in q.applied]
2570 mqtags = [(patch.node, patch.name) for patch in q.applied]
2572
2571
2573 if mqtags[-1][0] not in self.changelog.nodemap:
2572 if mqtags[-1][0] not in self.changelog.nodemap:
2574 self.ui.warn(_('mq status file refers to unknown node %s\n')
2573 self.ui.warn(_('mq status file refers to unknown node %s\n')
2575 % short(mqtags[-1][0]))
2574 % short(mqtags[-1][0]))
2576 return result
2575 return result
2577
2576
2578 mqtags.append((mqtags[-1][0], 'qtip'))
2577 mqtags.append((mqtags[-1][0], 'qtip'))
2579 mqtags.append((mqtags[0][0], 'qbase'))
2578 mqtags.append((mqtags[0][0], 'qbase'))
2580 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2579 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2581 tags = result[0]
2580 tags = result[0]
2582 for patch in mqtags:
2581 for patch in mqtags:
2583 if patch[1] in tags:
2582 if patch[1] in tags:
2584 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2583 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2585 % patch[1])
2584 % patch[1])
2586 else:
2585 else:
2587 tags[patch[1]] = patch[0]
2586 tags[patch[1]] = patch[0]
2588
2587
2589 return result
2588 return result
2590
2589
2591 def _branchtags(self, partial, lrev):
2590 def _branchtags(self, partial, lrev):
2592 q = self.mq
2591 q = self.mq
2593 if not q.applied:
2592 if not q.applied:
2594 return super(mqrepo, self)._branchtags(partial, lrev)
2593 return super(mqrepo, self)._branchtags(partial, lrev)
2595
2594
2596 cl = self.changelog
2595 cl = self.changelog
2597 qbasenode = q.applied[0].node
2596 qbasenode = q.applied[0].node
2598 if qbasenode not in cl.nodemap:
2597 if qbasenode not in cl.nodemap:
2599 self.ui.warn(_('mq status file refers to unknown node %s\n')
2598 self.ui.warn(_('mq status file refers to unknown node %s\n')
2600 % short(qbasenode))
2599 % short(qbasenode))
2601 return super(mqrepo, self)._branchtags(partial, lrev)
2600 return super(mqrepo, self)._branchtags(partial, lrev)
2602
2601
2603 qbase = cl.rev(qbasenode)
2602 qbase = cl.rev(qbasenode)
2604 start = lrev + 1
2603 start = lrev + 1
2605 if start < qbase:
2604 if start < qbase:
2606 # update the cache (excluding the patches) and save it
2605 # update the cache (excluding the patches) and save it
2607 ctxgen = (self[r] for r in xrange(lrev + 1, qbase))
2606 ctxgen = (self[r] for r in xrange(lrev + 1, qbase))
2608 self._updatebranchcache(partial, ctxgen)
2607 self._updatebranchcache(partial, ctxgen)
2609 self._writebranchcache(partial, cl.node(qbase - 1), qbase - 1)
2608 self._writebranchcache(partial, cl.node(qbase - 1), qbase - 1)
2610 start = qbase
2609 start = qbase
2611 # if start = qbase, the cache is as updated as it should be.
2610 # if start = qbase, the cache is as updated as it should be.
2612 # if start > qbase, the cache includes (part of) the patches.
2611 # if start > qbase, the cache includes (part of) the patches.
2613 # we might as well use it, but we won't save it.
2612 # we might as well use it, but we won't save it.
2614
2613
2615 # update the cache up to the tip
2614 # update the cache up to the tip
2616 ctxgen = (self[r] for r in xrange(start, len(cl)))
2615 ctxgen = (self[r] for r in xrange(start, len(cl)))
2617 self._updatebranchcache(partial, ctxgen)
2616 self._updatebranchcache(partial, ctxgen)
2618
2617
2619 return partial
2618 return partial
2620
2619
2621 if repo.local():
2620 if repo.local():
2622 repo.__class__ = mqrepo
2621 repo.__class__ = mqrepo
2623
2622
2624 def mqimport(orig, ui, repo, *args, **kwargs):
2623 def mqimport(orig, ui, repo, *args, **kwargs):
2625 if (hasattr(repo, 'abort_if_wdir_patched')
2624 if (hasattr(repo, 'abort_if_wdir_patched')
2626 and not kwargs.get('no_commit', False)):
2625 and not kwargs.get('no_commit', False)):
2627 repo.abort_if_wdir_patched(_('cannot import over an applied patch'),
2626 repo.abort_if_wdir_patched(_('cannot import over an applied patch'),
2628 kwargs.get('force'))
2627 kwargs.get('force'))
2629 return orig(ui, repo, *args, **kwargs)
2628 return orig(ui, repo, *args, **kwargs)
2630
2629
2631 def mqinit(orig, ui, *args, **kwargs):
2630 def mqinit(orig, ui, *args, **kwargs):
2632 mq = kwargs.pop('mq', None)
2631 mq = kwargs.pop('mq', None)
2633
2632
2634 if not mq:
2633 if not mq:
2635 return orig(ui, *args, **kwargs)
2634 return orig(ui, *args, **kwargs)
2636
2635
2637 if args:
2636 if args:
2638 repopath = args[0]
2637 repopath = args[0]
2639 if not hg.islocal(repopath):
2638 if not hg.islocal(repopath):
2640 raise util.Abort(_('only a local queue repository '
2639 raise util.Abort(_('only a local queue repository '
2641 'may be initialized'))
2640 'may be initialized'))
2642 else:
2641 else:
2643 repopath = cmdutil.findrepo(os.getcwd())
2642 repopath = cmdutil.findrepo(os.getcwd())
2644 if not repopath:
2643 if not repopath:
2645 raise util.Abort(_('There is no Mercurial repository here '
2644 raise util.Abort(_('There is no Mercurial repository here '
2646 '(.hg not found)'))
2645 '(.hg not found)'))
2647 repo = hg.repository(ui, repopath)
2646 repo = hg.repository(ui, repopath)
2648 return qinit(ui, repo, True)
2647 return qinit(ui, repo, True)
2649
2648
2650 def mqcommand(orig, ui, repo, *args, **kwargs):
2649 def mqcommand(orig, ui, repo, *args, **kwargs):
2651 """Add --mq option to operate on patch repository instead of main"""
2650 """Add --mq option to operate on patch repository instead of main"""
2652
2651
2653 # some commands do not like getting unknown options
2652 # some commands do not like getting unknown options
2654 mq = kwargs.pop('mq', None)
2653 mq = kwargs.pop('mq', None)
2655
2654
2656 if not mq:
2655 if not mq:
2657 return orig(ui, repo, *args, **kwargs)
2656 return orig(ui, repo, *args, **kwargs)
2658
2657
2659 q = repo.mq
2658 q = repo.mq
2660 r = q.qrepo()
2659 r = q.qrepo()
2661 if not r:
2660 if not r:
2662 raise util.Abort(_('no queue repository'))
2661 raise util.Abort(_('no queue repository'))
2663 return orig(r.ui, r, *args, **kwargs)
2662 return orig(r.ui, r, *args, **kwargs)
2664
2663
2665 def summary(orig, ui, repo, *args, **kwargs):
2664 def summary(orig, ui, repo, *args, **kwargs):
2666 r = orig(ui, repo, *args, **kwargs)
2665 r = orig(ui, repo, *args, **kwargs)
2667 q = repo.mq
2666 q = repo.mq
2668 m = []
2667 m = []
2669 a, u = len(q.applied), len(q.unapplied(repo))
2668 a, u = len(q.applied), len(q.unapplied(repo))
2670 if a:
2669 if a:
2671 m.append(ui.label(_("%d applied"), 'qseries.applied') % a)
2670 m.append(ui.label(_("%d applied"), 'qseries.applied') % a)
2672 if u:
2671 if u:
2673 m.append(ui.label(_("%d unapplied"), 'qseries.unapplied') % u)
2672 m.append(ui.label(_("%d unapplied"), 'qseries.unapplied') % u)
2674 if m:
2673 if m:
2675 ui.write("mq: %s\n" % ', '.join(m))
2674 ui.write("mq: %s\n" % ', '.join(m))
2676 else:
2675 else:
2677 ui.note(_("mq: (empty queue)\n"))
2676 ui.note(_("mq: (empty queue)\n"))
2678 return r
2677 return r
2679
2678
2680 def uisetup(ui):
2679 def uisetup(ui):
2681 mqopt = [('', 'mq', None, _("operate on patch repository"))]
2680 mqopt = [('', 'mq', None, _("operate on patch repository"))]
2682
2681
2683 extensions.wrapcommand(commands.table, 'import', mqimport)
2682 extensions.wrapcommand(commands.table, 'import', mqimport)
2684 extensions.wrapcommand(commands.table, 'summary', summary)
2683 extensions.wrapcommand(commands.table, 'summary', summary)
2685
2684
2686 entry = extensions.wrapcommand(commands.table, 'init', mqinit)
2685 entry = extensions.wrapcommand(commands.table, 'init', mqinit)
2687 entry[1].extend(mqopt)
2686 entry[1].extend(mqopt)
2688
2687
2689 norepo = commands.norepo.split(" ")
2688 norepo = commands.norepo.split(" ")
2690 for cmd in commands.table.keys():
2689 for cmd in commands.table.keys():
2691 cmd = cmdutil.parsealiases(cmd)[0]
2690 cmd = cmdutil.parsealiases(cmd)[0]
2692 if cmd in norepo:
2691 if cmd in norepo:
2693 continue
2692 continue
2694 entry = extensions.wrapcommand(commands.table, cmd, mqcommand)
2693 entry = extensions.wrapcommand(commands.table, cmd, mqcommand)
2695 entry[1].extend(mqopt)
2694 entry[1].extend(mqopt)
2696
2695
2697 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2696 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2698
2697
2699 cmdtable = {
2698 cmdtable = {
2700 "qapplied":
2699 "qapplied":
2701 (applied,
2700 (applied,
2702 [('1', 'last', None, _('show only the last patch'))] + seriesopts,
2701 [('1', 'last', None, _('show only the last patch'))] + seriesopts,
2703 _('hg qapplied [-1] [-s] [PATCH]')),
2702 _('hg qapplied [-1] [-s] [PATCH]')),
2704 "qclone":
2703 "qclone":
2705 (clone,
2704 (clone,
2706 [('', 'pull', None, _('use pull protocol to copy metadata')),
2705 [('', 'pull', None, _('use pull protocol to copy metadata')),
2707 ('U', 'noupdate', None, _('do not update the new working directories')),
2706 ('U', 'noupdate', None, _('do not update the new working directories')),
2708 ('', 'uncompressed', None,
2707 ('', 'uncompressed', None,
2709 _('use uncompressed transfer (fast over LAN)')),
2708 _('use uncompressed transfer (fast over LAN)')),
2710 ('p', 'patches', '', _('location of source patch repository')),
2709 ('p', 'patches', '', _('location of source patch repository')),
2711 ] + commands.remoteopts,
2710 ] + commands.remoteopts,
2712 _('hg qclone [OPTION]... SOURCE [DEST]')),
2711 _('hg qclone [OPTION]... SOURCE [DEST]')),
2713 "qcommit|qci":
2712 "qcommit|qci":
2714 (commit,
2713 (commit,
2715 commands.table["^commit|ci"][1],
2714 commands.table["^commit|ci"][1],
2716 _('hg qcommit [OPTION]... [FILE]...')),
2715 _('hg qcommit [OPTION]... [FILE]...')),
2717 "^qdiff":
2716 "^qdiff":
2718 (diff,
2717 (diff,
2719 commands.diffopts + commands.diffopts2 + commands.walkopts,
2718 commands.diffopts + commands.diffopts2 + commands.walkopts,
2720 _('hg qdiff [OPTION]... [FILE]...')),
2719 _('hg qdiff [OPTION]... [FILE]...')),
2721 "qdelete|qremove|qrm":
2720 "qdelete|qremove|qrm":
2722 (delete,
2721 (delete,
2723 [('k', 'keep', None, _('keep patch file')),
2722 [('k', 'keep', None, _('keep patch file')),
2724 ('r', 'rev', [], _('stop managing a revision (DEPRECATED)'))],
2723 ('r', 'rev', [], _('stop managing a revision (DEPRECATED)'))],
2725 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2724 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2726 'qfold':
2725 'qfold':
2727 (fold,
2726 (fold,
2728 [('e', 'edit', None, _('edit patch header')),
2727 [('e', 'edit', None, _('edit patch header')),
2729 ('k', 'keep', None, _('keep folded patch files')),
2728 ('k', 'keep', None, _('keep folded patch files')),
2730 ] + commands.commitopts,
2729 ] + commands.commitopts,
2731 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2730 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2732 'qgoto':
2731 'qgoto':
2733 (goto,
2732 (goto,
2734 [('f', 'force', None, _('overwrite any local changes'))],
2733 [('f', 'force', None, _('overwrite any local changes'))],
2735 _('hg qgoto [OPTION]... PATCH')),
2734 _('hg qgoto [OPTION]... PATCH')),
2736 'qguard':
2735 'qguard':
2737 (guard,
2736 (guard,
2738 [('l', 'list', None, _('list all patches and guards')),
2737 [('l', 'list', None, _('list all patches and guards')),
2739 ('n', 'none', None, _('drop all guards'))],
2738 ('n', 'none', None, _('drop all guards'))],
2740 _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]')),
2739 _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]')),
2741 'qheader': (header, [], _('hg qheader [PATCH]')),
2740 'qheader': (header, [], _('hg qheader [PATCH]')),
2742 "qimport":
2741 "qimport":
2743 (qimport,
2742 (qimport,
2744 [('e', 'existing', None, _('import file in patch directory')),
2743 [('e', 'existing', None, _('import file in patch directory')),
2745 ('n', 'name', '', _('name of patch file')),
2744 ('n', 'name', '', _('name of patch file')),
2746 ('f', 'force', None, _('overwrite existing files')),
2745 ('f', 'force', None, _('overwrite existing files')),
2747 ('r', 'rev', [], _('place existing revisions under mq control')),
2746 ('r', 'rev', [], _('place existing revisions under mq control')),
2748 ('g', 'git', None, _('use git extended diff format')),
2747 ('g', 'git', None, _('use git extended diff format')),
2749 ('P', 'push', None, _('qpush after importing'))],
2748 ('P', 'push', None, _('qpush after importing'))],
2750 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...')),
2749 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...')),
2751 "^qinit":
2750 "^qinit":
2752 (init,
2751 (init,
2753 [('c', 'create-repo', None, _('create queue repository'))],
2752 [('c', 'create-repo', None, _('create queue repository'))],
2754 _('hg qinit [-c]')),
2753 _('hg qinit [-c]')),
2755 "^qnew":
2754 "^qnew":
2756 (new,
2755 (new,
2757 [('e', 'edit', None, _('edit commit message')),
2756 [('e', 'edit', None, _('edit commit message')),
2758 ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
2757 ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
2759 ('g', 'git', None, _('use git extended diff format')),
2758 ('g', 'git', None, _('use git extended diff format')),
2760 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2759 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2761 ('u', 'user', '', _('add "From: <given user>" to patch')),
2760 ('u', 'user', '', _('add "From: <given user>" to patch')),
2762 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2761 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2763 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2762 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2764 ] + commands.walkopts + commands.commitopts,
2763 ] + commands.walkopts + commands.commitopts,
2765 _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...')),
2764 _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...')),
2766 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2765 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2767 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2766 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2768 "^qpop":
2767 "^qpop":
2769 (pop,
2768 (pop,
2770 [('a', 'all', None, _('pop all patches')),
2769 [('a', 'all', None, _('pop all patches')),
2771 ('n', 'name', '', _('queue name to pop (DEPRECATED)')),
2770 ('n', 'name', '', _('queue name to pop (DEPRECATED)')),
2772 ('f', 'force', None, _('forget any local changes to patched files'))],
2771 ('f', 'force', None, _('forget any local changes to patched files'))],
2773 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2772 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2774 "^qpush":
2773 "^qpush":
2775 (push,
2774 (push,
2776 [('f', 'force', None, _('apply if the patch has rejects')),
2775 [('f', 'force', None, _('apply if the patch has rejects')),
2777 ('l', 'list', None, _('list patch name in commit text')),
2776 ('l', 'list', None, _('list patch name in commit text')),
2778 ('a', 'all', None, _('apply all patches')),
2777 ('a', 'all', None, _('apply all patches')),
2779 ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
2778 ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
2780 ('n', 'name', '', _('merge queue name (DEPRECATED)')),
2779 ('n', 'name', '', _('merge queue name (DEPRECATED)')),
2781 ('', 'move', None, _('reorder patch series and apply only the patch'))],
2780 ('', 'move', None, _('reorder patch series and apply only the patch'))],
2782 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [--move] [PATCH | INDEX]')),
2781 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [--move] [PATCH | INDEX]')),
2783 "^qrefresh":
2782 "^qrefresh":
2784 (refresh,
2783 (refresh,
2785 [('e', 'edit', None, _('edit commit message')),
2784 [('e', 'edit', None, _('edit commit message')),
2786 ('g', 'git', None, _('use git extended diff format')),
2785 ('g', 'git', None, _('use git extended diff format')),
2787 ('s', 'short', None,
2786 ('s', 'short', None,
2788 _('refresh only files already in the patch and specified files')),
2787 _('refresh only files already in the patch and specified files')),
2789 ('U', 'currentuser', None,
2788 ('U', 'currentuser', None,
2790 _('add/update author field in patch with current user')),
2789 _('add/update author field in patch with current user')),
2791 ('u', 'user', '',
2790 ('u', 'user', '',
2792 _('add/update author field in patch with given user')),
2791 _('add/update author field in patch with given user')),
2793 ('D', 'currentdate', None,
2792 ('D', 'currentdate', None,
2794 _('add/update date field in patch with current date')),
2793 _('add/update date field in patch with current date')),
2795 ('d', 'date', '',
2794 ('d', 'date', '',
2796 _('add/update date field in patch with given date'))
2795 _('add/update date field in patch with given date'))
2797 ] + commands.walkopts + commands.commitopts,
2796 ] + commands.walkopts + commands.commitopts,
2798 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2797 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2799 'qrename|qmv':
2798 'qrename|qmv':
2800 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2799 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2801 "qrestore":
2800 "qrestore":
2802 (restore,
2801 (restore,
2803 [('d', 'delete', None, _('delete save entry')),
2802 [('d', 'delete', None, _('delete save entry')),
2804 ('u', 'update', None, _('update queue working directory'))],
2803 ('u', 'update', None, _('update queue working directory'))],
2805 _('hg qrestore [-d] [-u] REV')),
2804 _('hg qrestore [-d] [-u] REV')),
2806 "qsave":
2805 "qsave":
2807 (save,
2806 (save,
2808 [('c', 'copy', None, _('copy patch directory')),
2807 [('c', 'copy', None, _('copy patch directory')),
2809 ('n', 'name', '', _('copy directory name')),
2808 ('n', 'name', '', _('copy directory name')),
2810 ('e', 'empty', None, _('clear queue status file')),
2809 ('e', 'empty', None, _('clear queue status file')),
2811 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2810 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2812 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2811 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2813 "qselect":
2812 "qselect":
2814 (select,
2813 (select,
2815 [('n', 'none', None, _('disable all guards')),
2814 [('n', 'none', None, _('disable all guards')),
2816 ('s', 'series', None, _('list all guards in series file')),
2815 ('s', 'series', None, _('list all guards in series file')),
2817 ('', 'pop', None, _('pop to before first guarded applied patch')),
2816 ('', 'pop', None, _('pop to before first guarded applied patch')),
2818 ('', 'reapply', None, _('pop, then reapply patches'))],
2817 ('', 'reapply', None, _('pop, then reapply patches'))],
2819 _('hg qselect [OPTION]... [GUARD]...')),
2818 _('hg qselect [OPTION]... [GUARD]...')),
2820 "qseries":
2819 "qseries":
2821 (series,
2820 (series,
2822 [('m', 'missing', None, _('print patches not in series')),
2821 [('m', 'missing', None, _('print patches not in series')),
2823 ] + seriesopts,
2822 ] + seriesopts,
2824 _('hg qseries [-ms]')),
2823 _('hg qseries [-ms]')),
2825 "strip":
2824 "strip":
2826 (strip,
2825 (strip,
2827 [('f', 'force', None, _('force removal of changesets even if the '
2826 [('f', 'force', None, _('force removal of changesets even if the '
2828 'working directory has uncommitted changes')),
2827 'working directory has uncommitted changes')),
2829 ('b', 'backup', None, _('bundle only changesets with local revision'
2828 ('b', 'backup', None, _('bundle only changesets with local revision'
2830 ' number greater than REV which are not'
2829 ' number greater than REV which are not'
2831 ' descendants of REV (DEPRECATED)')),
2830 ' descendants of REV (DEPRECATED)')),
2832 ('n', 'nobackup', None, _('no backups'))],
2831 ('n', 'nobackup', None, _('no backups'))],
2833 _('hg strip [-f] [-n] REV')),
2832 _('hg strip [-f] [-n] REV')),
2834 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2833 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2835 "qunapplied":
2834 "qunapplied":
2836 (unapplied,
2835 (unapplied,
2837 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2836 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2838 _('hg qunapplied [-1] [-s] [PATCH]')),
2837 _('hg qunapplied [-1] [-s] [PATCH]')),
2839 "qfinish":
2838 "qfinish":
2840 (finish,
2839 (finish,
2841 [('a', 'applied', None, _('finish all applied changesets'))],
2840 [('a', 'applied', None, _('finish all applied changesets'))],
2842 _('hg qfinish [-a] [REV]...')),
2841 _('hg qfinish [-a] [REV]...')),
2843 }
2842 }
2844
2843
2845 colortable = {'qguard.negative': 'red',
2844 colortable = {'qguard.negative': 'red',
2846 'qguard.positive': 'yellow',
2845 'qguard.positive': 'yellow',
2847 'qguard.unguarded': 'green',
2846 'qguard.unguarded': 'green',
2848 'qseries.applied': 'blue bold underline',
2847 'qseries.applied': 'blue bold underline',
2849 'qseries.guarded': 'black bold',
2848 'qseries.guarded': 'black bold',
2850 'qseries.missing': 'red bold',
2849 'qseries.missing': 'red bold',
2851 'qseries.unapplied': 'black bold'}
2850 'qseries.unapplied': 'black bold'}
General Comments 0
You need to be logged in to leave comments. Login now