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