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