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