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