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