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