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