##// END OF EJS Templates
mq: mark error message for translation
Martin Geisler -
r11120:0bedcbcb default
parent child Browse files
Show More
@@ -1,2851 +1,2851 b''
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 = []
744 realpatches = []
745 for patch in patches:
745 for patch in patches:
746 patch = self.lookup(patch, strict=True)
746 patch = self.lookup(patch, strict=True)
747 info = self.isapplied(patch)
747 info = self.isapplied(patch)
748 if info:
748 if info:
749 raise util.Abort(_("cannot delete applied patch %s") % patch)
749 raise util.Abort(_("cannot delete applied patch %s") % patch)
750 if patch not in self.series:
750 if patch not in self.series:
751 raise util.Abort(_("patch %s not in series file") % patch)
751 raise util.Abort(_("patch %s not in series file") % patch)
752 realpatches.append(patch)
752 realpatches.append(patch)
753
753
754 numrevs = 0
754 numrevs = 0
755 if opts.get('rev'):
755 if opts.get('rev'):
756 if not self.applied:
756 if not self.applied:
757 raise util.Abort(_('no patches applied'))
757 raise util.Abort(_('no patches applied'))
758 revs = cmdutil.revrange(repo, opts['rev'])
758 revs = cmdutil.revrange(repo, opts['rev'])
759 if len(revs) > 1 and revs[0] > revs[1]:
759 if len(revs) > 1 and revs[0] > revs[1]:
760 revs.reverse()
760 revs.reverse()
761 revpatches = self._revpatches(repo, revs)
761 revpatches = self._revpatches(repo, revs)
762 realpatches += revpatches
762 realpatches += revpatches
763 numrevs = len(revpatches)
763 numrevs = len(revpatches)
764
764
765 self._cleanup(realpatches, numrevs, opts.get('keep'))
765 self._cleanup(realpatches, numrevs, opts.get('keep'))
766
766
767 def check_toppatch(self, repo):
767 def check_toppatch(self, repo):
768 if self.applied:
768 if self.applied:
769 top = self.applied[-1].node
769 top = self.applied[-1].node
770 patch = self.applied[-1].name
770 patch = self.applied[-1].name
771 pp = repo.dirstate.parents()
771 pp = repo.dirstate.parents()
772 if top not in pp:
772 if top not in pp:
773 raise util.Abort(_("working directory revision is not qtip"))
773 raise util.Abort(_("working directory revision is not qtip"))
774 return top, patch
774 return top, patch
775 return None, None
775 return None, None
776
776
777 def check_localchanges(self, repo, force=False, refresh=True):
777 def check_localchanges(self, repo, force=False, refresh=True):
778 m, a, r, d = repo.status()[:4]
778 m, a, r, d = repo.status()[:4]
779 if (m or a or r or d) and not force:
779 if (m or a or r or d) and not force:
780 if refresh:
780 if refresh:
781 raise util.Abort(_("local changes found, refresh first"))
781 raise util.Abort(_("local changes found, refresh first"))
782 else:
782 else:
783 raise util.Abort(_("local changes found"))
783 raise util.Abort(_("local changes found"))
784 return m, a, r, d
784 return m, a, r, d
785
785
786 _reserved = ('series', 'status', 'guards')
786 _reserved = ('series', 'status', 'guards')
787 def check_reserved_name(self, name):
787 def check_reserved_name(self, name):
788 if (name in self._reserved or name.startswith('.hg')
788 if (name in self._reserved or name.startswith('.hg')
789 or name.startswith('.mq') or '#' in name or ':' in name):
789 or name.startswith('.mq') or '#' in name or ':' in name):
790 raise util.Abort(_('"%s" cannot be used as the name of a patch')
790 raise util.Abort(_('"%s" cannot be used as the name of a patch')
791 % name)
791 % name)
792
792
793 def new(self, repo, patchfn, *pats, **opts):
793 def new(self, repo, patchfn, *pats, **opts):
794 """options:
794 """options:
795 msg: a string or a no-argument function returning a string
795 msg: a string or a no-argument function returning a string
796 """
796 """
797 msg = opts.get('msg')
797 msg = opts.get('msg')
798 user = opts.get('user')
798 user = opts.get('user')
799 date = opts.get('date')
799 date = opts.get('date')
800 if date:
800 if date:
801 date = util.parsedate(date)
801 date = util.parsedate(date)
802 diffopts = self.diffopts({'git': opts.get('git')})
802 diffopts = self.diffopts({'git': opts.get('git')})
803 self.check_reserved_name(patchfn)
803 self.check_reserved_name(patchfn)
804 if os.path.exists(self.join(patchfn)):
804 if os.path.exists(self.join(patchfn)):
805 raise util.Abort(_('patch "%s" already exists') % patchfn)
805 raise util.Abort(_('patch "%s" already exists') % patchfn)
806 if opts.get('include') or opts.get('exclude') or pats:
806 if opts.get('include') or opts.get('exclude') or pats:
807 match = cmdutil.match(repo, pats, opts)
807 match = cmdutil.match(repo, pats, opts)
808 # detect missing files in pats
808 # detect missing files in pats
809 def badfn(f, msg):
809 def badfn(f, msg):
810 raise util.Abort('%s: %s' % (f, msg))
810 raise util.Abort('%s: %s' % (f, msg))
811 match.bad = badfn
811 match.bad = badfn
812 m, a, r, d = repo.status(match=match)[:4]
812 m, a, r, d = repo.status(match=match)[:4]
813 else:
813 else:
814 m, a, r, d = self.check_localchanges(repo, force=True)
814 m, a, r, d = self.check_localchanges(repo, force=True)
815 match = cmdutil.matchfiles(repo, m + a + r)
815 match = cmdutil.matchfiles(repo, m + a + r)
816 if len(repo[None].parents()) > 1:
816 if len(repo[None].parents()) > 1:
817 raise util.Abort(_('cannot manage merge changesets'))
817 raise util.Abort(_('cannot manage merge changesets'))
818 commitfiles = m + a + r
818 commitfiles = m + a + r
819 self.check_toppatch(repo)
819 self.check_toppatch(repo)
820 insert = self.full_series_end()
820 insert = self.full_series_end()
821 wlock = repo.wlock()
821 wlock = repo.wlock()
822 try:
822 try:
823 # if patch file write fails, abort early
823 # if patch file write fails, abort early
824 p = self.opener(patchfn, "w")
824 p = self.opener(patchfn, "w")
825 try:
825 try:
826 if self.plainmode:
826 if self.plainmode:
827 if user:
827 if user:
828 p.write("From: " + user + "\n")
828 p.write("From: " + user + "\n")
829 if not date:
829 if not date:
830 p.write("\n")
830 p.write("\n")
831 if date:
831 if date:
832 p.write("Date: %d %d\n\n" % date)
832 p.write("Date: %d %d\n\n" % date)
833 else:
833 else:
834 p.write("# HG changeset patch\n")
834 p.write("# HG changeset patch\n")
835 p.write("# Parent "
835 p.write("# Parent "
836 + hex(repo[None].parents()[0].node()) + "\n")
836 + hex(repo[None].parents()[0].node()) + "\n")
837 if user:
837 if user:
838 p.write("# User " + user + "\n")
838 p.write("# User " + user + "\n")
839 if date:
839 if date:
840 p.write("# Date %s %s\n\n" % date)
840 p.write("# Date %s %s\n\n" % date)
841 if hasattr(msg, '__call__'):
841 if hasattr(msg, '__call__'):
842 msg = msg()
842 msg = msg()
843 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
843 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
844 n = repo.commit(commitmsg, user, date, match=match, force=True)
844 n = repo.commit(commitmsg, user, date, match=match, force=True)
845 if n is None:
845 if n is None:
846 raise util.Abort(_("repo commit failed"))
846 raise util.Abort(_("repo commit failed"))
847 try:
847 try:
848 self.full_series[insert:insert] = [patchfn]
848 self.full_series[insert:insert] = [patchfn]
849 self.applied.append(statusentry(n, patchfn))
849 self.applied.append(statusentry(n, patchfn))
850 self.parse_series()
850 self.parse_series()
851 self.series_dirty = 1
851 self.series_dirty = 1
852 self.applied_dirty = 1
852 self.applied_dirty = 1
853 if msg:
853 if msg:
854 msg = msg + "\n\n"
854 msg = msg + "\n\n"
855 p.write(msg)
855 p.write(msg)
856 if commitfiles:
856 if commitfiles:
857 parent = self.qparents(repo, n)
857 parent = self.qparents(repo, n)
858 chunks = patch.diff(repo, node1=parent, node2=n,
858 chunks = patch.diff(repo, node1=parent, node2=n,
859 match=match, opts=diffopts)
859 match=match, opts=diffopts)
860 for chunk in chunks:
860 for chunk in chunks:
861 p.write(chunk)
861 p.write(chunk)
862 p.close()
862 p.close()
863 wlock.release()
863 wlock.release()
864 wlock = None
864 wlock = None
865 r = self.qrepo()
865 r = self.qrepo()
866 if r:
866 if r:
867 r.add([patchfn])
867 r.add([patchfn])
868 except:
868 except:
869 repo.rollback()
869 repo.rollback()
870 raise
870 raise
871 except Exception:
871 except Exception:
872 patchpath = self.join(patchfn)
872 patchpath = self.join(patchfn)
873 try:
873 try:
874 os.unlink(patchpath)
874 os.unlink(patchpath)
875 except:
875 except:
876 self.ui.warn(_('error unlinking %s\n') % patchpath)
876 self.ui.warn(_('error unlinking %s\n') % patchpath)
877 raise
877 raise
878 self.removeundo(repo)
878 self.removeundo(repo)
879 finally:
879 finally:
880 release(wlock)
880 release(wlock)
881
881
882 def strip(self, repo, rev, update=True, backup="all", force=None):
882 def strip(self, repo, rev, update=True, backup="all", force=None):
883 wlock = lock = None
883 wlock = lock = None
884 try:
884 try:
885 wlock = repo.wlock()
885 wlock = repo.wlock()
886 lock = repo.lock()
886 lock = repo.lock()
887
887
888 if update:
888 if update:
889 self.check_localchanges(repo, force=force, refresh=False)
889 self.check_localchanges(repo, force=force, refresh=False)
890 urev = self.qparents(repo, rev)
890 urev = self.qparents(repo, rev)
891 hg.clean(repo, urev)
891 hg.clean(repo, urev)
892 repo.dirstate.write()
892 repo.dirstate.write()
893
893
894 self.removeundo(repo)
894 self.removeundo(repo)
895 repair.strip(self.ui, repo, rev, backup)
895 repair.strip(self.ui, repo, rev, backup)
896 # strip may have unbundled a set of backed up revisions after
896 # strip may have unbundled a set of backed up revisions after
897 # the actual strip
897 # the actual strip
898 self.removeundo(repo)
898 self.removeundo(repo)
899 finally:
899 finally:
900 release(lock, wlock)
900 release(lock, wlock)
901
901
902 def isapplied(self, patch):
902 def isapplied(self, patch):
903 """returns (index, rev, patch)"""
903 """returns (index, rev, patch)"""
904 for i, a in enumerate(self.applied):
904 for i, a in enumerate(self.applied):
905 if a.name == patch:
905 if a.name == patch:
906 return (i, a.node, a.name)
906 return (i, a.node, a.name)
907 return None
907 return None
908
908
909 # if the exact patch name does not exist, we try a few
909 # if the exact patch name does not exist, we try a few
910 # variations. If strict is passed, we try only #1
910 # variations. If strict is passed, we try only #1
911 #
911 #
912 # 1) a number to indicate an offset in the series file
912 # 1) a number to indicate an offset in the series file
913 # 2) a unique substring of the patch name was given
913 # 2) a unique substring of the patch name was given
914 # 3) patchname[-+]num to indicate an offset in the series file
914 # 3) patchname[-+]num to indicate an offset in the series file
915 def lookup(self, patch, strict=False):
915 def lookup(self, patch, strict=False):
916 patch = patch and str(patch)
916 patch = patch and str(patch)
917
917
918 def partial_name(s):
918 def partial_name(s):
919 if s in self.series:
919 if s in self.series:
920 return s
920 return s
921 matches = [x for x in self.series if s in x]
921 matches = [x for x in self.series if s in x]
922 if len(matches) > 1:
922 if len(matches) > 1:
923 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
923 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
924 for m in matches:
924 for m in matches:
925 self.ui.warn(' %s\n' % m)
925 self.ui.warn(' %s\n' % m)
926 return None
926 return None
927 if matches:
927 if matches:
928 return matches[0]
928 return matches[0]
929 if self.series and self.applied:
929 if self.series and self.applied:
930 if s == 'qtip':
930 if s == 'qtip':
931 return self.series[self.series_end(True)-1]
931 return self.series[self.series_end(True)-1]
932 if s == 'qbase':
932 if s == 'qbase':
933 return self.series[0]
933 return self.series[0]
934 return None
934 return None
935
935
936 if patch is None:
936 if patch is None:
937 return None
937 return None
938 if patch in self.series:
938 if patch in self.series:
939 return patch
939 return patch
940
940
941 if not os.path.isfile(self.join(patch)):
941 if not os.path.isfile(self.join(patch)):
942 try:
942 try:
943 sno = int(patch)
943 sno = int(patch)
944 except (ValueError, OverflowError):
944 except (ValueError, OverflowError):
945 pass
945 pass
946 else:
946 else:
947 if -len(self.series) <= sno < len(self.series):
947 if -len(self.series) <= sno < len(self.series):
948 return self.series[sno]
948 return self.series[sno]
949
949
950 if not strict:
950 if not strict:
951 res = partial_name(patch)
951 res = partial_name(patch)
952 if res:
952 if res:
953 return res
953 return res
954 minus = patch.rfind('-')
954 minus = patch.rfind('-')
955 if minus >= 0:
955 if minus >= 0:
956 res = partial_name(patch[:minus])
956 res = partial_name(patch[:minus])
957 if res:
957 if res:
958 i = self.series.index(res)
958 i = self.series.index(res)
959 try:
959 try:
960 off = int(patch[minus + 1:] or 1)
960 off = int(patch[minus + 1:] or 1)
961 except (ValueError, OverflowError):
961 except (ValueError, OverflowError):
962 pass
962 pass
963 else:
963 else:
964 if i - off >= 0:
964 if i - off >= 0:
965 return self.series[i - off]
965 return self.series[i - off]
966 plus = patch.rfind('+')
966 plus = patch.rfind('+')
967 if plus >= 0:
967 if plus >= 0:
968 res = partial_name(patch[:plus])
968 res = partial_name(patch[:plus])
969 if res:
969 if res:
970 i = self.series.index(res)
970 i = self.series.index(res)
971 try:
971 try:
972 off = int(patch[plus + 1:] or 1)
972 off = int(patch[plus + 1:] or 1)
973 except (ValueError, OverflowError):
973 except (ValueError, OverflowError):
974 pass
974 pass
975 else:
975 else:
976 if i + off < len(self.series):
976 if i + off < len(self.series):
977 return self.series[i + off]
977 return self.series[i + off]
978 raise util.Abort(_("patch %s not in series") % patch)
978 raise util.Abort(_("patch %s not in series") % patch)
979
979
980 def push(self, repo, patch=None, force=False, list=False,
980 def push(self, repo, patch=None, force=False, list=False,
981 mergeq=None, all=False, move=False):
981 mergeq=None, all=False, move=False):
982 diffopts = self.diffopts()
982 diffopts = self.diffopts()
983 wlock = repo.wlock()
983 wlock = repo.wlock()
984 try:
984 try:
985 heads = []
985 heads = []
986 for b, ls in repo.branchmap().iteritems():
986 for b, ls in repo.branchmap().iteritems():
987 heads += ls
987 heads += ls
988 if not heads:
988 if not heads:
989 heads = [nullid]
989 heads = [nullid]
990 if repo.dirstate.parents()[0] not in heads:
990 if repo.dirstate.parents()[0] not in heads:
991 self.ui.status(_("(working directory not at a head)\n"))
991 self.ui.status(_("(working directory not at a head)\n"))
992
992
993 if not self.series:
993 if not self.series:
994 self.ui.warn(_('no patches in series\n'))
994 self.ui.warn(_('no patches in series\n'))
995 return 0
995 return 0
996
996
997 patch = self.lookup(patch)
997 patch = self.lookup(patch)
998 # Suppose our series file is: A B C and the current 'top'
998 # Suppose our series file is: A B C and the current 'top'
999 # patch is B. qpush C should be performed (moving forward)
999 # 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
1000 # qpush B is a NOP (no change) qpush A is an error (can't
1001 # go backwards with qpush)
1001 # go backwards with qpush)
1002 if patch:
1002 if patch:
1003 info = self.isapplied(patch)
1003 info = self.isapplied(patch)
1004 if info:
1004 if info:
1005 if info[0] < len(self.applied) - 1:
1005 if info[0] < len(self.applied) - 1:
1006 raise util.Abort(
1006 raise util.Abort(
1007 _("cannot push to a previous patch: %s") % patch)
1007 _("cannot push to a previous patch: %s") % patch)
1008 self.ui.warn(
1008 self.ui.warn(
1009 _('qpush: %s is already at the top\n') % patch)
1009 _('qpush: %s is already at the top\n') % patch)
1010 return
1010 return
1011 pushable, reason = self.pushable(patch)
1011 pushable, reason = self.pushable(patch)
1012 if not pushable:
1012 if not pushable:
1013 if reason:
1013 if reason:
1014 reason = _('guarded by %r') % reason
1014 reason = _('guarded by %r') % reason
1015 else:
1015 else:
1016 reason = _('no matching guards')
1016 reason = _('no matching guards')
1017 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1017 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
1018 return 1
1018 return 1
1019 elif all:
1019 elif all:
1020 patch = self.series[-1]
1020 patch = self.series[-1]
1021 if self.isapplied(patch):
1021 if self.isapplied(patch):
1022 self.ui.warn(_('all patches are currently applied\n'))
1022 self.ui.warn(_('all patches are currently applied\n'))
1023 return 0
1023 return 0
1024
1024
1025 # Following the above example, starting at 'top' of B:
1025 # Following the above example, starting at 'top' of B:
1026 # qpush should be performed (pushes C), but a subsequent
1026 # qpush should be performed (pushes C), but a subsequent
1027 # qpush without an argument is an error (nothing to
1027 # qpush without an argument is an error (nothing to
1028 # apply). This allows a loop of "...while hg qpush..." to
1028 # apply). This allows a loop of "...while hg qpush..." to
1029 # work as it detects an error when done
1029 # work as it detects an error when done
1030 start = self.series_end()
1030 start = self.series_end()
1031 if start == len(self.series):
1031 if start == len(self.series):
1032 self.ui.warn(_('patch series already fully applied\n'))
1032 self.ui.warn(_('patch series already fully applied\n'))
1033 return 1
1033 return 1
1034 if not force:
1034 if not force:
1035 self.check_localchanges(repo)
1035 self.check_localchanges(repo)
1036
1036
1037 if move:
1037 if move:
1038 try:
1038 try:
1039 del self.full_series[self.full_series.index(patch, start)]
1039 del self.full_series[self.full_series.index(patch, start)]
1040 except ValueError:
1040 except ValueError:
1041 raise util.Abort(_("patch '%s' not found") % patch)
1041 raise util.Abort(_("patch '%s' not found") % patch)
1042 self.full_series.insert(start, patch)
1042 self.full_series.insert(start, patch)
1043 self.parse_series()
1043 self.parse_series()
1044 self.series_dirty = 1
1044 self.series_dirty = 1
1045
1045
1046 self.applied_dirty = 1
1046 self.applied_dirty = 1
1047 if start > 0:
1047 if start > 0:
1048 self.check_toppatch(repo)
1048 self.check_toppatch(repo)
1049 if not patch:
1049 if not patch:
1050 patch = self.series[start]
1050 patch = self.series[start]
1051 end = start + 1
1051 end = start + 1
1052 else:
1052 else:
1053 end = self.series.index(patch, start) + 1
1053 end = self.series.index(patch, start) + 1
1054
1054
1055 s = self.series[start:end]
1055 s = self.series[start:end]
1056 all_files = set()
1056 all_files = set()
1057 try:
1057 try:
1058 if mergeq:
1058 if mergeq:
1059 ret = self.mergepatch(repo, mergeq, s, diffopts)
1059 ret = self.mergepatch(repo, mergeq, s, diffopts)
1060 else:
1060 else:
1061 ret = self.apply(repo, s, list, all_files=all_files)
1061 ret = self.apply(repo, s, list, all_files=all_files)
1062 except:
1062 except:
1063 self.ui.warn(_('cleaning up working directory...'))
1063 self.ui.warn(_('cleaning up working directory...'))
1064 node = repo.dirstate.parents()[0]
1064 node = repo.dirstate.parents()[0]
1065 hg.revert(repo, node, None)
1065 hg.revert(repo, node, None)
1066 # only remove unknown files that we know we touched or
1066 # only remove unknown files that we know we touched or
1067 # created while patching
1067 # created while patching
1068 for f in all_files:
1068 for f in all_files:
1069 if f not in repo.dirstate:
1069 if f not in repo.dirstate:
1070 try:
1070 try:
1071 util.unlink(repo.wjoin(f))
1071 util.unlink(repo.wjoin(f))
1072 except OSError, inst:
1072 except OSError, inst:
1073 if inst.errno != errno.ENOENT:
1073 if inst.errno != errno.ENOENT:
1074 raise
1074 raise
1075 self.ui.warn(_('done\n'))
1075 self.ui.warn(_('done\n'))
1076 raise
1076 raise
1077
1077
1078 if not self.applied:
1078 if not self.applied:
1079 return ret[0]
1079 return ret[0]
1080 top = self.applied[-1].name
1080 top = self.applied[-1].name
1081 if ret[0] and ret[0] > 1:
1081 if ret[0] and ret[0] > 1:
1082 msg = _("errors during apply, please fix and refresh %s\n")
1082 msg = _("errors during apply, please fix and refresh %s\n")
1083 self.ui.write(msg % top)
1083 self.ui.write(msg % top)
1084 else:
1084 else:
1085 self.ui.write(_("now at: %s\n") % top)
1085 self.ui.write(_("now at: %s\n") % top)
1086 return ret[0]
1086 return ret[0]
1087
1087
1088 finally:
1088 finally:
1089 wlock.release()
1089 wlock.release()
1090
1090
1091 def pop(self, repo, patch=None, force=False, update=True, all=False):
1091 def pop(self, repo, patch=None, force=False, update=True, all=False):
1092 wlock = repo.wlock()
1092 wlock = repo.wlock()
1093 try:
1093 try:
1094 if patch:
1094 if patch:
1095 # index, rev, patch
1095 # index, rev, patch
1096 info = self.isapplied(patch)
1096 info = self.isapplied(patch)
1097 if not info:
1097 if not info:
1098 patch = self.lookup(patch)
1098 patch = self.lookup(patch)
1099 info = self.isapplied(patch)
1099 info = self.isapplied(patch)
1100 if not info:
1100 if not info:
1101 raise util.Abort(_("patch %s is not applied") % patch)
1101 raise util.Abort(_("patch %s is not applied") % patch)
1102
1102
1103 if not self.applied:
1103 if not self.applied:
1104 # Allow qpop -a to work repeatedly,
1104 # Allow qpop -a to work repeatedly,
1105 # but not qpop without an argument
1105 # but not qpop without an argument
1106 self.ui.warn(_("no patches applied\n"))
1106 self.ui.warn(_("no patches applied\n"))
1107 return not all
1107 return not all
1108
1108
1109 if all:
1109 if all:
1110 start = 0
1110 start = 0
1111 elif patch:
1111 elif patch:
1112 start = info[0] + 1
1112 start = info[0] + 1
1113 else:
1113 else:
1114 start = len(self.applied) - 1
1114 start = len(self.applied) - 1
1115
1115
1116 if start >= len(self.applied):
1116 if start >= len(self.applied):
1117 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1117 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1118 return
1118 return
1119
1119
1120 if not update:
1120 if not update:
1121 parents = repo.dirstate.parents()
1121 parents = repo.dirstate.parents()
1122 rr = [x.node for x in self.applied]
1122 rr = [x.node for x in self.applied]
1123 for p in parents:
1123 for p in parents:
1124 if p in rr:
1124 if p in rr:
1125 self.ui.warn(_("qpop: forcing dirstate update\n"))
1125 self.ui.warn(_("qpop: forcing dirstate update\n"))
1126 update = True
1126 update = True
1127 else:
1127 else:
1128 parents = [p.node() for p in repo[None].parents()]
1128 parents = [p.node() for p in repo[None].parents()]
1129 needupdate = False
1129 needupdate = False
1130 for entry in self.applied[start:]:
1130 for entry in self.applied[start:]:
1131 if entry.node in parents:
1131 if entry.node in parents:
1132 needupdate = True
1132 needupdate = True
1133 break
1133 break
1134 update = needupdate
1134 update = needupdate
1135
1135
1136 if not force and update:
1136 if not force and update:
1137 self.check_localchanges(repo)
1137 self.check_localchanges(repo)
1138
1138
1139 self.applied_dirty = 1
1139 self.applied_dirty = 1
1140 end = len(self.applied)
1140 end = len(self.applied)
1141 rev = self.applied[start].node
1141 rev = self.applied[start].node
1142 if update:
1142 if update:
1143 top = self.check_toppatch(repo)[0]
1143 top = self.check_toppatch(repo)[0]
1144
1144
1145 try:
1145 try:
1146 heads = repo.changelog.heads(rev)
1146 heads = repo.changelog.heads(rev)
1147 except error.LookupError:
1147 except error.LookupError:
1148 node = short(rev)
1148 node = short(rev)
1149 raise util.Abort(_('trying to pop unknown node %s') % node)
1149 raise util.Abort(_('trying to pop unknown node %s') % node)
1150
1150
1151 if heads != [self.applied[-1].node]:
1151 if heads != [self.applied[-1].node]:
1152 raise util.Abort(_("popping would remove a revision not "
1152 raise util.Abort(_("popping would remove a revision not "
1153 "managed by this patch queue"))
1153 "managed by this patch queue"))
1154
1154
1155 # we know there are no local changes, so we can make a simplified
1155 # we know there are no local changes, so we can make a simplified
1156 # form of hg.update.
1156 # form of hg.update.
1157 if update:
1157 if update:
1158 qp = self.qparents(repo, rev)
1158 qp = self.qparents(repo, rev)
1159 ctx = repo[qp]
1159 ctx = repo[qp]
1160 m, a, r, d = repo.status(qp, top)[:4]
1160 m, a, r, d = repo.status(qp, top)[:4]
1161 if d:
1161 if d:
1162 raise util.Abort(_("deletions found between repo revs"))
1162 raise util.Abort(_("deletions found between repo revs"))
1163 for f in a:
1163 for f in a:
1164 try:
1164 try:
1165 util.unlink(repo.wjoin(f))
1165 util.unlink(repo.wjoin(f))
1166 except OSError, e:
1166 except OSError, e:
1167 if e.errno != errno.ENOENT:
1167 if e.errno != errno.ENOENT:
1168 raise
1168 raise
1169 repo.dirstate.forget(f)
1169 repo.dirstate.forget(f)
1170 for f in m + r:
1170 for f in m + r:
1171 fctx = ctx[f]
1171 fctx = ctx[f]
1172 repo.wwrite(f, fctx.data(), fctx.flags())
1172 repo.wwrite(f, fctx.data(), fctx.flags())
1173 repo.dirstate.normal(f)
1173 repo.dirstate.normal(f)
1174 repo.dirstate.setparents(qp, nullid)
1174 repo.dirstate.setparents(qp, nullid)
1175 for patch in reversed(self.applied[start:end]):
1175 for patch in reversed(self.applied[start:end]):
1176 self.ui.status(_("popping %s\n") % patch.name)
1176 self.ui.status(_("popping %s\n") % patch.name)
1177 del self.applied[start:end]
1177 del self.applied[start:end]
1178 self.strip(repo, rev, update=False, backup='strip')
1178 self.strip(repo, rev, update=False, backup='strip')
1179 if self.applied:
1179 if self.applied:
1180 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1180 self.ui.write(_("now at: %s\n") % self.applied[-1].name)
1181 else:
1181 else:
1182 self.ui.write(_("patch queue now empty\n"))
1182 self.ui.write(_("patch queue now empty\n"))
1183 finally:
1183 finally:
1184 wlock.release()
1184 wlock.release()
1185
1185
1186 def diff(self, repo, pats, opts):
1186 def diff(self, repo, pats, opts):
1187 top, patch = self.check_toppatch(repo)
1187 top, patch = self.check_toppatch(repo)
1188 if not top:
1188 if not top:
1189 self.ui.write(_("no patches applied\n"))
1189 self.ui.write(_("no patches applied\n"))
1190 return
1190 return
1191 qp = self.qparents(repo, top)
1191 qp = self.qparents(repo, top)
1192 if opts.get('reverse'):
1192 if opts.get('reverse'):
1193 node1, node2 = None, qp
1193 node1, node2 = None, qp
1194 else:
1194 else:
1195 node1, node2 = qp, None
1195 node1, node2 = qp, None
1196 diffopts = self.diffopts(opts, patch)
1196 diffopts = self.diffopts(opts, patch)
1197 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1197 self.printdiff(repo, diffopts, node1, node2, files=pats, opts=opts)
1198
1198
1199 def refresh(self, repo, pats=None, **opts):
1199 def refresh(self, repo, pats=None, **opts):
1200 if not self.applied:
1200 if not self.applied:
1201 self.ui.write(_("no patches applied\n"))
1201 self.ui.write(_("no patches applied\n"))
1202 return 1
1202 return 1
1203 msg = opts.get('msg', '').rstrip()
1203 msg = opts.get('msg', '').rstrip()
1204 newuser = opts.get('user')
1204 newuser = opts.get('user')
1205 newdate = opts.get('date')
1205 newdate = opts.get('date')
1206 if newdate:
1206 if newdate:
1207 newdate = '%d %d' % util.parsedate(newdate)
1207 newdate = '%d %d' % util.parsedate(newdate)
1208 wlock = repo.wlock()
1208 wlock = repo.wlock()
1209
1209
1210 try:
1210 try:
1211 self.check_toppatch(repo)
1211 self.check_toppatch(repo)
1212 (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
1212 (top, patchfn) = (self.applied[-1].node, self.applied[-1].name)
1213 if repo.changelog.heads(top) != [top]:
1213 if repo.changelog.heads(top) != [top]:
1214 raise util.Abort(_("cannot refresh a revision with children"))
1214 raise util.Abort(_("cannot refresh a revision with children"))
1215
1215
1216 cparents = repo.changelog.parents(top)
1216 cparents = repo.changelog.parents(top)
1217 patchparent = self.qparents(repo, top)
1217 patchparent = self.qparents(repo, top)
1218 ph = patchheader(self.join(patchfn), self.plainmode)
1218 ph = patchheader(self.join(patchfn), self.plainmode)
1219 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1219 diffopts = self.diffopts({'git': opts.get('git')}, patchfn)
1220 if msg:
1220 if msg:
1221 ph.setmessage(msg)
1221 ph.setmessage(msg)
1222 if newuser:
1222 if newuser:
1223 ph.setuser(newuser)
1223 ph.setuser(newuser)
1224 if newdate:
1224 if newdate:
1225 ph.setdate(newdate)
1225 ph.setdate(newdate)
1226 ph.setparent(hex(patchparent))
1226 ph.setparent(hex(patchparent))
1227
1227
1228 # only commit new patch when write is complete
1228 # only commit new patch when write is complete
1229 patchf = self.opener(patchfn, 'w', atomictemp=True)
1229 patchf = self.opener(patchfn, 'w', atomictemp=True)
1230
1230
1231 comments = str(ph)
1231 comments = str(ph)
1232 if comments:
1232 if comments:
1233 patchf.write(comments)
1233 patchf.write(comments)
1234
1234
1235 # update the dirstate in place, strip off the qtip commit
1235 # update the dirstate in place, strip off the qtip commit
1236 # and then commit.
1236 # and then commit.
1237 #
1237 #
1238 # this should really read:
1238 # this should really read:
1239 # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
1239 # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
1240 # but we do it backwards to take advantage of manifest/chlog
1240 # but we do it backwards to take advantage of manifest/chlog
1241 # caching against the next repo.status call
1241 # caching against the next repo.status call
1242 mm, aa, dd, aa2 = repo.status(patchparent, top)[:4]
1242 mm, aa, dd, aa2 = repo.status(patchparent, top)[:4]
1243 changes = repo.changelog.read(top)
1243 changes = repo.changelog.read(top)
1244 man = repo.manifest.read(changes[0])
1244 man = repo.manifest.read(changes[0])
1245 aaa = aa[:]
1245 aaa = aa[:]
1246 matchfn = cmdutil.match(repo, pats, opts)
1246 matchfn = cmdutil.match(repo, pats, opts)
1247 # in short mode, we only diff the files included in the
1247 # in short mode, we only diff the files included in the
1248 # patch already plus specified files
1248 # patch already plus specified files
1249 if opts.get('short'):
1249 if opts.get('short'):
1250 # if amending a patch, we start with existing
1250 # if amending a patch, we start with existing
1251 # files plus specified files - unfiltered
1251 # files plus specified files - unfiltered
1252 match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1252 match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1253 # filter with inc/exl options
1253 # filter with inc/exl options
1254 matchfn = cmdutil.match(repo, opts=opts)
1254 matchfn = cmdutil.match(repo, opts=opts)
1255 else:
1255 else:
1256 match = cmdutil.matchall(repo)
1256 match = cmdutil.matchall(repo)
1257 m, a, r, d = repo.status(match=match)[:4]
1257 m, a, r, d = repo.status(match=match)[:4]
1258
1258
1259 # we might end up with files that were added between
1259 # we might end up with files that were added between
1260 # qtip and the dirstate parent, but then changed in the
1260 # qtip and the dirstate parent, but then changed in the
1261 # local dirstate. in this case, we want them to only
1261 # local dirstate. in this case, we want them to only
1262 # show up in the added section
1262 # show up in the added section
1263 for x in m:
1263 for x in m:
1264 if x not in aa:
1264 if x not in aa:
1265 mm.append(x)
1265 mm.append(x)
1266 # we might end up with files added by the local dirstate that
1266 # we might end up with files added by the local dirstate that
1267 # were deleted by the patch. In this case, they should only
1267 # were deleted by the patch. In this case, they should only
1268 # show up in the changed section.
1268 # show up in the changed section.
1269 for x in a:
1269 for x in a:
1270 if x in dd:
1270 if x in dd:
1271 del dd[dd.index(x)]
1271 del dd[dd.index(x)]
1272 mm.append(x)
1272 mm.append(x)
1273 else:
1273 else:
1274 aa.append(x)
1274 aa.append(x)
1275 # make sure any files deleted in the local dirstate
1275 # make sure any files deleted in the local dirstate
1276 # are not in the add or change column of the patch
1276 # are not in the add or change column of the patch
1277 forget = []
1277 forget = []
1278 for x in d + r:
1278 for x in d + r:
1279 if x in aa:
1279 if x in aa:
1280 del aa[aa.index(x)]
1280 del aa[aa.index(x)]
1281 forget.append(x)
1281 forget.append(x)
1282 continue
1282 continue
1283 elif x in mm:
1283 elif x in mm:
1284 del mm[mm.index(x)]
1284 del mm[mm.index(x)]
1285 dd.append(x)
1285 dd.append(x)
1286
1286
1287 m = list(set(mm))
1287 m = list(set(mm))
1288 r = list(set(dd))
1288 r = list(set(dd))
1289 a = list(set(aa))
1289 a = list(set(aa))
1290 c = [filter(matchfn, l) for l in (m, a, r)]
1290 c = [filter(matchfn, l) for l in (m, a, r)]
1291 match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2]))
1291 match = cmdutil.matchfiles(repo, set(c[0] + c[1] + c[2]))
1292 chunks = patch.diff(repo, patchparent, match=match,
1292 chunks = patch.diff(repo, patchparent, match=match,
1293 changes=c, opts=diffopts)
1293 changes=c, opts=diffopts)
1294 for chunk in chunks:
1294 for chunk in chunks:
1295 patchf.write(chunk)
1295 patchf.write(chunk)
1296
1296
1297 try:
1297 try:
1298 if diffopts.git or diffopts.upgrade:
1298 if diffopts.git or diffopts.upgrade:
1299 copies = {}
1299 copies = {}
1300 for dst in a:
1300 for dst in a:
1301 src = repo.dirstate.copied(dst)
1301 src = repo.dirstate.copied(dst)
1302 # during qfold, the source file for copies may
1302 # during qfold, the source file for copies may
1303 # be removed. Treat this as a simple add.
1303 # be removed. Treat this as a simple add.
1304 if src is not None and src in repo.dirstate:
1304 if src is not None and src in repo.dirstate:
1305 copies.setdefault(src, []).append(dst)
1305 copies.setdefault(src, []).append(dst)
1306 repo.dirstate.add(dst)
1306 repo.dirstate.add(dst)
1307 # remember the copies between patchparent and qtip
1307 # remember the copies between patchparent and qtip
1308 for dst in aaa:
1308 for dst in aaa:
1309 f = repo.file(dst)
1309 f = repo.file(dst)
1310 src = f.renamed(man[dst])
1310 src = f.renamed(man[dst])
1311 if src:
1311 if src:
1312 copies.setdefault(src[0], []).extend(
1312 copies.setdefault(src[0], []).extend(
1313 copies.get(dst, []))
1313 copies.get(dst, []))
1314 if dst in a:
1314 if dst in a:
1315 copies[src[0]].append(dst)
1315 copies[src[0]].append(dst)
1316 # we can't copy a file created by the patch itself
1316 # we can't copy a file created by the patch itself
1317 if dst in copies:
1317 if dst in copies:
1318 del copies[dst]
1318 del copies[dst]
1319 for src, dsts in copies.iteritems():
1319 for src, dsts in copies.iteritems():
1320 for dst in dsts:
1320 for dst in dsts:
1321 repo.dirstate.copy(src, dst)
1321 repo.dirstate.copy(src, dst)
1322 else:
1322 else:
1323 for dst in a:
1323 for dst in a:
1324 repo.dirstate.add(dst)
1324 repo.dirstate.add(dst)
1325 # Drop useless copy information
1325 # Drop useless copy information
1326 for f in list(repo.dirstate.copies()):
1326 for f in list(repo.dirstate.copies()):
1327 repo.dirstate.copy(None, f)
1327 repo.dirstate.copy(None, f)
1328 for f in r:
1328 for f in r:
1329 repo.dirstate.remove(f)
1329 repo.dirstate.remove(f)
1330 # if the patch excludes a modified file, mark that
1330 # if the patch excludes a modified file, mark that
1331 # file with mtime=0 so status can see it.
1331 # file with mtime=0 so status can see it.
1332 mm = []
1332 mm = []
1333 for i in xrange(len(m)-1, -1, -1):
1333 for i in xrange(len(m)-1, -1, -1):
1334 if not matchfn(m[i]):
1334 if not matchfn(m[i]):
1335 mm.append(m[i])
1335 mm.append(m[i])
1336 del m[i]
1336 del m[i]
1337 for f in m:
1337 for f in m:
1338 repo.dirstate.normal(f)
1338 repo.dirstate.normal(f)
1339 for f in mm:
1339 for f in mm:
1340 repo.dirstate.normallookup(f)
1340 repo.dirstate.normallookup(f)
1341 for f in forget:
1341 for f in forget:
1342 repo.dirstate.forget(f)
1342 repo.dirstate.forget(f)
1343
1343
1344 if not msg:
1344 if not msg:
1345 if not ph.message:
1345 if not ph.message:
1346 message = "[mq]: %s\n" % patchfn
1346 message = "[mq]: %s\n" % patchfn
1347 else:
1347 else:
1348 message = "\n".join(ph.message)
1348 message = "\n".join(ph.message)
1349 else:
1349 else:
1350 message = msg
1350 message = msg
1351
1351
1352 user = ph.user or changes[1]
1352 user = ph.user or changes[1]
1353
1353
1354 # assumes strip can roll itself back if interrupted
1354 # assumes strip can roll itself back if interrupted
1355 repo.dirstate.setparents(*cparents)
1355 repo.dirstate.setparents(*cparents)
1356 self.applied.pop()
1356 self.applied.pop()
1357 self.applied_dirty = 1
1357 self.applied_dirty = 1
1358 self.strip(repo, top, update=False,
1358 self.strip(repo, top, update=False,
1359 backup='strip')
1359 backup='strip')
1360 except:
1360 except:
1361 repo.dirstate.invalidate()
1361 repo.dirstate.invalidate()
1362 raise
1362 raise
1363
1363
1364 try:
1364 try:
1365 # might be nice to attempt to roll back strip after this
1365 # might be nice to attempt to roll back strip after this
1366 patchf.rename()
1366 patchf.rename()
1367 n = repo.commit(message, user, ph.date, match=match,
1367 n = repo.commit(message, user, ph.date, match=match,
1368 force=True)
1368 force=True)
1369 self.applied.append(statusentry(n, patchfn))
1369 self.applied.append(statusentry(n, patchfn))
1370 except:
1370 except:
1371 ctx = repo[cparents[0]]
1371 ctx = repo[cparents[0]]
1372 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1372 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1373 self.save_dirty()
1373 self.save_dirty()
1374 self.ui.warn(_('refresh interrupted while patch was popped! '
1374 self.ui.warn(_('refresh interrupted while patch was popped! '
1375 '(revert --all, qpush to recover)\n'))
1375 '(revert --all, qpush to recover)\n'))
1376 raise
1376 raise
1377 finally:
1377 finally:
1378 wlock.release()
1378 wlock.release()
1379 self.removeundo(repo)
1379 self.removeundo(repo)
1380
1380
1381 def init(self, repo, create=False):
1381 def init(self, repo, create=False):
1382 if not create and os.path.isdir(self.path):
1382 if not create and os.path.isdir(self.path):
1383 raise util.Abort(_("patch queue directory already exists"))
1383 raise util.Abort(_("patch queue directory already exists"))
1384 try:
1384 try:
1385 os.mkdir(self.path)
1385 os.mkdir(self.path)
1386 except OSError, inst:
1386 except OSError, inst:
1387 if inst.errno != errno.EEXIST or not create:
1387 if inst.errno != errno.EEXIST or not create:
1388 raise
1388 raise
1389 if create:
1389 if create:
1390 return self.qrepo(create=True)
1390 return self.qrepo(create=True)
1391
1391
1392 def unapplied(self, repo, patch=None):
1392 def unapplied(self, repo, patch=None):
1393 if patch and patch not in self.series:
1393 if patch and patch not in self.series:
1394 raise util.Abort(_("patch %s is not in series file") % patch)
1394 raise util.Abort(_("patch %s is not in series file") % patch)
1395 if not patch:
1395 if not patch:
1396 start = self.series_end()
1396 start = self.series_end()
1397 else:
1397 else:
1398 start = self.series.index(patch) + 1
1398 start = self.series.index(patch) + 1
1399 unapplied = []
1399 unapplied = []
1400 for i in xrange(start, len(self.series)):
1400 for i in xrange(start, len(self.series)):
1401 pushable, reason = self.pushable(i)
1401 pushable, reason = self.pushable(i)
1402 if pushable:
1402 if pushable:
1403 unapplied.append((i, self.series[i]))
1403 unapplied.append((i, self.series[i]))
1404 self.explain_pushable(i)
1404 self.explain_pushable(i)
1405 return unapplied
1405 return unapplied
1406
1406
1407 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1407 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1408 summary=False):
1408 summary=False):
1409 def displayname(pfx, patchname, state):
1409 def displayname(pfx, patchname, state):
1410 if pfx:
1410 if pfx:
1411 self.ui.write(pfx)
1411 self.ui.write(pfx)
1412 if summary:
1412 if summary:
1413 ph = patchheader(self.join(patchname), self.plainmode)
1413 ph = patchheader(self.join(patchname), self.plainmode)
1414 msg = ph.message and ph.message[0] or ''
1414 msg = ph.message and ph.message[0] or ''
1415 if not self.ui.plain():
1415 if not self.ui.plain():
1416 width = util.termwidth() - len(pfx) - len(patchname) - 2
1416 width = util.termwidth() - len(pfx) - len(patchname) - 2
1417 if width > 0:
1417 if width > 0:
1418 msg = util.ellipsis(msg, width)
1418 msg = util.ellipsis(msg, width)
1419 else:
1419 else:
1420 msg = ''
1420 msg = ''
1421 self.ui.write(patchname, label='qseries.' + state)
1421 self.ui.write(patchname, label='qseries.' + state)
1422 self.ui.write(': ')
1422 self.ui.write(': ')
1423 self.ui.write(msg, label='qseries.message.' + state)
1423 self.ui.write(msg, label='qseries.message.' + state)
1424 else:
1424 else:
1425 self.ui.write(patchname, label='qseries.' + state)
1425 self.ui.write(patchname, label='qseries.' + state)
1426 self.ui.write('\n')
1426 self.ui.write('\n')
1427
1427
1428 applied = set([p.name for p in self.applied])
1428 applied = set([p.name for p in self.applied])
1429 if length is None:
1429 if length is None:
1430 length = len(self.series) - start
1430 length = len(self.series) - start
1431 if not missing:
1431 if not missing:
1432 if self.ui.verbose:
1432 if self.ui.verbose:
1433 idxwidth = len(str(start + length - 1))
1433 idxwidth = len(str(start + length - 1))
1434 for i in xrange(start, start + length):
1434 for i in xrange(start, start + length):
1435 patch = self.series[i]
1435 patch = self.series[i]
1436 if patch in applied:
1436 if patch in applied:
1437 char, state = 'A', 'applied'
1437 char, state = 'A', 'applied'
1438 elif self.pushable(i)[0]:
1438 elif self.pushable(i)[0]:
1439 char, state = 'U', 'unapplied'
1439 char, state = 'U', 'unapplied'
1440 else:
1440 else:
1441 char, state = 'G', 'guarded'
1441 char, state = 'G', 'guarded'
1442 pfx = ''
1442 pfx = ''
1443 if self.ui.verbose:
1443 if self.ui.verbose:
1444 pfx = '%*d %s ' % (idxwidth, i, char)
1444 pfx = '%*d %s ' % (idxwidth, i, char)
1445 elif status and status != char:
1445 elif status and status != char:
1446 continue
1446 continue
1447 displayname(pfx, patch, state)
1447 displayname(pfx, patch, state)
1448 else:
1448 else:
1449 msng_list = []
1449 msng_list = []
1450 for root, dirs, files in os.walk(self.path):
1450 for root, dirs, files in os.walk(self.path):
1451 d = root[len(self.path) + 1:]
1451 d = root[len(self.path) + 1:]
1452 for f in files:
1452 for f in files:
1453 fl = os.path.join(d, f)
1453 fl = os.path.join(d, f)
1454 if (fl not in self.series and
1454 if (fl not in self.series and
1455 fl not in (self.status_path, self.series_path,
1455 fl not in (self.status_path, self.series_path,
1456 self.guards_path)
1456 self.guards_path)
1457 and not fl.startswith('.')):
1457 and not fl.startswith('.')):
1458 msng_list.append(fl)
1458 msng_list.append(fl)
1459 for x in sorted(msng_list):
1459 for x in sorted(msng_list):
1460 pfx = self.ui.verbose and ('D ') or ''
1460 pfx = self.ui.verbose and ('D ') or ''
1461 displayname(pfx, x, 'missing')
1461 displayname(pfx, x, 'missing')
1462
1462
1463 def issaveline(self, l):
1463 def issaveline(self, l):
1464 if l.name == '.hg.patches.save.line':
1464 if l.name == '.hg.patches.save.line':
1465 return True
1465 return True
1466
1466
1467 def qrepo(self, create=False):
1467 def qrepo(self, create=False):
1468 if create or os.path.isdir(self.join(".hg")):
1468 if create or os.path.isdir(self.join(".hg")):
1469 return hg.repository(self.ui, path=self.path, create=create)
1469 return hg.repository(self.ui, path=self.path, create=create)
1470
1470
1471 def restore(self, repo, rev, delete=None, qupdate=None):
1471 def restore(self, repo, rev, delete=None, qupdate=None):
1472 desc = repo[rev].description().strip()
1472 desc = repo[rev].description().strip()
1473 lines = desc.splitlines()
1473 lines = desc.splitlines()
1474 i = 0
1474 i = 0
1475 datastart = None
1475 datastart = None
1476 series = []
1476 series = []
1477 applied = []
1477 applied = []
1478 qpp = None
1478 qpp = None
1479 for i, line in enumerate(lines):
1479 for i, line in enumerate(lines):
1480 if line == 'Patch Data:':
1480 if line == 'Patch Data:':
1481 datastart = i + 1
1481 datastart = i + 1
1482 elif line.startswith('Dirstate:'):
1482 elif line.startswith('Dirstate:'):
1483 l = line.rstrip()
1483 l = line.rstrip()
1484 l = l[10:].split(' ')
1484 l = l[10:].split(' ')
1485 qpp = [bin(x) for x in l]
1485 qpp = [bin(x) for x in l]
1486 elif datastart != None:
1486 elif datastart != None:
1487 l = line.rstrip()
1487 l = line.rstrip()
1488 n, name = l.split(':', 1)
1488 n, name = l.split(':', 1)
1489 if n:
1489 if n:
1490 applied.append(statusentry(bin(n), name))
1490 applied.append(statusentry(bin(n), name))
1491 else:
1491 else:
1492 series.append(l)
1492 series.append(l)
1493 if datastart is None:
1493 if datastart is None:
1494 self.ui.warn(_("No saved patch data found\n"))
1494 self.ui.warn(_("No saved patch data found\n"))
1495 return 1
1495 return 1
1496 self.ui.warn(_("restoring status: %s\n") % lines[0])
1496 self.ui.warn(_("restoring status: %s\n") % lines[0])
1497 self.full_series = series
1497 self.full_series = series
1498 self.applied = applied
1498 self.applied = applied
1499 self.parse_series()
1499 self.parse_series()
1500 self.series_dirty = 1
1500 self.series_dirty = 1
1501 self.applied_dirty = 1
1501 self.applied_dirty = 1
1502 heads = repo.changelog.heads()
1502 heads = repo.changelog.heads()
1503 if delete:
1503 if delete:
1504 if rev not in heads:
1504 if rev not in heads:
1505 self.ui.warn(_("save entry has children, leaving it alone\n"))
1505 self.ui.warn(_("save entry has children, leaving it alone\n"))
1506 else:
1506 else:
1507 self.ui.warn(_("removing save entry %s\n") % short(rev))
1507 self.ui.warn(_("removing save entry %s\n") % short(rev))
1508 pp = repo.dirstate.parents()
1508 pp = repo.dirstate.parents()
1509 if rev in pp:
1509 if rev in pp:
1510 update = True
1510 update = True
1511 else:
1511 else:
1512 update = False
1512 update = False
1513 self.strip(repo, rev, update=update, backup='strip')
1513 self.strip(repo, rev, update=update, backup='strip')
1514 if qpp:
1514 if qpp:
1515 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1515 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1516 (short(qpp[0]), short(qpp[1])))
1516 (short(qpp[0]), short(qpp[1])))
1517 if qupdate:
1517 if qupdate:
1518 self.ui.status(_("queue directory updating\n"))
1518 self.ui.status(_("queue directory updating\n"))
1519 r = self.qrepo()
1519 r = self.qrepo()
1520 if not r:
1520 if not r:
1521 self.ui.warn(_("Unable to load queue repository\n"))
1521 self.ui.warn(_("Unable to load queue repository\n"))
1522 return 1
1522 return 1
1523 hg.clean(r, qpp[0])
1523 hg.clean(r, qpp[0])
1524
1524
1525 def save(self, repo, msg=None):
1525 def save(self, repo, msg=None):
1526 if not self.applied:
1526 if not self.applied:
1527 self.ui.warn(_("save: no patches applied, exiting\n"))
1527 self.ui.warn(_("save: no patches applied, exiting\n"))
1528 return 1
1528 return 1
1529 if self.issaveline(self.applied[-1]):
1529 if self.issaveline(self.applied[-1]):
1530 self.ui.warn(_("status is already saved\n"))
1530 self.ui.warn(_("status is already saved\n"))
1531 return 1
1531 return 1
1532
1532
1533 if not msg:
1533 if not msg:
1534 msg = _("hg patches saved state")
1534 msg = _("hg patches saved state")
1535 else:
1535 else:
1536 msg = "hg patches: " + msg.rstrip('\r\n')
1536 msg = "hg patches: " + msg.rstrip('\r\n')
1537 r = self.qrepo()
1537 r = self.qrepo()
1538 if r:
1538 if r:
1539 pp = r.dirstate.parents()
1539 pp = r.dirstate.parents()
1540 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1540 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1541 msg += "\n\nPatch Data:\n"
1541 msg += "\n\nPatch Data:\n"
1542 msg += ''.join('%s\n' % x for x in self.applied)
1542 msg += ''.join('%s\n' % x for x in self.applied)
1543 msg += ''.join(':%s\n' % x for x in self.full_series)
1543 msg += ''.join(':%s\n' % x for x in self.full_series)
1544 n = repo.commit(msg, force=True)
1544 n = repo.commit(msg, force=True)
1545 if not n:
1545 if not n:
1546 self.ui.warn(_("repo commit failed\n"))
1546 self.ui.warn(_("repo commit failed\n"))
1547 return 1
1547 return 1
1548 self.applied.append(statusentry(n, '.hg.patches.save.line'))
1548 self.applied.append(statusentry(n, '.hg.patches.save.line'))
1549 self.applied_dirty = 1
1549 self.applied_dirty = 1
1550 self.removeundo(repo)
1550 self.removeundo(repo)
1551
1551
1552 def full_series_end(self):
1552 def full_series_end(self):
1553 if self.applied:
1553 if self.applied:
1554 p = self.applied[-1].name
1554 p = self.applied[-1].name
1555 end = self.find_series(p)
1555 end = self.find_series(p)
1556 if end is None:
1556 if end is None:
1557 return len(self.full_series)
1557 return len(self.full_series)
1558 return end + 1
1558 return end + 1
1559 return 0
1559 return 0
1560
1560
1561 def series_end(self, all_patches=False):
1561 def series_end(self, all_patches=False):
1562 """If all_patches is False, return the index of the next pushable patch
1562 """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
1563 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.
1564 index of the first patch past the last applied one.
1565 """
1565 """
1566 end = 0
1566 end = 0
1567 def next(start):
1567 def next(start):
1568 if all_patches or start >= len(self.series):
1568 if all_patches or start >= len(self.series):
1569 return start
1569 return start
1570 for i in xrange(start, len(self.series)):
1570 for i in xrange(start, len(self.series)):
1571 p, reason = self.pushable(i)
1571 p, reason = self.pushable(i)
1572 if p:
1572 if p:
1573 break
1573 break
1574 self.explain_pushable(i)
1574 self.explain_pushable(i)
1575 return i
1575 return i
1576 if self.applied:
1576 if self.applied:
1577 p = self.applied[-1].name
1577 p = self.applied[-1].name
1578 try:
1578 try:
1579 end = self.series.index(p)
1579 end = self.series.index(p)
1580 except ValueError:
1580 except ValueError:
1581 return 0
1581 return 0
1582 return next(end + 1)
1582 return next(end + 1)
1583 return next(end)
1583 return next(end)
1584
1584
1585 def appliedname(self, index):
1585 def appliedname(self, index):
1586 pname = self.applied[index].name
1586 pname = self.applied[index].name
1587 if not self.ui.verbose:
1587 if not self.ui.verbose:
1588 p = pname
1588 p = pname
1589 else:
1589 else:
1590 p = str(self.series.index(pname)) + " " + pname
1590 p = str(self.series.index(pname)) + " " + pname
1591 return p
1591 return p
1592
1592
1593 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1593 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1594 force=None, git=False):
1594 force=None, git=False):
1595 def checkseries(patchname):
1595 def checkseries(patchname):
1596 if patchname in self.series:
1596 if patchname in self.series:
1597 raise util.Abort(_('patch %s is already in the series file')
1597 raise util.Abort(_('patch %s is already in the series file')
1598 % patchname)
1598 % patchname)
1599 def checkfile(patchname):
1599 def checkfile(patchname):
1600 if not force and os.path.exists(self.join(patchname)):
1600 if not force and os.path.exists(self.join(patchname)):
1601 raise util.Abort(_('patch "%s" already exists')
1601 raise util.Abort(_('patch "%s" already exists')
1602 % patchname)
1602 % patchname)
1603
1603
1604 if rev:
1604 if rev:
1605 if files:
1605 if files:
1606 raise util.Abort(_('option "-r" not valid when importing '
1606 raise util.Abort(_('option "-r" not valid when importing '
1607 'files'))
1607 'files'))
1608 rev = cmdutil.revrange(repo, rev)
1608 rev = cmdutil.revrange(repo, rev)
1609 rev.sort(reverse=True)
1609 rev.sort(reverse=True)
1610 if (len(files) > 1 or len(rev) > 1) and patchname:
1610 if (len(files) > 1 or len(rev) > 1) and patchname:
1611 raise util.Abort(_('option "-n" not valid when importing multiple '
1611 raise util.Abort(_('option "-n" not valid when importing multiple '
1612 'patches'))
1612 'patches'))
1613 added = []
1613 added = []
1614 if rev:
1614 if rev:
1615 # If mq patches are applied, we can only import revisions
1615 # If mq patches are applied, we can only import revisions
1616 # that form a linear path to qbase.
1616 # that form a linear path to qbase.
1617 # Otherwise, they should form a linear path to a head.
1617 # Otherwise, they should form a linear path to a head.
1618 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1618 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1619 if len(heads) > 1:
1619 if len(heads) > 1:
1620 raise util.Abort(_('revision %d is the root of more than one '
1620 raise util.Abort(_('revision %d is the root of more than one '
1621 'branch') % rev[-1])
1621 'branch') % rev[-1])
1622 if self.applied:
1622 if self.applied:
1623 base = repo.changelog.node(rev[0])
1623 base = repo.changelog.node(rev[0])
1624 if base in [n.node for n in self.applied]:
1624 if base in [n.node for n in self.applied]:
1625 raise util.Abort(_('revision %d is already managed')
1625 raise util.Abort(_('revision %d is already managed')
1626 % rev[0])
1626 % rev[0])
1627 if heads != [self.applied[-1].node]:
1627 if heads != [self.applied[-1].node]:
1628 raise util.Abort(_('revision %d is not the parent of '
1628 raise util.Abort(_('revision %d is not the parent of '
1629 'the queue') % rev[0])
1629 'the queue') % rev[0])
1630 base = repo.changelog.rev(self.applied[0].node)
1630 base = repo.changelog.rev(self.applied[0].node)
1631 lastparent = repo.changelog.parentrevs(base)[0]
1631 lastparent = repo.changelog.parentrevs(base)[0]
1632 else:
1632 else:
1633 if heads != [repo.changelog.node(rev[0])]:
1633 if heads != [repo.changelog.node(rev[0])]:
1634 raise util.Abort(_('revision %d has unmanaged children')
1634 raise util.Abort(_('revision %d has unmanaged children')
1635 % rev[0])
1635 % rev[0])
1636 lastparent = None
1636 lastparent = None
1637
1637
1638 diffopts = self.diffopts({'git': git})
1638 diffopts = self.diffopts({'git': git})
1639 for r in rev:
1639 for r in rev:
1640 p1, p2 = repo.changelog.parentrevs(r)
1640 p1, p2 = repo.changelog.parentrevs(r)
1641 n = repo.changelog.node(r)
1641 n = repo.changelog.node(r)
1642 if p2 != nullrev:
1642 if p2 != nullrev:
1643 raise util.Abort(_('cannot import merge revision %d') % r)
1643 raise util.Abort(_('cannot import merge revision %d') % r)
1644 if lastparent and lastparent != r:
1644 if lastparent and lastparent != r:
1645 raise util.Abort(_('revision %d is not the parent of %d')
1645 raise util.Abort(_('revision %d is not the parent of %d')
1646 % (r, lastparent))
1646 % (r, lastparent))
1647 lastparent = p1
1647 lastparent = p1
1648
1648
1649 if not patchname:
1649 if not patchname:
1650 patchname = normname('%d.diff' % r)
1650 patchname = normname('%d.diff' % r)
1651 self.check_reserved_name(patchname)
1651 self.check_reserved_name(patchname)
1652 checkseries(patchname)
1652 checkseries(patchname)
1653 checkfile(patchname)
1653 checkfile(patchname)
1654 self.full_series.insert(0, patchname)
1654 self.full_series.insert(0, patchname)
1655
1655
1656 patchf = self.opener(patchname, "w")
1656 patchf = self.opener(patchname, "w")
1657 cmdutil.export(repo, [n], fp=patchf, opts=diffopts)
1657 cmdutil.export(repo, [n], fp=patchf, opts=diffopts)
1658 patchf.close()
1658 patchf.close()
1659
1659
1660 se = statusentry(n, patchname)
1660 se = statusentry(n, patchname)
1661 self.applied.insert(0, se)
1661 self.applied.insert(0, se)
1662
1662
1663 added.append(patchname)
1663 added.append(patchname)
1664 patchname = None
1664 patchname = None
1665 self.parse_series()
1665 self.parse_series()
1666 self.applied_dirty = 1
1666 self.applied_dirty = 1
1667
1667
1668 for i, filename in enumerate(files):
1668 for i, filename in enumerate(files):
1669 if existing:
1669 if existing:
1670 if filename == '-':
1670 if filename == '-':
1671 raise util.Abort(_('-e is incompatible with import from -'))
1671 raise util.Abort(_('-e is incompatible with import from -'))
1672 if not patchname:
1672 if not patchname:
1673 patchname = normname(filename)
1673 patchname = normname(filename)
1674 self.check_reserved_name(patchname)
1674 self.check_reserved_name(patchname)
1675 if not os.path.isfile(self.join(patchname)):
1675 if not os.path.isfile(self.join(patchname)):
1676 raise util.Abort(_("patch %s does not exist") % patchname)
1676 raise util.Abort(_("patch %s does not exist") % patchname)
1677 else:
1677 else:
1678 try:
1678 try:
1679 if filename == '-':
1679 if filename == '-':
1680 if not patchname:
1680 if not patchname:
1681 raise util.Abort(
1681 raise util.Abort(
1682 _('need --name to import a patch from -'))
1682 _('need --name to import a patch from -'))
1683 text = sys.stdin.read()
1683 text = sys.stdin.read()
1684 else:
1684 else:
1685 text = url.open(self.ui, filename).read()
1685 text = url.open(self.ui, filename).read()
1686 except (OSError, IOError):
1686 except (OSError, IOError):
1687 raise util.Abort(_("unable to read %s") % filename)
1687 raise util.Abort(_("unable to read %s") % filename)
1688 if not patchname:
1688 if not patchname:
1689 patchname = normname(os.path.basename(filename))
1689 patchname = normname(os.path.basename(filename))
1690 self.check_reserved_name(patchname)
1690 self.check_reserved_name(patchname)
1691 checkfile(patchname)
1691 checkfile(patchname)
1692 patchf = self.opener(patchname, "w")
1692 patchf = self.opener(patchname, "w")
1693 patchf.write(text)
1693 patchf.write(text)
1694 if not force:
1694 if not force:
1695 checkseries(patchname)
1695 checkseries(patchname)
1696 if patchname not in self.series:
1696 if patchname not in self.series:
1697 index = self.full_series_end() + i
1697 index = self.full_series_end() + i
1698 self.full_series[index:index] = [patchname]
1698 self.full_series[index:index] = [patchname]
1699 self.parse_series()
1699 self.parse_series()
1700 self.ui.warn(_("adding %s to series file\n") % patchname)
1700 self.ui.warn(_("adding %s to series file\n") % patchname)
1701 added.append(patchname)
1701 added.append(patchname)
1702 patchname = None
1702 patchname = None
1703 self.series_dirty = 1
1703 self.series_dirty = 1
1704 qrepo = self.qrepo()
1704 qrepo = self.qrepo()
1705 if qrepo:
1705 if qrepo:
1706 qrepo.add(added)
1706 qrepo.add(added)
1707
1707
1708 def delete(ui, repo, *patches, **opts):
1708 def delete(ui, repo, *patches, **opts):
1709 """remove patches from queue
1709 """remove patches from queue
1710
1710
1711 The patches must not be applied, and at least one patch is required. With
1711 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.
1712 -k/--keep, the patch files are preserved in the patch directory.
1713
1713
1714 To stop managing a patch and move it into permanent history,
1714 To stop managing a patch and move it into permanent history,
1715 use the qfinish command."""
1715 use the qfinish command."""
1716 q = repo.mq
1716 q = repo.mq
1717 q.delete(repo, patches, opts)
1717 q.delete(repo, patches, opts)
1718 q.save_dirty()
1718 q.save_dirty()
1719 return 0
1719 return 0
1720
1720
1721 def applied(ui, repo, patch=None, **opts):
1721 def applied(ui, repo, patch=None, **opts):
1722 """print the patches already applied"""
1722 """print the patches already applied"""
1723
1723
1724 q = repo.mq
1724 q = repo.mq
1725 l = len(q.applied)
1725 l = len(q.applied)
1726
1726
1727 if patch:
1727 if patch:
1728 if patch not in q.series:
1728 if patch not in q.series:
1729 raise util.Abort(_("patch %s is not in series file") % patch)
1729 raise util.Abort(_("patch %s is not in series file") % patch)
1730 end = q.series.index(patch) + 1
1730 end = q.series.index(patch) + 1
1731 else:
1731 else:
1732 end = q.series_end(True)
1732 end = q.series_end(True)
1733
1733
1734 if opts.get('last') and not end:
1734 if opts.get('last') and not end:
1735 ui.write(_("no patches applied\n"))
1735 ui.write(_("no patches applied\n"))
1736 return 1
1736 return 1
1737 elif opts.get('last') and end == 1:
1737 elif opts.get('last') and end == 1:
1738 ui.write(_("only one patch applied\n"))
1738 ui.write(_("only one patch applied\n"))
1739 return 1
1739 return 1
1740 elif opts.get('last'):
1740 elif opts.get('last'):
1741 start = end - 2
1741 start = end - 2
1742 end = 1
1742 end = 1
1743 else:
1743 else:
1744 start = 0
1744 start = 0
1745
1745
1746 return q.qseries(repo, length=end, start=start, status='A',
1746 return q.qseries(repo, length=end, start=start, status='A',
1747 summary=opts.get('summary'))
1747 summary=opts.get('summary'))
1748
1748
1749 def unapplied(ui, repo, patch=None, **opts):
1749 def unapplied(ui, repo, patch=None, **opts):
1750 """print the patches not yet applied"""
1750 """print the patches not yet applied"""
1751
1751
1752 q = repo.mq
1752 q = repo.mq
1753 if patch:
1753 if patch:
1754 if patch not in q.series:
1754 if patch not in q.series:
1755 raise util.Abort(_("patch %s is not in series file") % patch)
1755 raise util.Abort(_("patch %s is not in series file") % patch)
1756 start = q.series.index(patch) + 1
1756 start = q.series.index(patch) + 1
1757 else:
1757 else:
1758 start = q.series_end(True)
1758 start = q.series_end(True)
1759
1759
1760 if start == len(q.series) and opts.get('first'):
1760 if start == len(q.series) and opts.get('first'):
1761 ui.write(_("all patches applied\n"))
1761 ui.write(_("all patches applied\n"))
1762 return 1
1762 return 1
1763
1763
1764 length = opts.get('first') and 1 or None
1764 length = opts.get('first') and 1 or None
1765 return q.qseries(repo, start=start, length=length, status='U',
1765 return q.qseries(repo, start=start, length=length, status='U',
1766 summary=opts.get('summary'))
1766 summary=opts.get('summary'))
1767
1767
1768 def qimport(ui, repo, *filename, **opts):
1768 def qimport(ui, repo, *filename, **opts):
1769 """import a patch
1769 """import a patch
1770
1770
1771 The patch is inserted into the series after the last applied
1771 The patch is inserted into the series after the last applied
1772 patch. If no patches have been applied, qimport prepends the patch
1772 patch. If no patches have been applied, qimport prepends the patch
1773 to the series.
1773 to the series.
1774
1774
1775 The patch will have the same name as its source file unless you
1775 The patch will have the same name as its source file unless you
1776 give it a new one with -n/--name.
1776 give it a new one with -n/--name.
1777
1777
1778 You can register an existing patch inside the patch directory with
1778 You can register an existing patch inside the patch directory with
1779 the -e/--existing flag.
1779 the -e/--existing flag.
1780
1780
1781 With -f/--force, an existing patch of the same name will be
1781 With -f/--force, an existing patch of the same name will be
1782 overwritten.
1782 overwritten.
1783
1783
1784 An existing changeset may be placed under mq control with -r/--rev
1784 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).
1785 (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
1786 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
1787 format. See the diffs help topic for information on why this is
1788 important for preserving rename/copy information and permission
1788 important for preserving rename/copy information and permission
1789 changes.
1789 changes.
1790
1790
1791 To import a patch from standard input, pass - as the patch file.
1791 To import a patch from standard input, pass - as the patch file.
1792 When importing from standard input, a patch name must be specified
1792 When importing from standard input, a patch name must be specified
1793 using the --name flag.
1793 using the --name flag.
1794 """
1794 """
1795 q = repo.mq
1795 q = repo.mq
1796 q.qimport(repo, filename, patchname=opts['name'],
1796 q.qimport(repo, filename, patchname=opts['name'],
1797 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1797 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1798 git=opts['git'])
1798 git=opts['git'])
1799 q.save_dirty()
1799 q.save_dirty()
1800
1800
1801 if opts.get('push') and not opts.get('rev'):
1801 if opts.get('push') and not opts.get('rev'):
1802 return q.push(repo, None)
1802 return q.push(repo, None)
1803 return 0
1803 return 0
1804
1804
1805 def qinit(ui, repo, create):
1805 def qinit(ui, repo, create):
1806 """initialize a new queue repository
1806 """initialize a new queue repository
1807
1807
1808 This command also creates a series file for ordering patches, and
1808 This command also creates a series file for ordering patches, and
1809 an mq-specific .hgignore file in the queue repository, to exclude
1809 an mq-specific .hgignore file in the queue repository, to exclude
1810 the status and guards files (these contain mostly transient state)."""
1810 the status and guards files (these contain mostly transient state)."""
1811 q = repo.mq
1811 q = repo.mq
1812 r = q.init(repo, create)
1812 r = q.init(repo, create)
1813 q.save_dirty()
1813 q.save_dirty()
1814 if r:
1814 if r:
1815 if not os.path.exists(r.wjoin('.hgignore')):
1815 if not os.path.exists(r.wjoin('.hgignore')):
1816 fp = r.wopener('.hgignore', 'w')
1816 fp = r.wopener('.hgignore', 'w')
1817 fp.write('^\\.hg\n')
1817 fp.write('^\\.hg\n')
1818 fp.write('^\\.mq\n')
1818 fp.write('^\\.mq\n')
1819 fp.write('syntax: glob\n')
1819 fp.write('syntax: glob\n')
1820 fp.write('status\n')
1820 fp.write('status\n')
1821 fp.write('guards\n')
1821 fp.write('guards\n')
1822 fp.close()
1822 fp.close()
1823 if not os.path.exists(r.wjoin('series')):
1823 if not os.path.exists(r.wjoin('series')):
1824 r.wopener('series', 'w').close()
1824 r.wopener('series', 'w').close()
1825 r.add(['.hgignore', 'series'])
1825 r.add(['.hgignore', 'series'])
1826 commands.add(ui, r)
1826 commands.add(ui, r)
1827 return 0
1827 return 0
1828
1828
1829 def init(ui, repo, **opts):
1829 def init(ui, repo, **opts):
1830 """init a new queue repository (DEPRECATED)
1830 """init a new queue repository (DEPRECATED)
1831
1831
1832 The queue repository is unversioned by default. If
1832 The queue repository is unversioned by default. If
1833 -c/--create-repo is specified, qinit will create a separate nested
1833 -c/--create-repo is specified, qinit will create a separate nested
1834 repository for patches (qinit -c may also be run later to convert
1834 repository for patches (qinit -c may also be run later to convert
1835 an unversioned patch repository into a versioned one). You can use
1835 an unversioned patch repository into a versioned one). You can use
1836 qcommit to commit changes to this queue repository.
1836 qcommit to commit changes to this queue repository.
1837
1837
1838 This command is deprecated. Without -c, it's implied by other relevant
1838 This command is deprecated. Without -c, it's implied by other relevant
1839 commands. With -c, use hg init --mq instead."""
1839 commands. With -c, use hg init --mq instead."""
1840 return qinit(ui, repo, create=opts['create_repo'])
1840 return qinit(ui, repo, create=opts['create_repo'])
1841
1841
1842 def clone(ui, source, dest=None, **opts):
1842 def clone(ui, source, dest=None, **opts):
1843 '''clone main and patch repository at same time
1843 '''clone main and patch repository at same time
1844
1844
1845 If source is local, destination will have no patches applied. If
1845 If source is local, destination will have no patches applied. If
1846 source is remote, this command can not check if patches are
1846 source is remote, this command can not check if patches are
1847 applied in source, so cannot guarantee that patches are not
1847 applied in source, so cannot guarantee that patches are not
1848 applied in destination. If you clone remote repository, be sure
1848 applied in destination. If you clone remote repository, be sure
1849 before that it has no patches applied.
1849 before that it has no patches applied.
1850
1850
1851 Source patch repository is looked for in <src>/.hg/patches by
1851 Source patch repository is looked for in <src>/.hg/patches by
1852 default. Use -p <url> to change.
1852 default. Use -p <url> to change.
1853
1853
1854 The patch directory must be a nested Mercurial repository, as
1854 The patch directory must be a nested Mercurial repository, as
1855 would be created by init --mq.
1855 would be created by init --mq.
1856 '''
1856 '''
1857 def patchdir(repo):
1857 def patchdir(repo):
1858 url = repo.url()
1858 url = repo.url()
1859 if url.endswith('/'):
1859 if url.endswith('/'):
1860 url = url[:-1]
1860 url = url[:-1]
1861 return url + '/.hg/patches'
1861 return url + '/.hg/patches'
1862 if dest is None:
1862 if dest is None:
1863 dest = hg.defaultdest(source)
1863 dest = hg.defaultdest(source)
1864 sr = hg.repository(cmdutil.remoteui(ui, opts), ui.expandpath(source))
1864 sr = hg.repository(cmdutil.remoteui(ui, opts), ui.expandpath(source))
1865 if opts['patches']:
1865 if opts['patches']:
1866 patchespath = ui.expandpath(opts['patches'])
1866 patchespath = ui.expandpath(opts['patches'])
1867 else:
1867 else:
1868 patchespath = patchdir(sr)
1868 patchespath = patchdir(sr)
1869 try:
1869 try:
1870 hg.repository(ui, patchespath)
1870 hg.repository(ui, patchespath)
1871 except error.RepoError:
1871 except error.RepoError:
1872 raise util.Abort(_('versioned patch repository not found'
1872 raise util.Abort(_('versioned patch repository not found'
1873 ' (see init --mq)'))
1873 ' (see init --mq)'))
1874 qbase, destrev = None, None
1874 qbase, destrev = None, None
1875 if sr.local():
1875 if sr.local():
1876 if sr.mq.applied:
1876 if sr.mq.applied:
1877 qbase = sr.mq.applied[0].node
1877 qbase = sr.mq.applied[0].node
1878 if not hg.islocal(dest):
1878 if not hg.islocal(dest):
1879 heads = set(sr.heads())
1879 heads = set(sr.heads())
1880 destrev = list(heads.difference(sr.heads(qbase)))
1880 destrev = list(heads.difference(sr.heads(qbase)))
1881 destrev.append(sr.changelog.parents(qbase)[0])
1881 destrev.append(sr.changelog.parents(qbase)[0])
1882 elif sr.capable('lookup'):
1882 elif sr.capable('lookup'):
1883 try:
1883 try:
1884 qbase = sr.lookup('qbase')
1884 qbase = sr.lookup('qbase')
1885 except error.RepoError:
1885 except error.RepoError:
1886 pass
1886 pass
1887 ui.note(_('cloning main repository\n'))
1887 ui.note(_('cloning main repository\n'))
1888 sr, dr = hg.clone(ui, sr.url(), dest,
1888 sr, dr = hg.clone(ui, sr.url(), dest,
1889 pull=opts['pull'],
1889 pull=opts['pull'],
1890 rev=destrev,
1890 rev=destrev,
1891 update=False,
1891 update=False,
1892 stream=opts['uncompressed'])
1892 stream=opts['uncompressed'])
1893 ui.note(_('cloning patch repository\n'))
1893 ui.note(_('cloning patch repository\n'))
1894 hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1894 hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1895 pull=opts['pull'], update=not opts['noupdate'],
1895 pull=opts['pull'], update=not opts['noupdate'],
1896 stream=opts['uncompressed'])
1896 stream=opts['uncompressed'])
1897 if dr.local():
1897 if dr.local():
1898 if qbase:
1898 if qbase:
1899 ui.note(_('stripping applied patches from destination '
1899 ui.note(_('stripping applied patches from destination '
1900 'repository\n'))
1900 'repository\n'))
1901 dr.mq.strip(dr, qbase, update=False, backup=None)
1901 dr.mq.strip(dr, qbase, update=False, backup=None)
1902 if not opts['noupdate']:
1902 if not opts['noupdate']:
1903 ui.note(_('updating destination repository\n'))
1903 ui.note(_('updating destination repository\n'))
1904 hg.update(dr, dr.changelog.tip())
1904 hg.update(dr, dr.changelog.tip())
1905
1905
1906 def commit(ui, repo, *pats, **opts):
1906 def commit(ui, repo, *pats, **opts):
1907 """commit changes in the queue repository (DEPRECATED)
1907 """commit changes in the queue repository (DEPRECATED)
1908
1908
1909 This command is deprecated; use hg commit --mq instead."""
1909 This command is deprecated; use hg commit --mq instead."""
1910 q = repo.mq
1910 q = repo.mq
1911 r = q.qrepo()
1911 r = q.qrepo()
1912 if not r:
1912 if not r:
1913 raise util.Abort('no queue repository')
1913 raise util.Abort('no queue repository')
1914 commands.commit(r.ui, r, *pats, **opts)
1914 commands.commit(r.ui, r, *pats, **opts)
1915
1915
1916 def series(ui, repo, **opts):
1916 def series(ui, repo, **opts):
1917 """print the entire series file"""
1917 """print the entire series file"""
1918 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1918 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1919 return 0
1919 return 0
1920
1920
1921 def top(ui, repo, **opts):
1921 def top(ui, repo, **opts):
1922 """print the name of the current patch"""
1922 """print the name of the current patch"""
1923 q = repo.mq
1923 q = repo.mq
1924 t = q.applied and q.series_end(True) or 0
1924 t = q.applied and q.series_end(True) or 0
1925 if t:
1925 if t:
1926 return q.qseries(repo, start=t - 1, length=1, status='A',
1926 return q.qseries(repo, start=t - 1, length=1, status='A',
1927 summary=opts.get('summary'))
1927 summary=opts.get('summary'))
1928 else:
1928 else:
1929 ui.write(_("no patches applied\n"))
1929 ui.write(_("no patches applied\n"))
1930 return 1
1930 return 1
1931
1931
1932 def next(ui, repo, **opts):
1932 def next(ui, repo, **opts):
1933 """print the name of the next patch"""
1933 """print the name of the next patch"""
1934 q = repo.mq
1934 q = repo.mq
1935 end = q.series_end()
1935 end = q.series_end()
1936 if end == len(q.series):
1936 if end == len(q.series):
1937 ui.write(_("all patches applied\n"))
1937 ui.write(_("all patches applied\n"))
1938 return 1
1938 return 1
1939 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1939 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1940
1940
1941 def prev(ui, repo, **opts):
1941 def prev(ui, repo, **opts):
1942 """print the name of the previous patch"""
1942 """print the name of the previous patch"""
1943 q = repo.mq
1943 q = repo.mq
1944 l = len(q.applied)
1944 l = len(q.applied)
1945 if l == 1:
1945 if l == 1:
1946 ui.write(_("only one patch applied\n"))
1946 ui.write(_("only one patch applied\n"))
1947 return 1
1947 return 1
1948 if not l:
1948 if not l:
1949 ui.write(_("no patches applied\n"))
1949 ui.write(_("no patches applied\n"))
1950 return 1
1950 return 1
1951 return q.qseries(repo, start=l - 2, length=1, status='A',
1951 return q.qseries(repo, start=l - 2, length=1, status='A',
1952 summary=opts.get('summary'))
1952 summary=opts.get('summary'))
1953
1953
1954 def setupheaderopts(ui, opts):
1954 def setupheaderopts(ui, opts):
1955 if not opts.get('user') and opts.get('currentuser'):
1955 if not opts.get('user') and opts.get('currentuser'):
1956 opts['user'] = ui.username()
1956 opts['user'] = ui.username()
1957 if not opts.get('date') and opts.get('currentdate'):
1957 if not opts.get('date') and opts.get('currentdate'):
1958 opts['date'] = "%d %d" % util.makedate()
1958 opts['date'] = "%d %d" % util.makedate()
1959
1959
1960 def new(ui, repo, patch, *args, **opts):
1960 def new(ui, repo, patch, *args, **opts):
1961 """create a new patch
1961 """create a new patch
1962
1962
1963 qnew creates a new patch on top of the currently-applied patch (if
1963 qnew creates a new patch on top of the currently-applied patch (if
1964 any). The patch will be initialized with any outstanding changes
1964 any). The patch will be initialized with any outstanding changes
1965 in the working directory. You may also use -I/--include,
1965 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
1966 -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
1967 only changes to matching files to the new patch, leaving the rest
1968 as uncommitted modifications.
1968 as uncommitted modifications.
1969
1969
1970 -u/--user and -d/--date can be used to set the (given) user and
1970 -u/--user and -d/--date can be used to set the (given) user and
1971 date, respectively. -U/--currentuser and -D/--currentdate set user
1971 date, respectively. -U/--currentuser and -D/--currentdate set user
1972 to current user and date to current date.
1972 to current user and date to current date.
1973
1973
1974 -e/--edit, -m/--message or -l/--logfile set the patch header as
1974 -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
1975 well as the commit message. If none is specified, the header is
1976 empty and the commit message is '[mq]: PATCH'.
1976 empty and the commit message is '[mq]: PATCH'.
1977
1977
1978 Use the -g/--git option to keep the patch in the git extended diff
1978 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
1979 format. Read the diffs help topic for more information on why this
1980 is important for preserving permission changes and copy/rename
1980 is important for preserving permission changes and copy/rename
1981 information.
1981 information.
1982 """
1982 """
1983 msg = cmdutil.logmessage(opts)
1983 msg = cmdutil.logmessage(opts)
1984 def getmsg():
1984 def getmsg():
1985 return ui.edit(msg, ui.username())
1985 return ui.edit(msg, ui.username())
1986 q = repo.mq
1986 q = repo.mq
1987 opts['msg'] = msg
1987 opts['msg'] = msg
1988 if opts.get('edit'):
1988 if opts.get('edit'):
1989 opts['msg'] = getmsg
1989 opts['msg'] = getmsg
1990 else:
1990 else:
1991 opts['msg'] = msg
1991 opts['msg'] = msg
1992 setupheaderopts(ui, opts)
1992 setupheaderopts(ui, opts)
1993 q.new(repo, patch, *args, **opts)
1993 q.new(repo, patch, *args, **opts)
1994 q.save_dirty()
1994 q.save_dirty()
1995 return 0
1995 return 0
1996
1996
1997 def refresh(ui, repo, *pats, **opts):
1997 def refresh(ui, repo, *pats, **opts):
1998 """update the current patch
1998 """update the current patch
1999
1999
2000 If any file patterns are provided, the refreshed patch will
2000 If any file patterns are provided, the refreshed patch will
2001 contain only the modifications that match those patterns; the
2001 contain only the modifications that match those patterns; the
2002 remaining modifications will remain in the working directory.
2002 remaining modifications will remain in the working directory.
2003
2003
2004 If -s/--short is specified, files currently included in the patch
2004 If -s/--short is specified, files currently included in the patch
2005 will be refreshed just like matched files and remain in the patch.
2005 will be refreshed just like matched files and remain in the patch.
2006
2006
2007 hg add/remove/copy/rename work as usual, though you might want to
2007 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
2008 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
2009 and renames. See the diffs help topic for more information on the
2010 git diff format.
2010 git diff format.
2011 """
2011 """
2012 q = repo.mq
2012 q = repo.mq
2013 message = cmdutil.logmessage(opts)
2013 message = cmdutil.logmessage(opts)
2014 if opts['edit']:
2014 if opts['edit']:
2015 if not q.applied:
2015 if not q.applied:
2016 ui.write(_("no patches applied\n"))
2016 ui.write(_("no patches applied\n"))
2017 return 1
2017 return 1
2018 if message:
2018 if message:
2019 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2019 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2020 patch = q.applied[-1].name
2020 patch = q.applied[-1].name
2021 ph = patchheader(q.join(patch), q.plainmode)
2021 ph = patchheader(q.join(patch), q.plainmode)
2022 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
2022 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
2023 setupheaderopts(ui, opts)
2023 setupheaderopts(ui, opts)
2024 ret = q.refresh(repo, pats, msg=message, **opts)
2024 ret = q.refresh(repo, pats, msg=message, **opts)
2025 q.save_dirty()
2025 q.save_dirty()
2026 return ret
2026 return ret
2027
2027
2028 def diff(ui, repo, *pats, **opts):
2028 def diff(ui, repo, *pats, **opts):
2029 """diff of the current patch and subsequent modifications
2029 """diff of the current patch and subsequent modifications
2030
2030
2031 Shows a diff which includes the current patch as well as any
2031 Shows a diff which includes the current patch as well as any
2032 changes which have been made in the working directory since the
2032 changes which have been made in the working directory since the
2033 last refresh (thus showing what the current patch would become
2033 last refresh (thus showing what the current patch would become
2034 after a qrefresh).
2034 after a qrefresh).
2035
2035
2036 Use :hg:`diff` if you only want to see the changes made since the
2036 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
2037 last qrefresh, or :hg:`export qtip` if you want to see changes
2038 made by the current patch without including changes made since the
2038 made by the current patch without including changes made since the
2039 qrefresh.
2039 qrefresh.
2040 """
2040 """
2041 repo.mq.diff(repo, pats, opts)
2041 repo.mq.diff(repo, pats, opts)
2042 return 0
2042 return 0
2043
2043
2044 def fold(ui, repo, *files, **opts):
2044 def fold(ui, repo, *files, **opts):
2045 """fold the named patches into the current patch
2045 """fold the named patches into the current patch
2046
2046
2047 Patches must not yet be applied. Each patch will be successively
2047 Patches must not yet be applied. Each patch will be successively
2048 applied to the current patch in the order given. If all the
2048 applied to the current patch in the order given. If all the
2049 patches apply successfully, the current patch will be refreshed
2049 patches apply successfully, the current patch will be refreshed
2050 with the new cumulative patch, and the folded patches will be
2050 with the new cumulative patch, and the folded patches will be
2051 deleted. With -k/--keep, the folded patch files will not be
2051 deleted. With -k/--keep, the folded patch files will not be
2052 removed afterwards.
2052 removed afterwards.
2053
2053
2054 The header for each folded patch will be concatenated with the
2054 The header for each folded patch will be concatenated with the
2055 current patch header, separated by a line of '* * *'."""
2055 current patch header, separated by a line of '* * *'."""
2056
2056
2057 q = repo.mq
2057 q = repo.mq
2058
2058
2059 if not files:
2059 if not files:
2060 raise util.Abort(_('qfold requires at least one patch name'))
2060 raise util.Abort(_('qfold requires at least one patch name'))
2061 if not q.check_toppatch(repo)[0]:
2061 if not q.check_toppatch(repo)[0]:
2062 raise util.Abort(_('No patches applied'))
2062 raise util.Abort(_('No patches applied'))
2063 q.check_localchanges(repo)
2063 q.check_localchanges(repo)
2064
2064
2065 message = cmdutil.logmessage(opts)
2065 message = cmdutil.logmessage(opts)
2066 if opts['edit']:
2066 if opts['edit']:
2067 if message:
2067 if message:
2068 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2068 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
2069
2069
2070 parent = q.lookup('qtip')
2070 parent = q.lookup('qtip')
2071 patches = []
2071 patches = []
2072 messages = []
2072 messages = []
2073 for f in files:
2073 for f in files:
2074 p = q.lookup(f)
2074 p = q.lookup(f)
2075 if p in patches or p == parent:
2075 if p in patches or p == parent:
2076 ui.warn(_('Skipping already folded patch %s') % p)
2076 ui.warn(_('Skipping already folded patch %s') % p)
2077 if q.isapplied(p):
2077 if q.isapplied(p):
2078 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2078 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
2079 patches.append(p)
2079 patches.append(p)
2080
2080
2081 for p in patches:
2081 for p in patches:
2082 if not message:
2082 if not message:
2083 ph = patchheader(q.join(p), q.plainmode)
2083 ph = patchheader(q.join(p), q.plainmode)
2084 if ph.message:
2084 if ph.message:
2085 messages.append(ph.message)
2085 messages.append(ph.message)
2086 pf = q.join(p)
2086 pf = q.join(p)
2087 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2087 (patchsuccess, files, fuzz) = q.patch(repo, pf)
2088 if not patchsuccess:
2088 if not patchsuccess:
2089 raise util.Abort(_('Error folding patch %s') % p)
2089 raise util.Abort(_('Error folding patch %s') % p)
2090 patch.updatedir(ui, repo, files)
2090 patch.updatedir(ui, repo, files)
2091
2091
2092 if not message:
2092 if not message:
2093 ph = patchheader(q.join(parent), q.plainmode)
2093 ph = patchheader(q.join(parent), q.plainmode)
2094 message, user = ph.message, ph.user
2094 message, user = ph.message, ph.user
2095 for msg in messages:
2095 for msg in messages:
2096 message.append('* * *')
2096 message.append('* * *')
2097 message.extend(msg)
2097 message.extend(msg)
2098 message = '\n'.join(message)
2098 message = '\n'.join(message)
2099
2099
2100 if opts['edit']:
2100 if opts['edit']:
2101 message = ui.edit(message, user or ui.username())
2101 message = ui.edit(message, user or ui.username())
2102
2102
2103 diffopts = q.patchopts(q.diffopts(), *patches)
2103 diffopts = q.patchopts(q.diffopts(), *patches)
2104 q.refresh(repo, msg=message, git=diffopts.git)
2104 q.refresh(repo, msg=message, git=diffopts.git)
2105 q.delete(repo, patches, opts)
2105 q.delete(repo, patches, opts)
2106 q.save_dirty()
2106 q.save_dirty()
2107
2107
2108 def goto(ui, repo, patch, **opts):
2108 def goto(ui, repo, patch, **opts):
2109 '''push or pop patches until named patch is at top of stack'''
2109 '''push or pop patches until named patch is at top of stack'''
2110 q = repo.mq
2110 q = repo.mq
2111 patch = q.lookup(patch)
2111 patch = q.lookup(patch)
2112 if q.isapplied(patch):
2112 if q.isapplied(patch):
2113 ret = q.pop(repo, patch, force=opts['force'])
2113 ret = q.pop(repo, patch, force=opts['force'])
2114 else:
2114 else:
2115 ret = q.push(repo, patch, force=opts['force'])
2115 ret = q.push(repo, patch, force=opts['force'])
2116 q.save_dirty()
2116 q.save_dirty()
2117 return ret
2117 return ret
2118
2118
2119 def guard(ui, repo, *args, **opts):
2119 def guard(ui, repo, *args, **opts):
2120 '''set or print guards for a patch
2120 '''set or print guards for a patch
2121
2121
2122 Guards control whether a patch can be pushed. A patch with no
2122 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
2123 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
2124 pushed only if the qselect command has activated it. A patch with
2125 a negative guard ("-foo") is never pushed if the qselect command
2125 a negative guard ("-foo") is never pushed if the qselect command
2126 has activated it.
2126 has activated it.
2127
2127
2128 With no arguments, print the currently active guards.
2128 With no arguments, print the currently active guards.
2129 With arguments, set guards for the named patch.
2129 With arguments, set guards for the named patch.
2130 NOTE: Specifying negative guards now requires '--'.
2130 NOTE: Specifying negative guards now requires '--'.
2131
2131
2132 To set guards on another patch::
2132 To set guards on another patch::
2133
2133
2134 hg qguard other.patch -- +2.6.17 -stable
2134 hg qguard other.patch -- +2.6.17 -stable
2135 '''
2135 '''
2136 def status(idx):
2136 def status(idx):
2137 guards = q.series_guards[idx] or ['unguarded']
2137 guards = q.series_guards[idx] or ['unguarded']
2138 ui.write('%s: ' % ui.label(q.series[idx], 'qguard.patch'))
2138 ui.write('%s: ' % ui.label(q.series[idx], 'qguard.patch'))
2139 for i, guard in enumerate(guards):
2139 for i, guard in enumerate(guards):
2140 if guard.startswith('+'):
2140 if guard.startswith('+'):
2141 ui.write(guard, label='qguard.positive')
2141 ui.write(guard, label='qguard.positive')
2142 elif guard.startswith('-'):
2142 elif guard.startswith('-'):
2143 ui.write(guard, label='qguard.negative')
2143 ui.write(guard, label='qguard.negative')
2144 else:
2144 else:
2145 ui.write(guard, label='qguard.unguarded')
2145 ui.write(guard, label='qguard.unguarded')
2146 if i != len(guards) - 1:
2146 if i != len(guards) - 1:
2147 ui.write(' ')
2147 ui.write(' ')
2148 ui.write('\n')
2148 ui.write('\n')
2149 q = repo.mq
2149 q = repo.mq
2150 patch = None
2150 patch = None
2151 args = list(args)
2151 args = list(args)
2152 if opts['list']:
2152 if opts['list']:
2153 if args or opts['none']:
2153 if args or opts['none']:
2154 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2154 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
2155 for i in xrange(len(q.series)):
2155 for i in xrange(len(q.series)):
2156 status(i)
2156 status(i)
2157 return
2157 return
2158 if not args or args[0][0:1] in '-+':
2158 if not args or args[0][0:1] in '-+':
2159 if not q.applied:
2159 if not q.applied:
2160 raise util.Abort(_('no patches applied'))
2160 raise util.Abort(_('no patches applied'))
2161 patch = q.applied[-1].name
2161 patch = q.applied[-1].name
2162 if patch is None and args[0][0:1] not in '-+':
2162 if patch is None and args[0][0:1] not in '-+':
2163 patch = args.pop(0)
2163 patch = args.pop(0)
2164 if patch is None:
2164 if patch is None:
2165 raise util.Abort(_('no patch to work with'))
2165 raise util.Abort(_('no patch to work with'))
2166 if args or opts['none']:
2166 if args or opts['none']:
2167 idx = q.find_series(patch)
2167 idx = q.find_series(patch)
2168 if idx is None:
2168 if idx is None:
2169 raise util.Abort(_('no patch named %s') % patch)
2169 raise util.Abort(_('no patch named %s') % patch)
2170 q.set_guards(idx, args)
2170 q.set_guards(idx, args)
2171 q.save_dirty()
2171 q.save_dirty()
2172 else:
2172 else:
2173 status(q.series.index(q.lookup(patch)))
2173 status(q.series.index(q.lookup(patch)))
2174
2174
2175 def header(ui, repo, patch=None):
2175 def header(ui, repo, patch=None):
2176 """print the header of the topmost or specified patch"""
2176 """print the header of the topmost or specified patch"""
2177 q = repo.mq
2177 q = repo.mq
2178
2178
2179 if patch:
2179 if patch:
2180 patch = q.lookup(patch)
2180 patch = q.lookup(patch)
2181 else:
2181 else:
2182 if not q.applied:
2182 if not q.applied:
2183 ui.write(_('no patches applied\n'))
2183 ui.write(_('no patches applied\n'))
2184 return 1
2184 return 1
2185 patch = q.lookup('qtip')
2185 patch = q.lookup('qtip')
2186 ph = patchheader(q.join(patch), q.plainmode)
2186 ph = patchheader(q.join(patch), q.plainmode)
2187
2187
2188 ui.write('\n'.join(ph.message) + '\n')
2188 ui.write('\n'.join(ph.message) + '\n')
2189
2189
2190 def lastsavename(path):
2190 def lastsavename(path):
2191 (directory, base) = os.path.split(path)
2191 (directory, base) = os.path.split(path)
2192 names = os.listdir(directory)
2192 names = os.listdir(directory)
2193 namere = re.compile("%s.([0-9]+)" % base)
2193 namere = re.compile("%s.([0-9]+)" % base)
2194 maxindex = None
2194 maxindex = None
2195 maxname = None
2195 maxname = None
2196 for f in names:
2196 for f in names:
2197 m = namere.match(f)
2197 m = namere.match(f)
2198 if m:
2198 if m:
2199 index = int(m.group(1))
2199 index = int(m.group(1))
2200 if maxindex is None or index > maxindex:
2200 if maxindex is None or index > maxindex:
2201 maxindex = index
2201 maxindex = index
2202 maxname = f
2202 maxname = f
2203 if maxname:
2203 if maxname:
2204 return (os.path.join(directory, maxname), maxindex)
2204 return (os.path.join(directory, maxname), maxindex)
2205 return (None, None)
2205 return (None, None)
2206
2206
2207 def savename(path):
2207 def savename(path):
2208 (last, index) = lastsavename(path)
2208 (last, index) = lastsavename(path)
2209 if last is None:
2209 if last is None:
2210 index = 0
2210 index = 0
2211 newpath = path + ".%d" % (index + 1)
2211 newpath = path + ".%d" % (index + 1)
2212 return newpath
2212 return newpath
2213
2213
2214 def push(ui, repo, patch=None, **opts):
2214 def push(ui, repo, patch=None, **opts):
2215 """push the next patch onto the stack
2215 """push the next patch onto the stack
2216
2216
2217 When -f/--force is applied, all local changes in patched files
2217 When -f/--force is applied, all local changes in patched files
2218 will be lost.
2218 will be lost.
2219 """
2219 """
2220 q = repo.mq
2220 q = repo.mq
2221 mergeq = None
2221 mergeq = None
2222
2222
2223 if opts['merge']:
2223 if opts['merge']:
2224 if opts['name']:
2224 if opts['name']:
2225 newpath = repo.join(opts['name'])
2225 newpath = repo.join(opts['name'])
2226 else:
2226 else:
2227 newpath, i = lastsavename(q.path)
2227 newpath, i = lastsavename(q.path)
2228 if not newpath:
2228 if not newpath:
2229 ui.warn(_("no saved queues found, please use -n\n"))
2229 ui.warn(_("no saved queues found, please use -n\n"))
2230 return 1
2230 return 1
2231 mergeq = queue(ui, repo.join(""), newpath)
2231 mergeq = queue(ui, repo.join(""), newpath)
2232 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2232 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2233 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2233 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2234 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'))
2234 mergeq=mergeq, all=opts.get('all'), move=opts.get('move'))
2235 return ret
2235 return ret
2236
2236
2237 def pop(ui, repo, patch=None, **opts):
2237 def pop(ui, repo, patch=None, **opts):
2238 """pop the current patch off the stack
2238 """pop the current patch off the stack
2239
2239
2240 By default, pops off the top of the patch stack. If given a patch
2240 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
2241 name, keeps popping off patches until the named patch is at the
2242 top of the stack.
2242 top of the stack.
2243 """
2243 """
2244 localupdate = True
2244 localupdate = True
2245 if opts['name']:
2245 if opts['name']:
2246 q = queue(ui, repo.join(""), repo.join(opts['name']))
2246 q = queue(ui, repo.join(""), repo.join(opts['name']))
2247 ui.warn(_('using patch queue: %s\n') % q.path)
2247 ui.warn(_('using patch queue: %s\n') % q.path)
2248 localupdate = False
2248 localupdate = False
2249 else:
2249 else:
2250 q = repo.mq
2250 q = repo.mq
2251 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2251 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2252 all=opts['all'])
2252 all=opts['all'])
2253 q.save_dirty()
2253 q.save_dirty()
2254 return ret
2254 return ret
2255
2255
2256 def rename(ui, repo, patch, name=None, **opts):
2256 def rename(ui, repo, patch, name=None, **opts):
2257 """rename a patch
2257 """rename a patch
2258
2258
2259 With one argument, renames the current patch to PATCH1.
2259 With one argument, renames the current patch to PATCH1.
2260 With two arguments, renames PATCH1 to PATCH2."""
2260 With two arguments, renames PATCH1 to PATCH2."""
2261
2261
2262 q = repo.mq
2262 q = repo.mq
2263
2263
2264 if not name:
2264 if not name:
2265 name = patch
2265 name = patch
2266 patch = None
2266 patch = None
2267
2267
2268 if patch:
2268 if patch:
2269 patch = q.lookup(patch)
2269 patch = q.lookup(patch)
2270 else:
2270 else:
2271 if not q.applied:
2271 if not q.applied:
2272 ui.write(_('no patches applied\n'))
2272 ui.write(_('no patches applied\n'))
2273 return
2273 return
2274 patch = q.lookup('qtip')
2274 patch = q.lookup('qtip')
2275 absdest = q.join(name)
2275 absdest = q.join(name)
2276 if os.path.isdir(absdest):
2276 if os.path.isdir(absdest):
2277 name = normname(os.path.join(name, os.path.basename(patch)))
2277 name = normname(os.path.join(name, os.path.basename(patch)))
2278 absdest = q.join(name)
2278 absdest = q.join(name)
2279 if os.path.exists(absdest):
2279 if os.path.exists(absdest):
2280 raise util.Abort(_('%s already exists') % absdest)
2280 raise util.Abort(_('%s already exists') % absdest)
2281
2281
2282 if name in q.series:
2282 if name in q.series:
2283 raise util.Abort(
2283 raise util.Abort(
2284 _('A patch named %s already exists in the series file') % name)
2284 _('A patch named %s already exists in the series file') % name)
2285
2285
2286 ui.note(_('renaming %s to %s\n') % (patch, name))
2286 ui.note(_('renaming %s to %s\n') % (patch, name))
2287 i = q.find_series(patch)
2287 i = q.find_series(patch)
2288 guards = q.guard_re.findall(q.full_series[i])
2288 guards = q.guard_re.findall(q.full_series[i])
2289 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2289 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2290 q.parse_series()
2290 q.parse_series()
2291 q.series_dirty = 1
2291 q.series_dirty = 1
2292
2292
2293 info = q.isapplied(patch)
2293 info = q.isapplied(patch)
2294 if info:
2294 if info:
2295 q.applied[info[0]] = statusentry(info[1], name)
2295 q.applied[info[0]] = statusentry(info[1], name)
2296 q.applied_dirty = 1
2296 q.applied_dirty = 1
2297
2297
2298 util.rename(q.join(patch), absdest)
2298 util.rename(q.join(patch), absdest)
2299 r = q.qrepo()
2299 r = q.qrepo()
2300 if r:
2300 if r:
2301 wlock = r.wlock()
2301 wlock = r.wlock()
2302 try:
2302 try:
2303 if r.dirstate[patch] == 'a':
2303 if r.dirstate[patch] == 'a':
2304 r.dirstate.forget(patch)
2304 r.dirstate.forget(patch)
2305 r.dirstate.add(name)
2305 r.dirstate.add(name)
2306 else:
2306 else:
2307 if r.dirstate[name] == 'r':
2307 if r.dirstate[name] == 'r':
2308 r.undelete([name])
2308 r.undelete([name])
2309 r.copy(patch, name)
2309 r.copy(patch, name)
2310 r.remove([patch], False)
2310 r.remove([patch], False)
2311 finally:
2311 finally:
2312 wlock.release()
2312 wlock.release()
2313
2313
2314 q.save_dirty()
2314 q.save_dirty()
2315
2315
2316 def restore(ui, repo, rev, **opts):
2316 def restore(ui, repo, rev, **opts):
2317 """restore the queue state saved by a revision (DEPRECATED)
2317 """restore the queue state saved by a revision (DEPRECATED)
2318
2318
2319 This command is deprecated, use rebase --mq instead."""
2319 This command is deprecated, use rebase --mq instead."""
2320 rev = repo.lookup(rev)
2320 rev = repo.lookup(rev)
2321 q = repo.mq
2321 q = repo.mq
2322 q.restore(repo, rev, delete=opts['delete'],
2322 q.restore(repo, rev, delete=opts['delete'],
2323 qupdate=opts['update'])
2323 qupdate=opts['update'])
2324 q.save_dirty()
2324 q.save_dirty()
2325 return 0
2325 return 0
2326
2326
2327 def save(ui, repo, **opts):
2327 def save(ui, repo, **opts):
2328 """save current queue state (DEPRECATED)
2328 """save current queue state (DEPRECATED)
2329
2329
2330 This command is deprecated, use rebase --mq instead."""
2330 This command is deprecated, use rebase --mq instead."""
2331 q = repo.mq
2331 q = repo.mq
2332 message = cmdutil.logmessage(opts)
2332 message = cmdutil.logmessage(opts)
2333 ret = q.save(repo, msg=message)
2333 ret = q.save(repo, msg=message)
2334 if ret:
2334 if ret:
2335 return ret
2335 return ret
2336 q.save_dirty()
2336 q.save_dirty()
2337 if opts['copy']:
2337 if opts['copy']:
2338 path = q.path
2338 path = q.path
2339 if opts['name']:
2339 if opts['name']:
2340 newpath = os.path.join(q.basepath, opts['name'])
2340 newpath = os.path.join(q.basepath, opts['name'])
2341 if os.path.exists(newpath):
2341 if os.path.exists(newpath):
2342 if not os.path.isdir(newpath):
2342 if not os.path.isdir(newpath):
2343 raise util.Abort(_('destination %s exists and is not '
2343 raise util.Abort(_('destination %s exists and is not '
2344 'a directory') % newpath)
2344 'a directory') % newpath)
2345 if not opts['force']:
2345 if not opts['force']:
2346 raise util.Abort(_('destination %s exists, '
2346 raise util.Abort(_('destination %s exists, '
2347 'use -f to force') % newpath)
2347 'use -f to force') % newpath)
2348 else:
2348 else:
2349 newpath = savename(path)
2349 newpath = savename(path)
2350 ui.warn(_("copy %s to %s\n") % (path, newpath))
2350 ui.warn(_("copy %s to %s\n") % (path, newpath))
2351 util.copyfiles(path, newpath)
2351 util.copyfiles(path, newpath)
2352 if opts['empty']:
2352 if opts['empty']:
2353 try:
2353 try:
2354 os.unlink(q.join(q.status_path))
2354 os.unlink(q.join(q.status_path))
2355 except:
2355 except:
2356 pass
2356 pass
2357 return 0
2357 return 0
2358
2358
2359 def strip(ui, repo, rev, **opts):
2359 def strip(ui, repo, rev, **opts):
2360 """strip a changeset and all its descendants from the repository
2360 """strip a changeset and all its descendants from the repository
2361
2361
2362 The strip command removes all changesets whose local revision
2362 The strip command removes all changesets whose local revision
2363 number is greater than or equal to REV, and then restores any
2363 number is greater than or equal to REV, and then restores any
2364 changesets that are not descendants of REV. If the working
2364 changesets that are not descendants of REV. If the working
2365 directory has uncommitted changes, the operation is aborted unless
2365 directory has uncommitted changes, the operation is aborted unless
2366 the --force flag is supplied.
2366 the --force flag is supplied.
2367
2367
2368 If a parent of the working directory is stripped, then the working
2368 If a parent of the working directory is stripped, then the working
2369 directory will automatically be updated to the most recent
2369 directory will automatically be updated to the most recent
2370 available ancestor of the stripped parent after the operation
2370 available ancestor of the stripped parent after the operation
2371 completes.
2371 completes.
2372
2372
2373 Any stripped changesets are stored in ``.hg/strip-backup`` as a
2373 Any stripped changesets are stored in ``.hg/strip-backup`` as a
2374 bundle (see ``hg help bundle`` and ``hg help unbundle``). They can
2374 bundle (see ``hg help bundle`` and ``hg help unbundle``). They can
2375 be restored by running ``hg unbundle .hg/strip-backup/BUNDLE``,
2375 be restored by running ``hg unbundle .hg/strip-backup/BUNDLE``,
2376 where BUNDLE is the bundle file created by the strip. Note that
2376 where BUNDLE is the bundle file created by the strip. Note that
2377 the local revision numbers will in general be different after the
2377 the local revision numbers will in general be different after the
2378 restore.
2378 restore.
2379
2379
2380 Use the --nobackup option to discard the backup bundle once the
2380 Use the --nobackup option to discard the backup bundle once the
2381 operation completes.
2381 operation completes.
2382 """
2382 """
2383 backup = 'all'
2383 backup = 'all'
2384 if opts['backup']:
2384 if opts['backup']:
2385 backup = 'strip'
2385 backup = 'strip'
2386 elif opts['nobackup']:
2386 elif opts['nobackup']:
2387 backup = 'none'
2387 backup = 'none'
2388
2388
2389 rev = repo.lookup(rev)
2389 rev = repo.lookup(rev)
2390 p = repo.dirstate.parents()
2390 p = repo.dirstate.parents()
2391 cl = repo.changelog
2391 cl = repo.changelog
2392 update = True
2392 update = True
2393 if p[0] == nullid:
2393 if p[0] == nullid:
2394 update = False
2394 update = False
2395 elif p[1] == nullid and rev != cl.ancestor(p[0], rev):
2395 elif p[1] == nullid and rev != cl.ancestor(p[0], rev):
2396 update = False
2396 update = False
2397 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2397 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2398 update = False
2398 update = False
2399
2399
2400 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2400 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2401 return 0
2401 return 0
2402
2402
2403 def select(ui, repo, *args, **opts):
2403 def select(ui, repo, *args, **opts):
2404 '''set or print guarded patches to push
2404 '''set or print guarded patches to push
2405
2405
2406 Use the qguard command to set or print guards on patch, then use
2406 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
2407 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
2408 it has no guards or any positive guards match the currently
2409 selected guard, but will not be pushed if any negative guards
2409 selected guard, but will not be pushed if any negative guards
2410 match the current guard. For example::
2410 match the current guard. For example::
2411
2411
2412 qguard foo.patch -stable (negative guard)
2412 qguard foo.patch -stable (negative guard)
2413 qguard bar.patch +stable (positive guard)
2413 qguard bar.patch +stable (positive guard)
2414 qselect stable
2414 qselect stable
2415
2415
2416 This activates the "stable" guard. mq will skip foo.patch (because
2416 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
2417 it has a negative match) but push bar.patch (because it has a
2418 positive match).
2418 positive match).
2419
2419
2420 With no arguments, prints the currently active guards.
2420 With no arguments, prints the currently active guards.
2421 With one argument, sets the active guard.
2421 With one argument, sets the active guard.
2422
2422
2423 Use -n/--none to deactivate guards (no other arguments needed).
2423 Use -n/--none to deactivate guards (no other arguments needed).
2424 When no guards are active, patches with positive guards are
2424 When no guards are active, patches with positive guards are
2425 skipped and patches with negative guards are pushed.
2425 skipped and patches with negative guards are pushed.
2426
2426
2427 qselect can change the guards on applied patches. It does not pop
2427 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
2428 guarded patches by default. Use --pop to pop back to the last
2429 applied patch that is not guarded. Use --reapply (which implies
2429 applied patch that is not guarded. Use --reapply (which implies
2430 --pop) to push back to the current patch afterwards, but skip
2430 --pop) to push back to the current patch afterwards, but skip
2431 guarded patches.
2431 guarded patches.
2432
2432
2433 Use -s/--series to print a list of all guards in the series file
2433 Use -s/--series to print a list of all guards in the series file
2434 (no other arguments needed). Use -v for more information.'''
2434 (no other arguments needed). Use -v for more information.'''
2435
2435
2436 q = repo.mq
2436 q = repo.mq
2437 guards = q.active()
2437 guards = q.active()
2438 if args or opts['none']:
2438 if args or opts['none']:
2439 old_unapplied = q.unapplied(repo)
2439 old_unapplied = q.unapplied(repo)
2440 old_guarded = [i for i in xrange(len(q.applied)) if
2440 old_guarded = [i for i in xrange(len(q.applied)) if
2441 not q.pushable(i)[0]]
2441 not q.pushable(i)[0]]
2442 q.set_active(args)
2442 q.set_active(args)
2443 q.save_dirty()
2443 q.save_dirty()
2444 if not args:
2444 if not args:
2445 ui.status(_('guards deactivated\n'))
2445 ui.status(_('guards deactivated\n'))
2446 if not opts['pop'] and not opts['reapply']:
2446 if not opts['pop'] and not opts['reapply']:
2447 unapplied = q.unapplied(repo)
2447 unapplied = q.unapplied(repo)
2448 guarded = [i for i in xrange(len(q.applied))
2448 guarded = [i for i in xrange(len(q.applied))
2449 if not q.pushable(i)[0]]
2449 if not q.pushable(i)[0]]
2450 if len(unapplied) != len(old_unapplied):
2450 if len(unapplied) != len(old_unapplied):
2451 ui.status(_('number of unguarded, unapplied patches has '
2451 ui.status(_('number of unguarded, unapplied patches has '
2452 'changed from %d to %d\n') %
2452 'changed from %d to %d\n') %
2453 (len(old_unapplied), len(unapplied)))
2453 (len(old_unapplied), len(unapplied)))
2454 if len(guarded) != len(old_guarded):
2454 if len(guarded) != len(old_guarded):
2455 ui.status(_('number of guarded, applied patches has changed '
2455 ui.status(_('number of guarded, applied patches has changed '
2456 'from %d to %d\n') %
2456 'from %d to %d\n') %
2457 (len(old_guarded), len(guarded)))
2457 (len(old_guarded), len(guarded)))
2458 elif opts['series']:
2458 elif opts['series']:
2459 guards = {}
2459 guards = {}
2460 noguards = 0
2460 noguards = 0
2461 for gs in q.series_guards:
2461 for gs in q.series_guards:
2462 if not gs:
2462 if not gs:
2463 noguards += 1
2463 noguards += 1
2464 for g in gs:
2464 for g in gs:
2465 guards.setdefault(g, 0)
2465 guards.setdefault(g, 0)
2466 guards[g] += 1
2466 guards[g] += 1
2467 if ui.verbose:
2467 if ui.verbose:
2468 guards['NONE'] = noguards
2468 guards['NONE'] = noguards
2469 guards = guards.items()
2469 guards = guards.items()
2470 guards.sort(key=lambda x: x[0][1:])
2470 guards.sort(key=lambda x: x[0][1:])
2471 if guards:
2471 if guards:
2472 ui.note(_('guards in series file:\n'))
2472 ui.note(_('guards in series file:\n'))
2473 for guard, count in guards:
2473 for guard, count in guards:
2474 ui.note('%2d ' % count)
2474 ui.note('%2d ' % count)
2475 ui.write(guard, '\n')
2475 ui.write(guard, '\n')
2476 else:
2476 else:
2477 ui.note(_('no guards in series file\n'))
2477 ui.note(_('no guards in series file\n'))
2478 else:
2478 else:
2479 if guards:
2479 if guards:
2480 ui.note(_('active guards:\n'))
2480 ui.note(_('active guards:\n'))
2481 for g in guards:
2481 for g in guards:
2482 ui.write(g, '\n')
2482 ui.write(g, '\n')
2483 else:
2483 else:
2484 ui.write(_('no active guards\n'))
2484 ui.write(_('no active guards\n'))
2485 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2485 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2486 popped = False
2486 popped = False
2487 if opts['pop'] or opts['reapply']:
2487 if opts['pop'] or opts['reapply']:
2488 for i in xrange(len(q.applied)):
2488 for i in xrange(len(q.applied)):
2489 pushable, reason = q.pushable(i)
2489 pushable, reason = q.pushable(i)
2490 if not pushable:
2490 if not pushable:
2491 ui.status(_('popping guarded patches\n'))
2491 ui.status(_('popping guarded patches\n'))
2492 popped = True
2492 popped = True
2493 if i == 0:
2493 if i == 0:
2494 q.pop(repo, all=True)
2494 q.pop(repo, all=True)
2495 else:
2495 else:
2496 q.pop(repo, i - 1)
2496 q.pop(repo, i - 1)
2497 break
2497 break
2498 if popped:
2498 if popped:
2499 try:
2499 try:
2500 if reapply:
2500 if reapply:
2501 ui.status(_('reapplying unguarded patches\n'))
2501 ui.status(_('reapplying unguarded patches\n'))
2502 q.push(repo, reapply)
2502 q.push(repo, reapply)
2503 finally:
2503 finally:
2504 q.save_dirty()
2504 q.save_dirty()
2505
2505
2506 def finish(ui, repo, *revrange, **opts):
2506 def finish(ui, repo, *revrange, **opts):
2507 """move applied patches into repository history
2507 """move applied patches into repository history
2508
2508
2509 Finishes the specified revisions (corresponding to applied
2509 Finishes the specified revisions (corresponding to applied
2510 patches) by moving them out of mq control into regular repository
2510 patches) by moving them out of mq control into regular repository
2511 history.
2511 history.
2512
2512
2513 Accepts a revision range or the -a/--applied option. If --applied
2513 Accepts a revision range or the -a/--applied option. If --applied
2514 is specified, all applied mq revisions are removed from mq
2514 is specified, all applied mq revisions are removed from mq
2515 control. Otherwise, the given revisions must be at the base of the
2515 control. Otherwise, the given revisions must be at the base of the
2516 stack of applied patches.
2516 stack of applied patches.
2517
2517
2518 This can be especially useful if your changes have been applied to
2518 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
2519 an upstream repository, or if you are about to push your changes
2520 to upstream.
2520 to upstream.
2521 """
2521 """
2522 if not opts['applied'] and not revrange:
2522 if not opts['applied'] and not revrange:
2523 raise util.Abort(_('no revisions specified'))
2523 raise util.Abort(_('no revisions specified'))
2524 elif opts['applied']:
2524 elif opts['applied']:
2525 revrange = ('qbase:qtip',) + revrange
2525 revrange = ('qbase:qtip',) + revrange
2526
2526
2527 q = repo.mq
2527 q = repo.mq
2528 if not q.applied:
2528 if not q.applied:
2529 ui.status(_('no patches applied\n'))
2529 ui.status(_('no patches applied\n'))
2530 return 0
2530 return 0
2531
2531
2532 revs = cmdutil.revrange(repo, revrange)
2532 revs = cmdutil.revrange(repo, revrange)
2533 q.finish(repo, revs)
2533 q.finish(repo, revs)
2534 q.save_dirty()
2534 q.save_dirty()
2535 return 0
2535 return 0
2536
2536
2537 def reposetup(ui, repo):
2537 def reposetup(ui, repo):
2538 class mqrepo(repo.__class__):
2538 class mqrepo(repo.__class__):
2539 @util.propertycache
2539 @util.propertycache
2540 def mq(self):
2540 def mq(self):
2541 return queue(self.ui, self.join(""))
2541 return queue(self.ui, self.join(""))
2542
2542
2543 def abort_if_wdir_patched(self, errmsg, force=False):
2543 def abort_if_wdir_patched(self, errmsg, force=False):
2544 if self.mq.applied and not force:
2544 if self.mq.applied and not force:
2545 parent = self.dirstate.parents()[0]
2545 parent = self.dirstate.parents()[0]
2546 if parent in [s.node for s in self.mq.applied]:
2546 if parent in [s.node for s in self.mq.applied]:
2547 raise util.Abort(errmsg)
2547 raise util.Abort(errmsg)
2548
2548
2549 def commit(self, text="", user=None, date=None, match=None,
2549 def commit(self, text="", user=None, date=None, match=None,
2550 force=False, editor=False, extra={}):
2550 force=False, editor=False, extra={}):
2551 self.abort_if_wdir_patched(
2551 self.abort_if_wdir_patched(
2552 _('cannot commit over an applied mq patch'),
2552 _('cannot commit over an applied mq patch'),
2553 force)
2553 force)
2554
2554
2555 return super(mqrepo, self).commit(text, user, date, match, force,
2555 return super(mqrepo, self).commit(text, user, date, match, force,
2556 editor, extra)
2556 editor, extra)
2557
2557
2558 def push(self, remote, force=False, revs=None):
2558 def push(self, remote, force=False, revs=None):
2559 if self.mq.applied and not force and not revs:
2559 if self.mq.applied and not force and not revs:
2560 raise util.Abort(_('source has mq patches applied'))
2560 raise util.Abort(_('source has mq patches applied'))
2561 return super(mqrepo, self).push(remote, force, revs)
2561 return super(mqrepo, self).push(remote, force, revs)
2562
2562
2563 def _findtags(self):
2563 def _findtags(self):
2564 '''augment tags from base class with patch tags'''
2564 '''augment tags from base class with patch tags'''
2565 result = super(mqrepo, self)._findtags()
2565 result = super(mqrepo, self)._findtags()
2566
2566
2567 q = self.mq
2567 q = self.mq
2568 if not q.applied:
2568 if not q.applied:
2569 return result
2569 return result
2570
2570
2571 mqtags = [(patch.node, patch.name) for patch in q.applied]
2571 mqtags = [(patch.node, patch.name) for patch in q.applied]
2572
2572
2573 if mqtags[-1][0] not in self.changelog.nodemap:
2573 if mqtags[-1][0] not in self.changelog.nodemap:
2574 self.ui.warn(_('mq status file refers to unknown node %s\n')
2574 self.ui.warn(_('mq status file refers to unknown node %s\n')
2575 % short(mqtags[-1][0]))
2575 % short(mqtags[-1][0]))
2576 return result
2576 return result
2577
2577
2578 mqtags.append((mqtags[-1][0], 'qtip'))
2578 mqtags.append((mqtags[-1][0], 'qtip'))
2579 mqtags.append((mqtags[0][0], 'qbase'))
2579 mqtags.append((mqtags[0][0], 'qbase'))
2580 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2580 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2581 tags = result[0]
2581 tags = result[0]
2582 for patch in mqtags:
2582 for patch in mqtags:
2583 if patch[1] in tags:
2583 if patch[1] in tags:
2584 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2584 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2585 % patch[1])
2585 % patch[1])
2586 else:
2586 else:
2587 tags[patch[1]] = patch[0]
2587 tags[patch[1]] = patch[0]
2588
2588
2589 return result
2589 return result
2590
2590
2591 def _branchtags(self, partial, lrev):
2591 def _branchtags(self, partial, lrev):
2592 q = self.mq
2592 q = self.mq
2593 if not q.applied:
2593 if not q.applied:
2594 return super(mqrepo, self)._branchtags(partial, lrev)
2594 return super(mqrepo, self)._branchtags(partial, lrev)
2595
2595
2596 cl = self.changelog
2596 cl = self.changelog
2597 qbasenode = q.applied[0].node
2597 qbasenode = q.applied[0].node
2598 if qbasenode not in cl.nodemap:
2598 if qbasenode not in cl.nodemap:
2599 self.ui.warn(_('mq status file refers to unknown node %s\n')
2599 self.ui.warn(_('mq status file refers to unknown node %s\n')
2600 % short(qbasenode))
2600 % short(qbasenode))
2601 return super(mqrepo, self)._branchtags(partial, lrev)
2601 return super(mqrepo, self)._branchtags(partial, lrev)
2602
2602
2603 qbase = cl.rev(qbasenode)
2603 qbase = cl.rev(qbasenode)
2604 start = lrev + 1
2604 start = lrev + 1
2605 if start < qbase:
2605 if start < qbase:
2606 # update the cache (excluding the patches) and save it
2606 # update the cache (excluding the patches) and save it
2607 ctxgen = (self[r] for r in xrange(lrev + 1, qbase))
2607 ctxgen = (self[r] for r in xrange(lrev + 1, qbase))
2608 self._updatebranchcache(partial, ctxgen)
2608 self._updatebranchcache(partial, ctxgen)
2609 self._writebranchcache(partial, cl.node(qbase - 1), qbase - 1)
2609 self._writebranchcache(partial, cl.node(qbase - 1), qbase - 1)
2610 start = qbase
2610 start = qbase
2611 # if start = qbase, the cache is as updated as it should be.
2611 # if start = qbase, the cache is as updated as it should be.
2612 # if start > qbase, the cache includes (part of) the patches.
2612 # if start > qbase, the cache includes (part of) the patches.
2613 # we might as well use it, but we won't save it.
2613 # we might as well use it, but we won't save it.
2614
2614
2615 # update the cache up to the tip
2615 # update the cache up to the tip
2616 ctxgen = (self[r] for r in xrange(start, len(cl)))
2616 ctxgen = (self[r] for r in xrange(start, len(cl)))
2617 self._updatebranchcache(partial, ctxgen)
2617 self._updatebranchcache(partial, ctxgen)
2618
2618
2619 return partial
2619 return partial
2620
2620
2621 if repo.local():
2621 if repo.local():
2622 repo.__class__ = mqrepo
2622 repo.__class__ = mqrepo
2623
2623
2624 def mqimport(orig, ui, repo, *args, **kwargs):
2624 def mqimport(orig, ui, repo, *args, **kwargs):
2625 if (hasattr(repo, 'abort_if_wdir_patched')
2625 if (hasattr(repo, 'abort_if_wdir_patched')
2626 and not kwargs.get('no_commit', False)):
2626 and not kwargs.get('no_commit', False)):
2627 repo.abort_if_wdir_patched(_('cannot import over an applied patch'),
2627 repo.abort_if_wdir_patched(_('cannot import over an applied patch'),
2628 kwargs.get('force'))
2628 kwargs.get('force'))
2629 return orig(ui, repo, *args, **kwargs)
2629 return orig(ui, repo, *args, **kwargs)
2630
2630
2631 def mqinit(orig, ui, *args, **kwargs):
2631 def mqinit(orig, ui, *args, **kwargs):
2632 mq = kwargs.pop('mq', None)
2632 mq = kwargs.pop('mq', None)
2633
2633
2634 if not mq:
2634 if not mq:
2635 return orig(ui, *args, **kwargs)
2635 return orig(ui, *args, **kwargs)
2636
2636
2637 if args:
2637 if args:
2638 repopath = args[0]
2638 repopath = args[0]
2639 if not hg.islocal(repopath):
2639 if not hg.islocal(repopath):
2640 raise util.Abort(_('only a local queue repository '
2640 raise util.Abort(_('only a local queue repository '
2641 'may be initialized'))
2641 'may be initialized'))
2642 else:
2642 else:
2643 repopath = cmdutil.findrepo(os.getcwd())
2643 repopath = cmdutil.findrepo(os.getcwd())
2644 if not repopath:
2644 if not repopath:
2645 raise util.Abort(_('There is no Mercurial repository here '
2645 raise util.Abort(_('There is no Mercurial repository here '
2646 '(.hg not found)'))
2646 '(.hg not found)'))
2647 repo = hg.repository(ui, repopath)
2647 repo = hg.repository(ui, repopath)
2648 return qinit(ui, repo, True)
2648 return qinit(ui, repo, True)
2649
2649
2650 def mqcommand(orig, ui, repo, *args, **kwargs):
2650 def mqcommand(orig, ui, repo, *args, **kwargs):
2651 """Add --mq option to operate on patch repository instead of main"""
2651 """Add --mq option to operate on patch repository instead of main"""
2652
2652
2653 # some commands do not like getting unknown options
2653 # some commands do not like getting unknown options
2654 mq = kwargs.pop('mq', None)
2654 mq = kwargs.pop('mq', None)
2655
2655
2656 if not mq:
2656 if not mq:
2657 return orig(ui, repo, *args, **kwargs)
2657 return orig(ui, repo, *args, **kwargs)
2658
2658
2659 q = repo.mq
2659 q = repo.mq
2660 r = q.qrepo()
2660 r = q.qrepo()
2661 if not r:
2661 if not r:
2662 raise util.Abort('no queue repository')
2662 raise util.Abort(_('no queue repository'))
2663 return orig(r.ui, r, *args, **kwargs)
2663 return orig(r.ui, r, *args, **kwargs)
2664
2664
2665 def summary(orig, ui, repo, *args, **kwargs):
2665 def summary(orig, ui, repo, *args, **kwargs):
2666 r = orig(ui, repo, *args, **kwargs)
2666 r = orig(ui, repo, *args, **kwargs)
2667 q = repo.mq
2667 q = repo.mq
2668 m = []
2668 m = []
2669 a, u = len(q.applied), len(q.unapplied(repo))
2669 a, u = len(q.applied), len(q.unapplied(repo))
2670 if a:
2670 if a:
2671 m.append(_("%d applied") % a)
2671 m.append(_("%d applied") % a)
2672 if u:
2672 if u:
2673 m.append(_("%d unapplied") % u)
2673 m.append(_("%d unapplied") % u)
2674 if m:
2674 if m:
2675 ui.write("mq: %s\n" % ', '.join(m))
2675 ui.write("mq: %s\n" % ', '.join(m))
2676 else:
2676 else:
2677 ui.note(_("mq: (empty queue)\n"))
2677 ui.note(_("mq: (empty queue)\n"))
2678 return r
2678 return r
2679
2679
2680 def uisetup(ui):
2680 def uisetup(ui):
2681 mqopt = [('', 'mq', None, _("operate on patch repository"))]
2681 mqopt = [('', 'mq', None, _("operate on patch repository"))]
2682
2682
2683 extensions.wrapcommand(commands.table, 'import', mqimport)
2683 extensions.wrapcommand(commands.table, 'import', mqimport)
2684 extensions.wrapcommand(commands.table, 'summary', summary)
2684 extensions.wrapcommand(commands.table, 'summary', summary)
2685
2685
2686 entry = extensions.wrapcommand(commands.table, 'init', mqinit)
2686 entry = extensions.wrapcommand(commands.table, 'init', mqinit)
2687 entry[1].extend(mqopt)
2687 entry[1].extend(mqopt)
2688
2688
2689 norepo = commands.norepo.split(" ")
2689 norepo = commands.norepo.split(" ")
2690 for cmd in commands.table.keys():
2690 for cmd in commands.table.keys():
2691 cmd = cmdutil.parsealiases(cmd)[0]
2691 cmd = cmdutil.parsealiases(cmd)[0]
2692 if cmd in norepo:
2692 if cmd in norepo:
2693 continue
2693 continue
2694 entry = extensions.wrapcommand(commands.table, cmd, mqcommand)
2694 entry = extensions.wrapcommand(commands.table, cmd, mqcommand)
2695 entry[1].extend(mqopt)
2695 entry[1].extend(mqopt)
2696
2696
2697 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2697 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2698
2698
2699 cmdtable = {
2699 cmdtable = {
2700 "qapplied":
2700 "qapplied":
2701 (applied,
2701 (applied,
2702 [('1', 'last', None, _('show only the last patch'))] + seriesopts,
2702 [('1', 'last', None, _('show only the last patch'))] + seriesopts,
2703 _('hg qapplied [-1] [-s] [PATCH]')),
2703 _('hg qapplied [-1] [-s] [PATCH]')),
2704 "qclone":
2704 "qclone":
2705 (clone,
2705 (clone,
2706 [('', 'pull', None, _('use pull protocol to copy metadata')),
2706 [('', 'pull', None, _('use pull protocol to copy metadata')),
2707 ('U', 'noupdate', None, _('do not update the new working directories')),
2707 ('U', 'noupdate', None, _('do not update the new working directories')),
2708 ('', 'uncompressed', None,
2708 ('', 'uncompressed', None,
2709 _('use uncompressed transfer (fast over LAN)')),
2709 _('use uncompressed transfer (fast over LAN)')),
2710 ('p', 'patches', '', _('location of source patch repository')),
2710 ('p', 'patches', '', _('location of source patch repository')),
2711 ] + commands.remoteopts,
2711 ] + commands.remoteopts,
2712 _('hg qclone [OPTION]... SOURCE [DEST]')),
2712 _('hg qclone [OPTION]... SOURCE [DEST]')),
2713 "qcommit|qci":
2713 "qcommit|qci":
2714 (commit,
2714 (commit,
2715 commands.table["^commit|ci"][1],
2715 commands.table["^commit|ci"][1],
2716 _('hg qcommit [OPTION]... [FILE]...')),
2716 _('hg qcommit [OPTION]... [FILE]...')),
2717 "^qdiff":
2717 "^qdiff":
2718 (diff,
2718 (diff,
2719 commands.diffopts + commands.diffopts2 + commands.walkopts,
2719 commands.diffopts + commands.diffopts2 + commands.walkopts,
2720 _('hg qdiff [OPTION]... [FILE]...')),
2720 _('hg qdiff [OPTION]... [FILE]...')),
2721 "qdelete|qremove|qrm":
2721 "qdelete|qremove|qrm":
2722 (delete,
2722 (delete,
2723 [('k', 'keep', None, _('keep patch file')),
2723 [('k', 'keep', None, _('keep patch file')),
2724 ('r', 'rev', [], _('stop managing a revision (DEPRECATED)'))],
2724 ('r', 'rev', [], _('stop managing a revision (DEPRECATED)'))],
2725 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2725 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2726 'qfold':
2726 'qfold':
2727 (fold,
2727 (fold,
2728 [('e', 'edit', None, _('edit patch header')),
2728 [('e', 'edit', None, _('edit patch header')),
2729 ('k', 'keep', None, _('keep folded patch files')),
2729 ('k', 'keep', None, _('keep folded patch files')),
2730 ] + commands.commitopts,
2730 ] + commands.commitopts,
2731 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2731 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2732 'qgoto':
2732 'qgoto':
2733 (goto,
2733 (goto,
2734 [('f', 'force', None, _('overwrite any local changes'))],
2734 [('f', 'force', None, _('overwrite any local changes'))],
2735 _('hg qgoto [OPTION]... PATCH')),
2735 _('hg qgoto [OPTION]... PATCH')),
2736 'qguard':
2736 'qguard':
2737 (guard,
2737 (guard,
2738 [('l', 'list', None, _('list all patches and guards')),
2738 [('l', 'list', None, _('list all patches and guards')),
2739 ('n', 'none', None, _('drop all guards'))],
2739 ('n', 'none', None, _('drop all guards'))],
2740 _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]')),
2740 _('hg qguard [-l] [-n] [PATCH] [-- [+GUARD]... [-GUARD]...]')),
2741 'qheader': (header, [], _('hg qheader [PATCH]')),
2741 'qheader': (header, [], _('hg qheader [PATCH]')),
2742 "qimport":
2742 "qimport":
2743 (qimport,
2743 (qimport,
2744 [('e', 'existing', None, _('import file in patch directory')),
2744 [('e', 'existing', None, _('import file in patch directory')),
2745 ('n', 'name', '', _('name of patch file')),
2745 ('n', 'name', '', _('name of patch file')),
2746 ('f', 'force', None, _('overwrite existing files')),
2746 ('f', 'force', None, _('overwrite existing files')),
2747 ('r', 'rev', [], _('place existing revisions under mq control')),
2747 ('r', 'rev', [], _('place existing revisions under mq control')),
2748 ('g', 'git', None, _('use git extended diff format')),
2748 ('g', 'git', None, _('use git extended diff format')),
2749 ('P', 'push', None, _('qpush after importing'))],
2749 ('P', 'push', None, _('qpush after importing'))],
2750 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...')),
2750 _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...')),
2751 "^qinit":
2751 "^qinit":
2752 (init,
2752 (init,
2753 [('c', 'create-repo', None, _('create queue repository'))],
2753 [('c', 'create-repo', None, _('create queue repository'))],
2754 _('hg qinit [-c]')),
2754 _('hg qinit [-c]')),
2755 "^qnew":
2755 "^qnew":
2756 (new,
2756 (new,
2757 [('e', 'edit', None, _('edit commit message')),
2757 [('e', 'edit', None, _('edit commit message')),
2758 ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
2758 ('f', 'force', None, _('import uncommitted changes (DEPRECATED)')),
2759 ('g', 'git', None, _('use git extended diff format')),
2759 ('g', 'git', None, _('use git extended diff format')),
2760 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2760 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2761 ('u', 'user', '', _('add "From: <given user>" to patch')),
2761 ('u', 'user', '', _('add "From: <given user>" to patch')),
2762 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2762 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2763 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2763 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2764 ] + commands.walkopts + commands.commitopts,
2764 ] + commands.walkopts + commands.commitopts,
2765 _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...')),
2765 _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...')),
2766 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2766 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2767 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2767 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2768 "^qpop":
2768 "^qpop":
2769 (pop,
2769 (pop,
2770 [('a', 'all', None, _('pop all patches')),
2770 [('a', 'all', None, _('pop all patches')),
2771 ('n', 'name', '', _('queue name to pop (DEPRECATED)')),
2771 ('n', 'name', '', _('queue name to pop (DEPRECATED)')),
2772 ('f', 'force', None, _('forget any local changes to patched files'))],
2772 ('f', 'force', None, _('forget any local changes to patched files'))],
2773 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2773 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2774 "^qpush":
2774 "^qpush":
2775 (push,
2775 (push,
2776 [('f', 'force', None, _('apply if the patch has rejects')),
2776 [('f', 'force', None, _('apply if the patch has rejects')),
2777 ('l', 'list', None, _('list patch name in commit text')),
2777 ('l', 'list', None, _('list patch name in commit text')),
2778 ('a', 'all', None, _('apply all patches')),
2778 ('a', 'all', None, _('apply all patches')),
2779 ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
2779 ('m', 'merge', None, _('merge from another queue (DEPRECATED)')),
2780 ('n', 'name', '', _('merge queue name (DEPRECATED)')),
2780 ('n', 'name', '', _('merge queue name (DEPRECATED)')),
2781 ('', 'move', None, _('reorder patch series and apply only the patch'))],
2781 ('', 'move', None, _('reorder patch series and apply only the patch'))],
2782 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [--move] [PATCH | INDEX]')),
2782 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [--move] [PATCH | INDEX]')),
2783 "^qrefresh":
2783 "^qrefresh":
2784 (refresh,
2784 (refresh,
2785 [('e', 'edit', None, _('edit commit message')),
2785 [('e', 'edit', None, _('edit commit message')),
2786 ('g', 'git', None, _('use git extended diff format')),
2786 ('g', 'git', None, _('use git extended diff format')),
2787 ('s', 'short', None,
2787 ('s', 'short', None,
2788 _('refresh only files already in the patch and specified files')),
2788 _('refresh only files already in the patch and specified files')),
2789 ('U', 'currentuser', None,
2789 ('U', 'currentuser', None,
2790 _('add/update author field in patch with current user')),
2790 _('add/update author field in patch with current user')),
2791 ('u', 'user', '',
2791 ('u', 'user', '',
2792 _('add/update author field in patch with given user')),
2792 _('add/update author field in patch with given user')),
2793 ('D', 'currentdate', None,
2793 ('D', 'currentdate', None,
2794 _('add/update date field in patch with current date')),
2794 _('add/update date field in patch with current date')),
2795 ('d', 'date', '',
2795 ('d', 'date', '',
2796 _('add/update date field in patch with given date'))
2796 _('add/update date field in patch with given date'))
2797 ] + commands.walkopts + commands.commitopts,
2797 ] + commands.walkopts + commands.commitopts,
2798 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2798 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2799 'qrename|qmv':
2799 'qrename|qmv':
2800 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2800 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2801 "qrestore":
2801 "qrestore":
2802 (restore,
2802 (restore,
2803 [('d', 'delete', None, _('delete save entry')),
2803 [('d', 'delete', None, _('delete save entry')),
2804 ('u', 'update', None, _('update queue working directory'))],
2804 ('u', 'update', None, _('update queue working directory'))],
2805 _('hg qrestore [-d] [-u] REV')),
2805 _('hg qrestore [-d] [-u] REV')),
2806 "qsave":
2806 "qsave":
2807 (save,
2807 (save,
2808 [('c', 'copy', None, _('copy patch directory')),
2808 [('c', 'copy', None, _('copy patch directory')),
2809 ('n', 'name', '', _('copy directory name')),
2809 ('n', 'name', '', _('copy directory name')),
2810 ('e', 'empty', None, _('clear queue status file')),
2810 ('e', 'empty', None, _('clear queue status file')),
2811 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2811 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2812 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2812 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2813 "qselect":
2813 "qselect":
2814 (select,
2814 (select,
2815 [('n', 'none', None, _('disable all guards')),
2815 [('n', 'none', None, _('disable all guards')),
2816 ('s', 'series', None, _('list all guards in series file')),
2816 ('s', 'series', None, _('list all guards in series file')),
2817 ('', 'pop', None, _('pop to before first guarded applied patch')),
2817 ('', 'pop', None, _('pop to before first guarded applied patch')),
2818 ('', 'reapply', None, _('pop, then reapply patches'))],
2818 ('', 'reapply', None, _('pop, then reapply patches'))],
2819 _('hg qselect [OPTION]... [GUARD]...')),
2819 _('hg qselect [OPTION]... [GUARD]...')),
2820 "qseries":
2820 "qseries":
2821 (series,
2821 (series,
2822 [('m', 'missing', None, _('print patches not in series')),
2822 [('m', 'missing', None, _('print patches not in series')),
2823 ] + seriesopts,
2823 ] + seriesopts,
2824 _('hg qseries [-ms]')),
2824 _('hg qseries [-ms]')),
2825 "strip":
2825 "strip":
2826 (strip,
2826 (strip,
2827 [('f', 'force', None, _('force removal of changesets even if the '
2827 [('f', 'force', None, _('force removal of changesets even if the '
2828 'working directory has uncommitted changes')),
2828 'working directory has uncommitted changes')),
2829 ('b', 'backup', None, _('bundle only changesets with local revision'
2829 ('b', 'backup', None, _('bundle only changesets with local revision'
2830 ' number greater than REV which are not'
2830 ' number greater than REV which are not'
2831 ' descendants of REV (DEPRECATED)')),
2831 ' descendants of REV (DEPRECATED)')),
2832 ('n', 'nobackup', None, _('no backups'))],
2832 ('n', 'nobackup', None, _('no backups'))],
2833 _('hg strip [-f] [-b] [-n] REV')),
2833 _('hg strip [-f] [-b] [-n] REV')),
2834 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2834 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2835 "qunapplied":
2835 "qunapplied":
2836 (unapplied,
2836 (unapplied,
2837 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2837 [('1', 'first', None, _('show only the first patch'))] + seriesopts,
2838 _('hg qunapplied [-1] [-s] [PATCH]')),
2838 _('hg qunapplied [-1] [-s] [PATCH]')),
2839 "qfinish":
2839 "qfinish":
2840 (finish,
2840 (finish,
2841 [('a', 'applied', None, _('finish all applied changesets'))],
2841 [('a', 'applied', None, _('finish all applied changesets'))],
2842 _('hg qfinish [-a] [REV]...')),
2842 _('hg qfinish [-a] [REV]...')),
2843 }
2843 }
2844
2844
2845 colortable = {'qguard.negative': 'red',
2845 colortable = {'qguard.negative': 'red',
2846 'qguard.positive': 'yellow',
2846 'qguard.positive': 'yellow',
2847 'qguard.unguarded': 'green',
2847 'qguard.unguarded': 'green',
2848 'qseries.applied': 'blue bold underline',
2848 'qseries.applied': 'blue bold underline',
2849 'qseries.guarded': 'black bold',
2849 'qseries.guarded': 'black bold',
2850 'qseries.missing': 'red bold',
2850 'qseries.missing': 'red bold',
2851 'qseries.unapplied': 'black bold'}
2851 'qseries.unapplied': 'black bold'}
General Comments 0
You need to be logged in to leave comments. Login now