##// END OF EJS Templates
manifest.execf is now a function.
Vadim Gelfer -
r2872:d36af1f1 default
parent child Browse files
Show More
@@ -1,1925 +1,1925 b''
1
1
2 # queue.py - patch queues for mercurial
2 # queue.py - patch queues for mercurial
3 #
3 #
4 # Copyright 2005 Chris Mason <mason@suse.com>
4 # Copyright 2005 Chris Mason <mason@suse.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 '''patch management and development
9 '''patch management and development
10
10
11 This extension lets you work with a stack of patches in a Mercurial
11 This extension lets you work with a stack of patches in a Mercurial
12 repository. It manages two stacks of patches - all known patches, and
12 repository. It manages two stacks of patches - all known patches, and
13 applied patches (subset of known patches).
13 applied patches (subset of known patches).
14
14
15 Known patches are represented as patch files in the .hg/patches
15 Known patches are represented as patch files in the .hg/patches
16 directory. Applied patches are both patch files and changesets.
16 directory. Applied patches are both patch files and changesets.
17
17
18 Common tasks (use "hg help command" for more details):
18 Common tasks (use "hg help command" for more details):
19
19
20 prepare repository to work with patches qinit
20 prepare repository to work with patches qinit
21 create new patch qnew
21 create new patch qnew
22 import existing patch qimport
22 import existing patch qimport
23
23
24 print patch series qseries
24 print patch series qseries
25 print applied patches qapplied
25 print applied patches qapplied
26 print name of top applied patch qtop
26 print name of top applied patch qtop
27
27
28 add known patch to applied stack qpush
28 add known patch to applied stack qpush
29 remove patch from applied stack qpop
29 remove patch from applied stack qpop
30 refresh contents of top applied patch qrefresh
30 refresh contents of top applied patch qrefresh
31 '''
31 '''
32
32
33 from mercurial.demandload import *
33 from mercurial.demandload import *
34 demandload(globals(), "os sys re struct traceback errno bz2")
34 demandload(globals(), "os sys re struct traceback errno bz2")
35 from mercurial.i18n import gettext as _
35 from mercurial.i18n import gettext as _
36 from mercurial import ui, hg, revlog, commands, util
36 from mercurial import ui, hg, revlog, commands, util
37
37
38 commands.norepo += " qclone qversion"
38 commands.norepo += " qclone qversion"
39
39
40 class statusentry:
40 class statusentry:
41 def __init__(self, rev, name=None):
41 def __init__(self, rev, name=None):
42 if not name:
42 if not name:
43 fields = rev.split(':')
43 fields = rev.split(':')
44 if len(fields) == 2:
44 if len(fields) == 2:
45 self.rev, self.name = fields
45 self.rev, self.name = fields
46 else:
46 else:
47 self.rev, self.name = None, None
47 self.rev, self.name = None, None
48 else:
48 else:
49 self.rev, self.name = rev, name
49 self.rev, self.name = rev, name
50
50
51 def __str__(self):
51 def __str__(self):
52 return self.rev + ':' + self.name
52 return self.rev + ':' + self.name
53
53
54 class queue:
54 class queue:
55 def __init__(self, ui, path, patchdir=None):
55 def __init__(self, ui, path, patchdir=None):
56 self.basepath = path
56 self.basepath = path
57 self.path = patchdir or os.path.join(path, "patches")
57 self.path = patchdir or os.path.join(path, "patches")
58 self.opener = util.opener(self.path)
58 self.opener = util.opener(self.path)
59 self.ui = ui
59 self.ui = ui
60 self.applied = []
60 self.applied = []
61 self.full_series = []
61 self.full_series = []
62 self.applied_dirty = 0
62 self.applied_dirty = 0
63 self.series_dirty = 0
63 self.series_dirty = 0
64 self.series_path = "series"
64 self.series_path = "series"
65 self.status_path = "status"
65 self.status_path = "status"
66 self.guards_path = "guards"
66 self.guards_path = "guards"
67 self.active_guards = None
67 self.active_guards = None
68 self.guards_dirty = False
68 self.guards_dirty = False
69
69
70 if os.path.exists(self.join(self.series_path)):
70 if os.path.exists(self.join(self.series_path)):
71 self.full_series = self.opener(self.series_path).read().splitlines()
71 self.full_series = self.opener(self.series_path).read().splitlines()
72 self.parse_series()
72 self.parse_series()
73
73
74 if os.path.exists(self.join(self.status_path)):
74 if os.path.exists(self.join(self.status_path)):
75 lines = self.opener(self.status_path).read().splitlines()
75 lines = self.opener(self.status_path).read().splitlines()
76 self.applied = [statusentry(l) for l in lines]
76 self.applied = [statusentry(l) for l in lines]
77
77
78 def join(self, *p):
78 def join(self, *p):
79 return os.path.join(self.path, *p)
79 return os.path.join(self.path, *p)
80
80
81 def find_series(self, patch):
81 def find_series(self, patch):
82 pre = re.compile("(\s*)([^#]+)")
82 pre = re.compile("(\s*)([^#]+)")
83 index = 0
83 index = 0
84 for l in self.full_series:
84 for l in self.full_series:
85 m = pre.match(l)
85 m = pre.match(l)
86 if m:
86 if m:
87 s = m.group(2)
87 s = m.group(2)
88 s = s.rstrip()
88 s = s.rstrip()
89 if s == patch:
89 if s == patch:
90 return index
90 return index
91 index += 1
91 index += 1
92 return None
92 return None
93
93
94 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
94 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
95
95
96 def parse_series(self):
96 def parse_series(self):
97 self.series = []
97 self.series = []
98 self.series_guards = []
98 self.series_guards = []
99 for l in self.full_series:
99 for l in self.full_series:
100 h = l.find('#')
100 h = l.find('#')
101 if h == -1:
101 if h == -1:
102 patch = l
102 patch = l
103 comment = ''
103 comment = ''
104 elif h == 0:
104 elif h == 0:
105 continue
105 continue
106 else:
106 else:
107 patch = l[:h]
107 patch = l[:h]
108 comment = l[h:]
108 comment = l[h:]
109 patch = patch.strip()
109 patch = patch.strip()
110 if patch:
110 if patch:
111 self.series.append(patch)
111 self.series.append(patch)
112 self.series_guards.append(self.guard_re.findall(comment))
112 self.series_guards.append(self.guard_re.findall(comment))
113
113
114 def check_guard(self, guard):
114 def check_guard(self, guard):
115 bad_chars = '# \t\r\n\f'
115 bad_chars = '# \t\r\n\f'
116 first = guard[0]
116 first = guard[0]
117 for c in '-+':
117 for c in '-+':
118 if first == c:
118 if first == c:
119 return (_('guard %r starts with invalid character: %r') %
119 return (_('guard %r starts with invalid character: %r') %
120 (guard, c))
120 (guard, c))
121 for c in bad_chars:
121 for c in bad_chars:
122 if c in guard:
122 if c in guard:
123 return _('invalid character in guard %r: %r') % (guard, c)
123 return _('invalid character in guard %r: %r') % (guard, c)
124
124
125 def set_active(self, guards):
125 def set_active(self, guards):
126 for guard in guards:
126 for guard in guards:
127 bad = self.check_guard(guard)
127 bad = self.check_guard(guard)
128 if bad:
128 if bad:
129 raise util.Abort(bad)
129 raise util.Abort(bad)
130 guards = dict.fromkeys(guards).keys()
130 guards = dict.fromkeys(guards).keys()
131 guards.sort()
131 guards.sort()
132 self.ui.debug('active guards: %s\n' % ' '.join(guards))
132 self.ui.debug('active guards: %s\n' % ' '.join(guards))
133 self.active_guards = guards
133 self.active_guards = guards
134 self.guards_dirty = True
134 self.guards_dirty = True
135
135
136 def active(self):
136 def active(self):
137 if self.active_guards is None:
137 if self.active_guards is None:
138 self.active_guards = []
138 self.active_guards = []
139 try:
139 try:
140 guards = self.opener(self.guards_path).read().split()
140 guards = self.opener(self.guards_path).read().split()
141 except IOError, err:
141 except IOError, err:
142 if err.errno != errno.ENOENT: raise
142 if err.errno != errno.ENOENT: raise
143 guards = []
143 guards = []
144 for i, guard in enumerate(guards):
144 for i, guard in enumerate(guards):
145 bad = self.check_guard(guard)
145 bad = self.check_guard(guard)
146 if bad:
146 if bad:
147 self.ui.warn('%s:%d: %s\n' %
147 self.ui.warn('%s:%d: %s\n' %
148 (self.join(self.guards_path), i + 1, bad))
148 (self.join(self.guards_path), i + 1, bad))
149 else:
149 else:
150 self.active_guards.append(guard)
150 self.active_guards.append(guard)
151 return self.active_guards
151 return self.active_guards
152
152
153 def set_guards(self, idx, guards):
153 def set_guards(self, idx, guards):
154 for g in guards:
154 for g in guards:
155 if len(g) < 2:
155 if len(g) < 2:
156 raise util.Abort(_('guard %r too short') % g)
156 raise util.Abort(_('guard %r too short') % g)
157 if g[0] not in '-+':
157 if g[0] not in '-+':
158 raise util.Abort(_('guard %r starts with invalid char') % g)
158 raise util.Abort(_('guard %r starts with invalid char') % g)
159 bad = self.check_guard(g[1:])
159 bad = self.check_guard(g[1:])
160 if bad:
160 if bad:
161 raise util.Abort(bad)
161 raise util.Abort(bad)
162 drop = self.guard_re.sub('', self.full_series[idx])
162 drop = self.guard_re.sub('', self.full_series[idx])
163 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
163 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
164 self.parse_series()
164 self.parse_series()
165 self.series_dirty = True
165 self.series_dirty = True
166
166
167 def pushable(self, idx):
167 def pushable(self, idx):
168 if isinstance(idx, str):
168 if isinstance(idx, str):
169 idx = self.series.index(idx)
169 idx = self.series.index(idx)
170 patchguards = self.series_guards[idx]
170 patchguards = self.series_guards[idx]
171 if not patchguards:
171 if not patchguards:
172 return True, None
172 return True, None
173 default = False
173 default = False
174 guards = self.active()
174 guards = self.active()
175 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
175 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
176 if exactneg:
176 if exactneg:
177 return False, exactneg[0]
177 return False, exactneg[0]
178 pos = [g for g in patchguards if g[0] == '+']
178 pos = [g for g in patchguards if g[0] == '+']
179 nonpos = [g for g in pos if g[1:] not in guards]
179 nonpos = [g for g in pos if g[1:] not in guards]
180 if pos:
180 if pos:
181 if not nonpos:
181 if not nonpos:
182 return True, ''
182 return True, ''
183 return False, nonpos
183 return False, nonpos
184 return True, ''
184 return True, ''
185
185
186 def explain_pushable(self, idx, all_patches=False):
186 def explain_pushable(self, idx, all_patches=False):
187 write = all_patches and self.ui.write or self.ui.warn
187 write = all_patches and self.ui.write or self.ui.warn
188 if all_patches or self.ui.verbose:
188 if all_patches or self.ui.verbose:
189 if isinstance(idx, str):
189 if isinstance(idx, str):
190 idx = self.series.index(idx)
190 idx = self.series.index(idx)
191 pushable, why = self.pushable(idx)
191 pushable, why = self.pushable(idx)
192 if all_patches and pushable:
192 if all_patches and pushable:
193 if why is None:
193 if why is None:
194 write(_('allowing %s - no guards in effect\n') %
194 write(_('allowing %s - no guards in effect\n') %
195 self.series[idx])
195 self.series[idx])
196 else:
196 else:
197 if not why:
197 if not why:
198 write(_('allowing %s - no matching negative guards\n') %
198 write(_('allowing %s - no matching negative guards\n') %
199 self.series[idx])
199 self.series[idx])
200 else:
200 else:
201 write(_('allowing %s - guarded by %r\n') %
201 write(_('allowing %s - guarded by %r\n') %
202 (self.series[idx], why))
202 (self.series[idx], why))
203 if not pushable:
203 if not pushable:
204 if why:
204 if why:
205 write(_('skipping %s - guarded by %r\n') %
205 write(_('skipping %s - guarded by %r\n') %
206 (self.series[idx], ' '.join(why)))
206 (self.series[idx], ' '.join(why)))
207 else:
207 else:
208 write(_('skipping %s - no matching guards\n') %
208 write(_('skipping %s - no matching guards\n') %
209 self.series[idx])
209 self.series[idx])
210
210
211 def save_dirty(self):
211 def save_dirty(self):
212 def write_list(items, path):
212 def write_list(items, path):
213 fp = self.opener(path, 'w')
213 fp = self.opener(path, 'w')
214 for i in items:
214 for i in items:
215 print >> fp, i
215 print >> fp, i
216 fp.close()
216 fp.close()
217 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
217 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
218 if self.series_dirty: write_list(self.full_series, self.series_path)
218 if self.series_dirty: write_list(self.full_series, self.series_path)
219 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
219 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
220
220
221 def readheaders(self, patch):
221 def readheaders(self, patch):
222 def eatdiff(lines):
222 def eatdiff(lines):
223 while lines:
223 while lines:
224 l = lines[-1]
224 l = lines[-1]
225 if (l.startswith("diff -") or
225 if (l.startswith("diff -") or
226 l.startswith("Index:") or
226 l.startswith("Index:") or
227 l.startswith("===========")):
227 l.startswith("===========")):
228 del lines[-1]
228 del lines[-1]
229 else:
229 else:
230 break
230 break
231 def eatempty(lines):
231 def eatempty(lines):
232 while lines:
232 while lines:
233 l = lines[-1]
233 l = lines[-1]
234 if re.match('\s*$', l):
234 if re.match('\s*$', l):
235 del lines[-1]
235 del lines[-1]
236 else:
236 else:
237 break
237 break
238
238
239 pf = self.join(patch)
239 pf = self.join(patch)
240 message = []
240 message = []
241 comments = []
241 comments = []
242 user = None
242 user = None
243 date = None
243 date = None
244 format = None
244 format = None
245 subject = None
245 subject = None
246 diffstart = 0
246 diffstart = 0
247
247
248 for line in file(pf):
248 for line in file(pf):
249 line = line.rstrip()
249 line = line.rstrip()
250 if diffstart:
250 if diffstart:
251 if line.startswith('+++ '):
251 if line.startswith('+++ '):
252 diffstart = 2
252 diffstart = 2
253 break
253 break
254 if line.startswith("--- "):
254 if line.startswith("--- "):
255 diffstart = 1
255 diffstart = 1
256 continue
256 continue
257 elif format == "hgpatch":
257 elif format == "hgpatch":
258 # parse values when importing the result of an hg export
258 # parse values when importing the result of an hg export
259 if line.startswith("# User "):
259 if line.startswith("# User "):
260 user = line[7:]
260 user = line[7:]
261 elif line.startswith("# Date "):
261 elif line.startswith("# Date "):
262 date = line[7:]
262 date = line[7:]
263 elif not line.startswith("# ") and line:
263 elif not line.startswith("# ") and line:
264 message.append(line)
264 message.append(line)
265 format = None
265 format = None
266 elif line == '# HG changeset patch':
266 elif line == '# HG changeset patch':
267 format = "hgpatch"
267 format = "hgpatch"
268 elif (format != "tagdone" and (line.startswith("Subject: ") or
268 elif (format != "tagdone" and (line.startswith("Subject: ") or
269 line.startswith("subject: "))):
269 line.startswith("subject: "))):
270 subject = line[9:]
270 subject = line[9:]
271 format = "tag"
271 format = "tag"
272 elif (format != "tagdone" and (line.startswith("From: ") or
272 elif (format != "tagdone" and (line.startswith("From: ") or
273 line.startswith("from: "))):
273 line.startswith("from: "))):
274 user = line[6:]
274 user = line[6:]
275 format = "tag"
275 format = "tag"
276 elif format == "tag" and line == "":
276 elif format == "tag" and line == "":
277 # when looking for tags (subject: from: etc) they
277 # when looking for tags (subject: from: etc) they
278 # end once you find a blank line in the source
278 # end once you find a blank line in the source
279 format = "tagdone"
279 format = "tagdone"
280 elif message or line:
280 elif message or line:
281 message.append(line)
281 message.append(line)
282 comments.append(line)
282 comments.append(line)
283
283
284 eatdiff(message)
284 eatdiff(message)
285 eatdiff(comments)
285 eatdiff(comments)
286 eatempty(message)
286 eatempty(message)
287 eatempty(comments)
287 eatempty(comments)
288
288
289 # make sure message isn't empty
289 # make sure message isn't empty
290 if format and format.startswith("tag") and subject:
290 if format and format.startswith("tag") and subject:
291 message.insert(0, "")
291 message.insert(0, "")
292 message.insert(0, subject)
292 message.insert(0, subject)
293 return (message, comments, user, date, diffstart > 1)
293 return (message, comments, user, date, diffstart > 1)
294
294
295 def mergeone(self, repo, mergeq, head, patch, rev, wlock):
295 def mergeone(self, repo, mergeq, head, patch, rev, wlock):
296 # first try just applying the patch
296 # first try just applying the patch
297 (err, n) = self.apply(repo, [ patch ], update_status=False,
297 (err, n) = self.apply(repo, [ patch ], update_status=False,
298 strict=True, merge=rev, wlock=wlock)
298 strict=True, merge=rev, wlock=wlock)
299
299
300 if err == 0:
300 if err == 0:
301 return (err, n)
301 return (err, n)
302
302
303 if n is None:
303 if n is None:
304 raise util.Abort(_("apply failed for patch %s") % patch)
304 raise util.Abort(_("apply failed for patch %s") % patch)
305
305
306 self.ui.warn("patch didn't work out, merging %s\n" % patch)
306 self.ui.warn("patch didn't work out, merging %s\n" % patch)
307
307
308 # apply failed, strip away that rev and merge.
308 # apply failed, strip away that rev and merge.
309 hg.clean(repo, head, wlock=wlock)
309 hg.clean(repo, head, wlock=wlock)
310 self.strip(repo, n, update=False, backup='strip', wlock=wlock)
310 self.strip(repo, n, update=False, backup='strip', wlock=wlock)
311
311
312 c = repo.changelog.read(rev)
312 c = repo.changelog.read(rev)
313 ret = hg.merge(repo, rev, wlock=wlock)
313 ret = hg.merge(repo, rev, wlock=wlock)
314 if ret:
314 if ret:
315 raise util.Abort(_("update returned %d") % ret)
315 raise util.Abort(_("update returned %d") % ret)
316 n = repo.commit(None, c[4], c[1], force=1, wlock=wlock)
316 n = repo.commit(None, c[4], c[1], force=1, wlock=wlock)
317 if n == None:
317 if n == None:
318 raise util.Abort(_("repo commit failed"))
318 raise util.Abort(_("repo commit failed"))
319 try:
319 try:
320 message, comments, user, date, patchfound = mergeq.readheaders(patch)
320 message, comments, user, date, patchfound = mergeq.readheaders(patch)
321 except:
321 except:
322 raise util.Abort(_("unable to read %s") % patch)
322 raise util.Abort(_("unable to read %s") % patch)
323
323
324 patchf = self.opener(patch, "w")
324 patchf = self.opener(patch, "w")
325 if comments:
325 if comments:
326 comments = "\n".join(comments) + '\n\n'
326 comments = "\n".join(comments) + '\n\n'
327 patchf.write(comments)
327 patchf.write(comments)
328 commands.dodiff(patchf, self.ui, repo, head, n)
328 commands.dodiff(patchf, self.ui, repo, head, n)
329 patchf.close()
329 patchf.close()
330 return (0, n)
330 return (0, n)
331
331
332 def qparents(self, repo, rev=None):
332 def qparents(self, repo, rev=None):
333 if rev is None:
333 if rev is None:
334 (p1, p2) = repo.dirstate.parents()
334 (p1, p2) = repo.dirstate.parents()
335 if p2 == revlog.nullid:
335 if p2 == revlog.nullid:
336 return p1
336 return p1
337 if len(self.applied) == 0:
337 if len(self.applied) == 0:
338 return None
338 return None
339 return revlog.bin(self.applied[-1].rev)
339 return revlog.bin(self.applied[-1].rev)
340 pp = repo.changelog.parents(rev)
340 pp = repo.changelog.parents(rev)
341 if pp[1] != revlog.nullid:
341 if pp[1] != revlog.nullid:
342 arevs = [ x.rev for x in self.applied ]
342 arevs = [ x.rev for x in self.applied ]
343 p0 = revlog.hex(pp[0])
343 p0 = revlog.hex(pp[0])
344 p1 = revlog.hex(pp[1])
344 p1 = revlog.hex(pp[1])
345 if p0 in arevs:
345 if p0 in arevs:
346 return pp[0]
346 return pp[0]
347 if p1 in arevs:
347 if p1 in arevs:
348 return pp[1]
348 return pp[1]
349 return pp[0]
349 return pp[0]
350
350
351 def mergepatch(self, repo, mergeq, series, wlock):
351 def mergepatch(self, repo, mergeq, series, wlock):
352 if len(self.applied) == 0:
352 if len(self.applied) == 0:
353 # each of the patches merged in will have two parents. This
353 # each of the patches merged in will have two parents. This
354 # can confuse the qrefresh, qdiff, and strip code because it
354 # can confuse the qrefresh, qdiff, and strip code because it
355 # needs to know which parent is actually in the patch queue.
355 # needs to know which parent is actually in the patch queue.
356 # so, we insert a merge marker with only one parent. This way
356 # so, we insert a merge marker with only one parent. This way
357 # the first patch in the queue is never a merge patch
357 # the first patch in the queue is never a merge patch
358 #
358 #
359 pname = ".hg.patches.merge.marker"
359 pname = ".hg.patches.merge.marker"
360 n = repo.commit(None, '[mq]: merge marker', user=None, force=1,
360 n = repo.commit(None, '[mq]: merge marker', user=None, force=1,
361 wlock=wlock)
361 wlock=wlock)
362 self.applied.append(statusentry(revlog.hex(n), pname))
362 self.applied.append(statusentry(revlog.hex(n), pname))
363 self.applied_dirty = 1
363 self.applied_dirty = 1
364
364
365 head = self.qparents(repo)
365 head = self.qparents(repo)
366
366
367 for patch in series:
367 for patch in series:
368 patch = mergeq.lookup(patch, strict=True)
368 patch = mergeq.lookup(patch, strict=True)
369 if not patch:
369 if not patch:
370 self.ui.warn("patch %s does not exist\n" % patch)
370 self.ui.warn("patch %s does not exist\n" % patch)
371 return (1, None)
371 return (1, None)
372 pushable, reason = self.pushable(patch)
372 pushable, reason = self.pushable(patch)
373 if not pushable:
373 if not pushable:
374 self.explain_pushable(patch, all_patches=True)
374 self.explain_pushable(patch, all_patches=True)
375 continue
375 continue
376 info = mergeq.isapplied(patch)
376 info = mergeq.isapplied(patch)
377 if not info:
377 if not info:
378 self.ui.warn("patch %s is not applied\n" % patch)
378 self.ui.warn("patch %s is not applied\n" % patch)
379 return (1, None)
379 return (1, None)
380 rev = revlog.bin(info[1])
380 rev = revlog.bin(info[1])
381 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock)
381 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock)
382 if head:
382 if head:
383 self.applied.append(statusentry(revlog.hex(head), patch))
383 self.applied.append(statusentry(revlog.hex(head), patch))
384 self.applied_dirty = 1
384 self.applied_dirty = 1
385 if err:
385 if err:
386 return (err, head)
386 return (err, head)
387 return (0, head)
387 return (0, head)
388
388
389 def patch(self, repo, patchfile):
389 def patch(self, repo, patchfile):
390 '''Apply patchfile to the working directory.
390 '''Apply patchfile to the working directory.
391 patchfile: file name of patch'''
391 patchfile: file name of patch'''
392 try:
392 try:
393 pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
393 pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
394 f = os.popen("%s -d %s -p1 --no-backup-if-mismatch < %s" %
394 f = os.popen("%s -d %s -p1 --no-backup-if-mismatch < %s" %
395 (pp, util.shellquote(repo.root), util.shellquote(patchfile)))
395 (pp, util.shellquote(repo.root), util.shellquote(patchfile)))
396 except:
396 except:
397 self.ui.warn("patch failed, unable to continue (try -v)\n")
397 self.ui.warn("patch failed, unable to continue (try -v)\n")
398 return (None, [], False)
398 return (None, [], False)
399 files = []
399 files = []
400 fuzz = False
400 fuzz = False
401 for l in f:
401 for l in f:
402 l = l.rstrip('\r\n');
402 l = l.rstrip('\r\n');
403 if self.ui.verbose:
403 if self.ui.verbose:
404 self.ui.warn(l + "\n")
404 self.ui.warn(l + "\n")
405 if l[:14] == 'patching file ':
405 if l[:14] == 'patching file ':
406 pf = os.path.normpath(util.parse_patch_output(l))
406 pf = os.path.normpath(util.parse_patch_output(l))
407 if pf not in files:
407 if pf not in files:
408 files.append(pf)
408 files.append(pf)
409 printed_file = False
409 printed_file = False
410 file_str = l
410 file_str = l
411 elif l.find('with fuzz') >= 0:
411 elif l.find('with fuzz') >= 0:
412 if not printed_file:
412 if not printed_file:
413 self.ui.warn(file_str + '\n')
413 self.ui.warn(file_str + '\n')
414 printed_file = True
414 printed_file = True
415 self.ui.warn(l + '\n')
415 self.ui.warn(l + '\n')
416 fuzz = True
416 fuzz = True
417 elif l.find('saving rejects to file') >= 0:
417 elif l.find('saving rejects to file') >= 0:
418 self.ui.warn(l + '\n')
418 self.ui.warn(l + '\n')
419 elif l.find('FAILED') >= 0:
419 elif l.find('FAILED') >= 0:
420 if not printed_file:
420 if not printed_file:
421 self.ui.warn(file_str + '\n')
421 self.ui.warn(file_str + '\n')
422 printed_file = True
422 printed_file = True
423 self.ui.warn(l + '\n')
423 self.ui.warn(l + '\n')
424
424
425 return (not f.close(), files, fuzz)
425 return (not f.close(), files, fuzz)
426
426
427 def apply(self, repo, series, list=False, update_status=True,
427 def apply(self, repo, series, list=False, update_status=True,
428 strict=False, patchdir=None, merge=None, wlock=None):
428 strict=False, patchdir=None, merge=None, wlock=None):
429 # TODO unify with commands.py
429 # TODO unify with commands.py
430 if not patchdir:
430 if not patchdir:
431 patchdir = self.path
431 patchdir = self.path
432 err = 0
432 err = 0
433 if not wlock:
433 if not wlock:
434 wlock = repo.wlock()
434 wlock = repo.wlock()
435 lock = repo.lock()
435 lock = repo.lock()
436 tr = repo.transaction()
436 tr = repo.transaction()
437 n = None
437 n = None
438 for patch in series:
438 for patch in series:
439 pushable, reason = self.pushable(patch)
439 pushable, reason = self.pushable(patch)
440 if not pushable:
440 if not pushable:
441 self.explain_pushable(patch, all_patches=True)
441 self.explain_pushable(patch, all_patches=True)
442 continue
442 continue
443 self.ui.warn("applying %s\n" % patch)
443 self.ui.warn("applying %s\n" % patch)
444 pf = os.path.join(patchdir, patch)
444 pf = os.path.join(patchdir, patch)
445
445
446 try:
446 try:
447 message, comments, user, date, patchfound = self.readheaders(patch)
447 message, comments, user, date, patchfound = self.readheaders(patch)
448 except:
448 except:
449 self.ui.warn("Unable to read %s\n" % pf)
449 self.ui.warn("Unable to read %s\n" % pf)
450 err = 1
450 err = 1
451 break
451 break
452
452
453 if not message:
453 if not message:
454 message = "imported patch %s\n" % patch
454 message = "imported patch %s\n" % patch
455 else:
455 else:
456 if list:
456 if list:
457 message.append("\nimported patch %s" % patch)
457 message.append("\nimported patch %s" % patch)
458 message = '\n'.join(message)
458 message = '\n'.join(message)
459
459
460 (patcherr, files, fuzz) = self.patch(repo, pf)
460 (patcherr, files, fuzz) = self.patch(repo, pf)
461 patcherr = not patcherr
461 patcherr = not patcherr
462
462
463 if merge and len(files) > 0:
463 if merge and len(files) > 0:
464 # Mark as merged and update dirstate parent info
464 # Mark as merged and update dirstate parent info
465 repo.dirstate.update(repo.dirstate.filterfiles(files), 'm')
465 repo.dirstate.update(repo.dirstate.filterfiles(files), 'm')
466 p1, p2 = repo.dirstate.parents()
466 p1, p2 = repo.dirstate.parents()
467 repo.dirstate.setparents(p1, merge)
467 repo.dirstate.setparents(p1, merge)
468 if len(files) > 0:
468 if len(files) > 0:
469 cwd = repo.getcwd()
469 cwd = repo.getcwd()
470 cfiles = files
470 cfiles = files
471 if cwd:
471 if cwd:
472 cfiles = [util.pathto(cwd, f) for f in files]
472 cfiles = [util.pathto(cwd, f) for f in files]
473 commands.addremove_lock(self.ui, repo, cfiles,
473 commands.addremove_lock(self.ui, repo, cfiles,
474 opts={}, wlock=wlock)
474 opts={}, wlock=wlock)
475 n = repo.commit(files, message, user, date, force=1, lock=lock,
475 n = repo.commit(files, message, user, date, force=1, lock=lock,
476 wlock=wlock)
476 wlock=wlock)
477
477
478 if n == None:
478 if n == None:
479 raise util.Abort(_("repo commit failed"))
479 raise util.Abort(_("repo commit failed"))
480
480
481 if update_status:
481 if update_status:
482 self.applied.append(statusentry(revlog.hex(n), patch))
482 self.applied.append(statusentry(revlog.hex(n), patch))
483
483
484 if patcherr:
484 if patcherr:
485 if not patchfound:
485 if not patchfound:
486 self.ui.warn("patch %s is empty\n" % patch)
486 self.ui.warn("patch %s is empty\n" % patch)
487 err = 0
487 err = 0
488 else:
488 else:
489 self.ui.warn("patch failed, rejects left in working dir\n")
489 self.ui.warn("patch failed, rejects left in working dir\n")
490 err = 1
490 err = 1
491 break
491 break
492
492
493 if fuzz and strict:
493 if fuzz and strict:
494 self.ui.warn("fuzz found when applying patch, stopping\n")
494 self.ui.warn("fuzz found when applying patch, stopping\n")
495 err = 1
495 err = 1
496 break
496 break
497 tr.close()
497 tr.close()
498 return (err, n)
498 return (err, n)
499
499
500 def delete(self, repo, patch, force=False):
500 def delete(self, repo, patch, force=False):
501 patch = self.lookup(patch, strict=True)
501 patch = self.lookup(patch, strict=True)
502 info = self.isapplied(patch)
502 info = self.isapplied(patch)
503 if info:
503 if info:
504 raise util.Abort(_("cannot delete applied patch %s") % patch)
504 raise util.Abort(_("cannot delete applied patch %s") % patch)
505 if patch not in self.series:
505 if patch not in self.series:
506 raise util.Abort(_("patch %s not in series file") % patch)
506 raise util.Abort(_("patch %s not in series file") % patch)
507 if force:
507 if force:
508 r = self.qrepo()
508 r = self.qrepo()
509 if r:
509 if r:
510 r.remove([patch], True)
510 r.remove([patch], True)
511 else:
511 else:
512 os.unlink(self.join(patch))
512 os.unlink(self.join(patch))
513 i = self.find_series(patch)
513 i = self.find_series(patch)
514 del self.full_series[i]
514 del self.full_series[i]
515 self.parse_series()
515 self.parse_series()
516 self.series_dirty = 1
516 self.series_dirty = 1
517
517
518 def check_toppatch(self, repo):
518 def check_toppatch(self, repo):
519 if len(self.applied) > 0:
519 if len(self.applied) > 0:
520 top = revlog.bin(self.applied[-1].rev)
520 top = revlog.bin(self.applied[-1].rev)
521 pp = repo.dirstate.parents()
521 pp = repo.dirstate.parents()
522 if top not in pp:
522 if top not in pp:
523 raise util.Abort(_("queue top not at same revision as working directory"))
523 raise util.Abort(_("queue top not at same revision as working directory"))
524 return top
524 return top
525 return None
525 return None
526 def check_localchanges(self, repo):
526 def check_localchanges(self, repo):
527 (c, a, r, d, u) = repo.changes(None, None)
527 (c, a, r, d, u) = repo.changes(None, None)
528 if c or a or d or r:
528 if c or a or d or r:
529 raise util.Abort(_("local changes found, refresh first"))
529 raise util.Abort(_("local changes found, refresh first"))
530 def new(self, repo, patch, msg=None, force=None):
530 def new(self, repo, patch, msg=None, force=None):
531 if os.path.exists(self.join(patch)):
531 if os.path.exists(self.join(patch)):
532 raise util.Abort(_('patch "%s" already exists') % patch)
532 raise util.Abort(_('patch "%s" already exists') % patch)
533 commitfiles = []
533 commitfiles = []
534 (c, a, r, d, u) = repo.changes(None, None)
534 (c, a, r, d, u) = repo.changes(None, None)
535 if c or a or d or r:
535 if c or a or d or r:
536 if not force:
536 if not force:
537 raise util.Abort(_("local changes found, refresh first"))
537 raise util.Abort(_("local changes found, refresh first"))
538 commitfiles = c + a + r
538 commitfiles = c + a + r
539 self.check_toppatch(repo)
539 self.check_toppatch(repo)
540 wlock = repo.wlock()
540 wlock = repo.wlock()
541 insert = self.full_series_end()
541 insert = self.full_series_end()
542 if msg:
542 if msg:
543 n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True,
543 n = repo.commit(commitfiles, "[mq]: %s" % msg, force=True,
544 wlock=wlock)
544 wlock=wlock)
545 else:
545 else:
546 n = repo.commit(commitfiles,
546 n = repo.commit(commitfiles,
547 "New patch: %s" % patch, force=True, wlock=wlock)
547 "New patch: %s" % patch, force=True, wlock=wlock)
548 if n == None:
548 if n == None:
549 raise util.Abort(_("repo commit failed"))
549 raise util.Abort(_("repo commit failed"))
550 self.full_series[insert:insert] = [patch]
550 self.full_series[insert:insert] = [patch]
551 self.applied.append(statusentry(revlog.hex(n), patch))
551 self.applied.append(statusentry(revlog.hex(n), patch))
552 self.parse_series()
552 self.parse_series()
553 self.series_dirty = 1
553 self.series_dirty = 1
554 self.applied_dirty = 1
554 self.applied_dirty = 1
555 p = self.opener(patch, "w")
555 p = self.opener(patch, "w")
556 if msg:
556 if msg:
557 msg = msg + "\n"
557 msg = msg + "\n"
558 p.write(msg)
558 p.write(msg)
559 p.close()
559 p.close()
560 wlock = None
560 wlock = None
561 r = self.qrepo()
561 r = self.qrepo()
562 if r: r.add([patch])
562 if r: r.add([patch])
563 if commitfiles:
563 if commitfiles:
564 self.refresh(repo, msg=None, short=True)
564 self.refresh(repo, msg=None, short=True)
565
565
566 def strip(self, repo, rev, update=True, backup="all", wlock=None):
566 def strip(self, repo, rev, update=True, backup="all", wlock=None):
567 def limitheads(chlog, stop):
567 def limitheads(chlog, stop):
568 """return the list of all nodes that have no children"""
568 """return the list of all nodes that have no children"""
569 p = {}
569 p = {}
570 h = []
570 h = []
571 stoprev = 0
571 stoprev = 0
572 if stop in chlog.nodemap:
572 if stop in chlog.nodemap:
573 stoprev = chlog.rev(stop)
573 stoprev = chlog.rev(stop)
574
574
575 for r in range(chlog.count() - 1, -1, -1):
575 for r in range(chlog.count() - 1, -1, -1):
576 n = chlog.node(r)
576 n = chlog.node(r)
577 if n not in p:
577 if n not in p:
578 h.append(n)
578 h.append(n)
579 if n == stop:
579 if n == stop:
580 break
580 break
581 if r < stoprev:
581 if r < stoprev:
582 break
582 break
583 for pn in chlog.parents(n):
583 for pn in chlog.parents(n):
584 p[pn] = 1
584 p[pn] = 1
585 return h
585 return h
586
586
587 def bundle(cg):
587 def bundle(cg):
588 backupdir = repo.join("strip-backup")
588 backupdir = repo.join("strip-backup")
589 if not os.path.isdir(backupdir):
589 if not os.path.isdir(backupdir):
590 os.mkdir(backupdir)
590 os.mkdir(backupdir)
591 name = os.path.join(backupdir, "%s" % revlog.short(rev))
591 name = os.path.join(backupdir, "%s" % revlog.short(rev))
592 name = savename(name)
592 name = savename(name)
593 self.ui.warn("saving bundle to %s\n" % name)
593 self.ui.warn("saving bundle to %s\n" % name)
594 # TODO, exclusive open
594 # TODO, exclusive open
595 f = open(name, "wb")
595 f = open(name, "wb")
596 try:
596 try:
597 f.write("HG10")
597 f.write("HG10")
598 z = bz2.BZ2Compressor(9)
598 z = bz2.BZ2Compressor(9)
599 while 1:
599 while 1:
600 chunk = cg.read(4096)
600 chunk = cg.read(4096)
601 if not chunk:
601 if not chunk:
602 break
602 break
603 f.write(z.compress(chunk))
603 f.write(z.compress(chunk))
604 f.write(z.flush())
604 f.write(z.flush())
605 except:
605 except:
606 os.unlink(name)
606 os.unlink(name)
607 raise
607 raise
608 f.close()
608 f.close()
609 return name
609 return name
610
610
611 def stripall(rev, revnum):
611 def stripall(rev, revnum):
612 cl = repo.changelog
612 cl = repo.changelog
613 c = cl.read(rev)
613 c = cl.read(rev)
614 mm = repo.manifest.read(c[0])
614 mm = repo.manifest.read(c[0])
615 seen = {}
615 seen = {}
616
616
617 for x in xrange(revnum, cl.count()):
617 for x in xrange(revnum, cl.count()):
618 c = cl.read(cl.node(x))
618 c = cl.read(cl.node(x))
619 for f in c[3]:
619 for f in c[3]:
620 if f in seen:
620 if f in seen:
621 continue
621 continue
622 seen[f] = 1
622 seen[f] = 1
623 if f in mm:
623 if f in mm:
624 filerev = mm[f]
624 filerev = mm[f]
625 else:
625 else:
626 filerev = 0
626 filerev = 0
627 seen[f] = filerev
627 seen[f] = filerev
628 # we go in two steps here so the strip loop happens in a
628 # we go in two steps here so the strip loop happens in a
629 # sensible order. When stripping many files, this helps keep
629 # sensible order. When stripping many files, this helps keep
630 # our disk access patterns under control.
630 # our disk access patterns under control.
631 seen_list = seen.keys()
631 seen_list = seen.keys()
632 seen_list.sort()
632 seen_list.sort()
633 for f in seen_list:
633 for f in seen_list:
634 ff = repo.file(f)
634 ff = repo.file(f)
635 filerev = seen[f]
635 filerev = seen[f]
636 if filerev != 0:
636 if filerev != 0:
637 if filerev in ff.nodemap:
637 if filerev in ff.nodemap:
638 filerev = ff.rev(filerev)
638 filerev = ff.rev(filerev)
639 else:
639 else:
640 filerev = 0
640 filerev = 0
641 ff.strip(filerev, revnum)
641 ff.strip(filerev, revnum)
642
642
643 if not wlock:
643 if not wlock:
644 wlock = repo.wlock()
644 wlock = repo.wlock()
645 lock = repo.lock()
645 lock = repo.lock()
646 chlog = repo.changelog
646 chlog = repo.changelog
647 # TODO delete the undo files, and handle undo of merge sets
647 # TODO delete the undo files, and handle undo of merge sets
648 pp = chlog.parents(rev)
648 pp = chlog.parents(rev)
649 revnum = chlog.rev(rev)
649 revnum = chlog.rev(rev)
650
650
651 if update:
651 if update:
652 (c, a, r, d, u) = repo.changes(None, None)
652 (c, a, r, d, u) = repo.changes(None, None)
653 if c or a or d or r:
653 if c or a or d or r:
654 raise util.Abort(_("local changes found"))
654 raise util.Abort(_("local changes found"))
655 urev = self.qparents(repo, rev)
655 urev = self.qparents(repo, rev)
656 hg.clean(repo, urev, wlock=wlock)
656 hg.clean(repo, urev, wlock=wlock)
657 repo.dirstate.write()
657 repo.dirstate.write()
658
658
659 # save is a list of all the branches we are truncating away
659 # save is a list of all the branches we are truncating away
660 # that we actually want to keep. changegroup will be used
660 # that we actually want to keep. changegroup will be used
661 # to preserve them and add them back after the truncate
661 # to preserve them and add them back after the truncate
662 saveheads = []
662 saveheads = []
663 savebases = {}
663 savebases = {}
664
664
665 heads = limitheads(chlog, rev)
665 heads = limitheads(chlog, rev)
666 seen = {}
666 seen = {}
667
667
668 # search through all the heads, finding those where the revision
668 # search through all the heads, finding those where the revision
669 # we want to strip away is an ancestor. Also look for merges
669 # we want to strip away is an ancestor. Also look for merges
670 # that might be turned into new heads by the strip.
670 # that might be turned into new heads by the strip.
671 while heads:
671 while heads:
672 h = heads.pop()
672 h = heads.pop()
673 n = h
673 n = h
674 while True:
674 while True:
675 seen[n] = 1
675 seen[n] = 1
676 pp = chlog.parents(n)
676 pp = chlog.parents(n)
677 if pp[1] != revlog.nullid and chlog.rev(pp[1]) > revnum:
677 if pp[1] != revlog.nullid and chlog.rev(pp[1]) > revnum:
678 if pp[1] not in seen:
678 if pp[1] not in seen:
679 heads.append(pp[1])
679 heads.append(pp[1])
680 if pp[0] == revlog.nullid:
680 if pp[0] == revlog.nullid:
681 break
681 break
682 if chlog.rev(pp[0]) < revnum:
682 if chlog.rev(pp[0]) < revnum:
683 break
683 break
684 n = pp[0]
684 n = pp[0]
685 if n == rev:
685 if n == rev:
686 break
686 break
687 r = chlog.reachable(h, rev)
687 r = chlog.reachable(h, rev)
688 if rev not in r:
688 if rev not in r:
689 saveheads.append(h)
689 saveheads.append(h)
690 for x in r:
690 for x in r:
691 if chlog.rev(x) > revnum:
691 if chlog.rev(x) > revnum:
692 savebases[x] = 1
692 savebases[x] = 1
693
693
694 # create a changegroup for all the branches we need to keep
694 # create a changegroup for all the branches we need to keep
695 if backup == "all":
695 if backup == "all":
696 backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip')
696 backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip')
697 bundle(backupch)
697 bundle(backupch)
698 if saveheads:
698 if saveheads:
699 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
699 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
700 chgrpfile = bundle(backupch)
700 chgrpfile = bundle(backupch)
701
701
702 stripall(rev, revnum)
702 stripall(rev, revnum)
703
703
704 change = chlog.read(rev)
704 change = chlog.read(rev)
705 repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
705 repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
706 chlog.strip(revnum, revnum)
706 chlog.strip(revnum, revnum)
707 if saveheads:
707 if saveheads:
708 self.ui.status("adding branch\n")
708 self.ui.status("adding branch\n")
709 commands.unbundle(self.ui, repo, chgrpfile, update=False)
709 commands.unbundle(self.ui, repo, chgrpfile, update=False)
710 if backup != "strip":
710 if backup != "strip":
711 os.unlink(chgrpfile)
711 os.unlink(chgrpfile)
712
712
713 def isapplied(self, patch):
713 def isapplied(self, patch):
714 """returns (index, rev, patch)"""
714 """returns (index, rev, patch)"""
715 for i in xrange(len(self.applied)):
715 for i in xrange(len(self.applied)):
716 a = self.applied[i]
716 a = self.applied[i]
717 if a.name == patch:
717 if a.name == patch:
718 return (i, a.rev, a.name)
718 return (i, a.rev, a.name)
719 return None
719 return None
720
720
721 # if the exact patch name does not exist, we try a few
721 # if the exact patch name does not exist, we try a few
722 # variations. If strict is passed, we try only #1
722 # variations. If strict is passed, we try only #1
723 #
723 #
724 # 1) a number to indicate an offset in the series file
724 # 1) a number to indicate an offset in the series file
725 # 2) a unique substring of the patch name was given
725 # 2) a unique substring of the patch name was given
726 # 3) patchname[-+]num to indicate an offset in the series file
726 # 3) patchname[-+]num to indicate an offset in the series file
727 def lookup(self, patch, strict=False):
727 def lookup(self, patch, strict=False):
728 def partial_name(s):
728 def partial_name(s):
729 if s in self.series:
729 if s in self.series:
730 return s
730 return s
731 matches = [x for x in self.series if s in x]
731 matches = [x for x in self.series if s in x]
732 if len(matches) > 1:
732 if len(matches) > 1:
733 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
733 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
734 for m in matches:
734 for m in matches:
735 self.ui.warn(' %s\n' % m)
735 self.ui.warn(' %s\n' % m)
736 return None
736 return None
737 if matches:
737 if matches:
738 return matches[0]
738 return matches[0]
739 if len(self.series) > 0 and len(self.applied) > 0:
739 if len(self.series) > 0 and len(self.applied) > 0:
740 if s == 'qtip':
740 if s == 'qtip':
741 return self.series[self.series_end()-1]
741 return self.series[self.series_end()-1]
742 if s == 'qbase':
742 if s == 'qbase':
743 return self.series[0]
743 return self.series[0]
744 return None
744 return None
745 if patch == None:
745 if patch == None:
746 return None
746 return None
747
747
748 # we don't want to return a partial match until we make
748 # we don't want to return a partial match until we make
749 # sure the file name passed in does not exist (checked below)
749 # sure the file name passed in does not exist (checked below)
750 res = partial_name(patch)
750 res = partial_name(patch)
751 if res and res == patch:
751 if res and res == patch:
752 return res
752 return res
753
753
754 if not os.path.isfile(self.join(patch)):
754 if not os.path.isfile(self.join(patch)):
755 try:
755 try:
756 sno = int(patch)
756 sno = int(patch)
757 except(ValueError, OverflowError):
757 except(ValueError, OverflowError):
758 pass
758 pass
759 else:
759 else:
760 if sno < len(self.series):
760 if sno < len(self.series):
761 return self.series[sno]
761 return self.series[sno]
762 if not strict:
762 if not strict:
763 # return any partial match made above
763 # return any partial match made above
764 if res:
764 if res:
765 return res
765 return res
766 minus = patch.rsplit('-', 1)
766 minus = patch.rsplit('-', 1)
767 if len(minus) > 1:
767 if len(minus) > 1:
768 res = partial_name(minus[0])
768 res = partial_name(minus[0])
769 if res:
769 if res:
770 i = self.series.index(res)
770 i = self.series.index(res)
771 try:
771 try:
772 off = int(minus[1] or 1)
772 off = int(minus[1] or 1)
773 except(ValueError, OverflowError):
773 except(ValueError, OverflowError):
774 pass
774 pass
775 else:
775 else:
776 if i - off >= 0:
776 if i - off >= 0:
777 return self.series[i - off]
777 return self.series[i - off]
778 plus = patch.rsplit('+', 1)
778 plus = patch.rsplit('+', 1)
779 if len(plus) > 1:
779 if len(plus) > 1:
780 res = partial_name(plus[0])
780 res = partial_name(plus[0])
781 if res:
781 if res:
782 i = self.series.index(res)
782 i = self.series.index(res)
783 try:
783 try:
784 off = int(plus[1] or 1)
784 off = int(plus[1] or 1)
785 except(ValueError, OverflowError):
785 except(ValueError, OverflowError):
786 pass
786 pass
787 else:
787 else:
788 if i + off < len(self.series):
788 if i + off < len(self.series):
789 return self.series[i + off]
789 return self.series[i + off]
790 raise util.Abort(_("patch %s not in series") % patch)
790 raise util.Abort(_("patch %s not in series") % patch)
791
791
792 def push(self, repo, patch=None, force=False, list=False,
792 def push(self, repo, patch=None, force=False, list=False,
793 mergeq=None, wlock=None):
793 mergeq=None, wlock=None):
794 if not wlock:
794 if not wlock:
795 wlock = repo.wlock()
795 wlock = repo.wlock()
796 patch = self.lookup(patch)
796 patch = self.lookup(patch)
797 if patch and self.isapplied(patch):
797 if patch and self.isapplied(patch):
798 self.ui.warn(_("patch %s is already applied\n") % patch)
798 self.ui.warn(_("patch %s is already applied\n") % patch)
799 sys.exit(1)
799 sys.exit(1)
800 if self.series_end() == len(self.series):
800 if self.series_end() == len(self.series):
801 self.ui.warn(_("patch series fully applied\n"))
801 self.ui.warn(_("patch series fully applied\n"))
802 sys.exit(1)
802 sys.exit(1)
803 if not force:
803 if not force:
804 self.check_localchanges(repo)
804 self.check_localchanges(repo)
805
805
806 self.applied_dirty = 1;
806 self.applied_dirty = 1;
807 start = self.series_end()
807 start = self.series_end()
808 if start > 0:
808 if start > 0:
809 self.check_toppatch(repo)
809 self.check_toppatch(repo)
810 if not patch:
810 if not patch:
811 patch = self.series[start]
811 patch = self.series[start]
812 end = start + 1
812 end = start + 1
813 else:
813 else:
814 end = self.series.index(patch, start) + 1
814 end = self.series.index(patch, start) + 1
815 s = self.series[start:end]
815 s = self.series[start:end]
816 if mergeq:
816 if mergeq:
817 ret = self.mergepatch(repo, mergeq, s, wlock)
817 ret = self.mergepatch(repo, mergeq, s, wlock)
818 else:
818 else:
819 ret = self.apply(repo, s, list, wlock=wlock)
819 ret = self.apply(repo, s, list, wlock=wlock)
820 top = self.applied[-1].name
820 top = self.applied[-1].name
821 if ret[0]:
821 if ret[0]:
822 self.ui.write("Errors during apply, please fix and refresh %s\n" %
822 self.ui.write("Errors during apply, please fix and refresh %s\n" %
823 top)
823 top)
824 else:
824 else:
825 self.ui.write("Now at: %s\n" % top)
825 self.ui.write("Now at: %s\n" % top)
826 return ret[0]
826 return ret[0]
827
827
828 def pop(self, repo, patch=None, force=False, update=True, all=False,
828 def pop(self, repo, patch=None, force=False, update=True, all=False,
829 wlock=None):
829 wlock=None):
830 def getfile(f, rev):
830 def getfile(f, rev):
831 t = repo.file(f).read(rev)
831 t = repo.file(f).read(rev)
832 try:
832 try:
833 repo.wfile(f, "w").write(t)
833 repo.wfile(f, "w").write(t)
834 except IOError:
834 except IOError:
835 try:
835 try:
836 os.makedirs(os.path.dirname(repo.wjoin(f)))
836 os.makedirs(os.path.dirname(repo.wjoin(f)))
837 except OSError, err:
837 except OSError, err:
838 if err.errno != errno.EEXIST: raise
838 if err.errno != errno.EEXIST: raise
839 repo.wfile(f, "w").write(t)
839 repo.wfile(f, "w").write(t)
840
840
841 if not wlock:
841 if not wlock:
842 wlock = repo.wlock()
842 wlock = repo.wlock()
843 if patch:
843 if patch:
844 # index, rev, patch
844 # index, rev, patch
845 info = self.isapplied(patch)
845 info = self.isapplied(patch)
846 if not info:
846 if not info:
847 patch = self.lookup(patch)
847 patch = self.lookup(patch)
848 info = self.isapplied(patch)
848 info = self.isapplied(patch)
849 if not info:
849 if not info:
850 raise util.Abort(_("patch %s is not applied") % patch)
850 raise util.Abort(_("patch %s is not applied") % patch)
851 if len(self.applied) == 0:
851 if len(self.applied) == 0:
852 self.ui.warn(_("no patches applied\n"))
852 self.ui.warn(_("no patches applied\n"))
853 sys.exit(1)
853 sys.exit(1)
854
854
855 if not update:
855 if not update:
856 parents = repo.dirstate.parents()
856 parents = repo.dirstate.parents()
857 rr = [ revlog.bin(x.rev) for x in self.applied ]
857 rr = [ revlog.bin(x.rev) for x in self.applied ]
858 for p in parents:
858 for p in parents:
859 if p in rr:
859 if p in rr:
860 self.ui.warn("qpop: forcing dirstate update\n")
860 self.ui.warn("qpop: forcing dirstate update\n")
861 update = True
861 update = True
862
862
863 if not force and update:
863 if not force and update:
864 self.check_localchanges(repo)
864 self.check_localchanges(repo)
865
865
866 self.applied_dirty = 1;
866 self.applied_dirty = 1;
867 end = len(self.applied)
867 end = len(self.applied)
868 if not patch:
868 if not patch:
869 if all:
869 if all:
870 popi = 0
870 popi = 0
871 else:
871 else:
872 popi = len(self.applied) - 1
872 popi = len(self.applied) - 1
873 else:
873 else:
874 popi = info[0] + 1
874 popi = info[0] + 1
875 if popi >= end:
875 if popi >= end:
876 self.ui.warn("qpop: %s is already at the top\n" % patch)
876 self.ui.warn("qpop: %s is already at the top\n" % patch)
877 return
877 return
878 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
878 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
879
879
880 start = info[0]
880 start = info[0]
881 rev = revlog.bin(info[1])
881 rev = revlog.bin(info[1])
882
882
883 # we know there are no local changes, so we can make a simplified
883 # we know there are no local changes, so we can make a simplified
884 # form of hg.update.
884 # form of hg.update.
885 if update:
885 if update:
886 top = self.check_toppatch(repo)
886 top = self.check_toppatch(repo)
887 qp = self.qparents(repo, rev)
887 qp = self.qparents(repo, rev)
888 changes = repo.changelog.read(qp)
888 changes = repo.changelog.read(qp)
889 mmap = repo.manifest.read(changes[0])
889 mmap = repo.manifest.read(changes[0])
890 (c, a, r, d, u) = repo.changes(qp, top)
890 (c, a, r, d, u) = repo.changes(qp, top)
891 if d:
891 if d:
892 raise util.Abort("deletions found between repo revs")
892 raise util.Abort("deletions found between repo revs")
893 for f in c:
893 for f in c:
894 getfile(f, mmap[f])
894 getfile(f, mmap[f])
895 for f in r:
895 for f in r:
896 getfile(f, mmap[f])
896 getfile(f, mmap[f])
897 util.set_exec(repo.wjoin(f), mmap.execf[f])
897 util.set_exec(repo.wjoin(f), mmap.execf(f))
898 repo.dirstate.update(c + r, 'n')
898 repo.dirstate.update(c + r, 'n')
899 for f in a:
899 for f in a:
900 try: os.unlink(repo.wjoin(f))
900 try: os.unlink(repo.wjoin(f))
901 except: raise
901 except: raise
902 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
902 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
903 except: pass
903 except: pass
904 if a:
904 if a:
905 repo.dirstate.forget(a)
905 repo.dirstate.forget(a)
906 repo.dirstate.setparents(qp, revlog.nullid)
906 repo.dirstate.setparents(qp, revlog.nullid)
907 self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
907 self.strip(repo, rev, update=False, backup='strip', wlock=wlock)
908 del self.applied[start:end]
908 del self.applied[start:end]
909 if len(self.applied):
909 if len(self.applied):
910 self.ui.write("Now at: %s\n" % self.applied[-1].name)
910 self.ui.write("Now at: %s\n" % self.applied[-1].name)
911 else:
911 else:
912 self.ui.write("Patch queue now empty\n")
912 self.ui.write("Patch queue now empty\n")
913
913
914 def diff(self, repo, files):
914 def diff(self, repo, files):
915 top = self.check_toppatch(repo)
915 top = self.check_toppatch(repo)
916 if not top:
916 if not top:
917 self.ui.write("No patches applied\n")
917 self.ui.write("No patches applied\n")
918 return
918 return
919 qp = self.qparents(repo, top)
919 qp = self.qparents(repo, top)
920 commands.dodiff(sys.stdout, self.ui, repo, qp, None, files)
920 commands.dodiff(sys.stdout, self.ui, repo, qp, None, files)
921
921
922 def refresh(self, repo, msg=None, short=False):
922 def refresh(self, repo, msg=None, short=False):
923 if len(self.applied) == 0:
923 if len(self.applied) == 0:
924 self.ui.write("No patches applied\n")
924 self.ui.write("No patches applied\n")
925 return
925 return
926 wlock = repo.wlock()
926 wlock = repo.wlock()
927 self.check_toppatch(repo)
927 self.check_toppatch(repo)
928 (top, patch) = (self.applied[-1].rev, self.applied[-1].name)
928 (top, patch) = (self.applied[-1].rev, self.applied[-1].name)
929 top = revlog.bin(top)
929 top = revlog.bin(top)
930 cparents = repo.changelog.parents(top)
930 cparents = repo.changelog.parents(top)
931 patchparent = self.qparents(repo, top)
931 patchparent = self.qparents(repo, top)
932 message, comments, user, date, patchfound = self.readheaders(patch)
932 message, comments, user, date, patchfound = self.readheaders(patch)
933
933
934 patchf = self.opener(patch, "w")
934 patchf = self.opener(patch, "w")
935 msg = msg.rstrip()
935 msg = msg.rstrip()
936 if msg:
936 if msg:
937 if comments:
937 if comments:
938 # Remove existing message.
938 # Remove existing message.
939 ci = 0
939 ci = 0
940 for mi in range(len(message)):
940 for mi in range(len(message)):
941 while message[mi] != comments[ci]:
941 while message[mi] != comments[ci]:
942 ci += 1
942 ci += 1
943 del comments[ci]
943 del comments[ci]
944 comments.append(msg)
944 comments.append(msg)
945 if comments:
945 if comments:
946 comments = "\n".join(comments) + '\n\n'
946 comments = "\n".join(comments) + '\n\n'
947 patchf.write(comments)
947 patchf.write(comments)
948
948
949 tip = repo.changelog.tip()
949 tip = repo.changelog.tip()
950 if top == tip:
950 if top == tip:
951 # if the top of our patch queue is also the tip, there is an
951 # if the top of our patch queue is also the tip, there is an
952 # optimization here. We update the dirstate in place and strip
952 # optimization here. We update the dirstate in place and strip
953 # off the tip commit. Then just commit the current directory
953 # off the tip commit. Then just commit the current directory
954 # tree. We can also send repo.commit the list of files
954 # tree. We can also send repo.commit the list of files
955 # changed to speed up the diff
955 # changed to speed up the diff
956 #
956 #
957 # in short mode, we only diff the files included in the
957 # in short mode, we only diff the files included in the
958 # patch already
958 # patch already
959 #
959 #
960 # this should really read:
960 # this should really read:
961 #(cc, dd, aa, aa2, uu) = repo.changes(tip, patchparent)
961 #(cc, dd, aa, aa2, uu) = repo.changes(tip, patchparent)
962 # but we do it backwards to take advantage of manifest/chlog
962 # but we do it backwards to take advantage of manifest/chlog
963 # caching against the next repo.changes call
963 # caching against the next repo.changes call
964 #
964 #
965 (cc, aa, dd, aa2, uu) = repo.changes(patchparent, tip)
965 (cc, aa, dd, aa2, uu) = repo.changes(patchparent, tip)
966 if short:
966 if short:
967 filelist = cc + aa + dd
967 filelist = cc + aa + dd
968 else:
968 else:
969 filelist = None
969 filelist = None
970 (c, a, r, d, u) = repo.changes(None, None, filelist)
970 (c, a, r, d, u) = repo.changes(None, None, filelist)
971
971
972 # we might end up with files that were added between tip and
972 # we might end up with files that were added between tip and
973 # the dirstate parent, but then changed in the local dirstate.
973 # the dirstate parent, but then changed in the local dirstate.
974 # in this case, we want them to only show up in the added section
974 # in this case, we want them to only show up in the added section
975 for x in c:
975 for x in c:
976 if x not in aa:
976 if x not in aa:
977 cc.append(x)
977 cc.append(x)
978 # we might end up with files added by the local dirstate that
978 # we might end up with files added by the local dirstate that
979 # were deleted by the patch. In this case, they should only
979 # were deleted by the patch. In this case, they should only
980 # show up in the changed section.
980 # show up in the changed section.
981 for x in a:
981 for x in a:
982 if x in dd:
982 if x in dd:
983 del dd[dd.index(x)]
983 del dd[dd.index(x)]
984 cc.append(x)
984 cc.append(x)
985 else:
985 else:
986 aa.append(x)
986 aa.append(x)
987 # make sure any files deleted in the local dirstate
987 # make sure any files deleted in the local dirstate
988 # are not in the add or change column of the patch
988 # are not in the add or change column of the patch
989 forget = []
989 forget = []
990 for x in d + r:
990 for x in d + r:
991 if x in aa:
991 if x in aa:
992 del aa[aa.index(x)]
992 del aa[aa.index(x)]
993 forget.append(x)
993 forget.append(x)
994 continue
994 continue
995 elif x in cc:
995 elif x in cc:
996 del cc[cc.index(x)]
996 del cc[cc.index(x)]
997 dd.append(x)
997 dd.append(x)
998
998
999 c = list(util.unique(cc))
999 c = list(util.unique(cc))
1000 r = list(util.unique(dd))
1000 r = list(util.unique(dd))
1001 a = list(util.unique(aa))
1001 a = list(util.unique(aa))
1002 filelist = list(util.unique(c + r + a ))
1002 filelist = list(util.unique(c + r + a ))
1003 commands.dodiff(patchf, self.ui, repo, patchparent, None,
1003 commands.dodiff(patchf, self.ui, repo, patchparent, None,
1004 filelist, changes=(c, a, r, [], u))
1004 filelist, changes=(c, a, r, [], u))
1005 patchf.close()
1005 patchf.close()
1006
1006
1007 changes = repo.changelog.read(tip)
1007 changes = repo.changelog.read(tip)
1008 repo.dirstate.setparents(*cparents)
1008 repo.dirstate.setparents(*cparents)
1009 repo.dirstate.update(a, 'a')
1009 repo.dirstate.update(a, 'a')
1010 repo.dirstate.update(r, 'r')
1010 repo.dirstate.update(r, 'r')
1011 repo.dirstate.update(c, 'n')
1011 repo.dirstate.update(c, 'n')
1012 repo.dirstate.forget(forget)
1012 repo.dirstate.forget(forget)
1013
1013
1014 if not msg:
1014 if not msg:
1015 if not message:
1015 if not message:
1016 message = "patch queue: %s\n" % patch
1016 message = "patch queue: %s\n" % patch
1017 else:
1017 else:
1018 message = "\n".join(message)
1018 message = "\n".join(message)
1019 else:
1019 else:
1020 message = msg
1020 message = msg
1021
1021
1022 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
1022 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
1023 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
1023 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
1024 self.applied[-1] = statusentry(revlog.hex(n), patch)
1024 self.applied[-1] = statusentry(revlog.hex(n), patch)
1025 self.applied_dirty = 1
1025 self.applied_dirty = 1
1026 else:
1026 else:
1027 commands.dodiff(patchf, self.ui, repo, patchparent, None)
1027 commands.dodiff(patchf, self.ui, repo, patchparent, None)
1028 patchf.close()
1028 patchf.close()
1029 self.pop(repo, force=True, wlock=wlock)
1029 self.pop(repo, force=True, wlock=wlock)
1030 self.push(repo, force=True, wlock=wlock)
1030 self.push(repo, force=True, wlock=wlock)
1031
1031
1032 def init(self, repo, create=False):
1032 def init(self, repo, create=False):
1033 if os.path.isdir(self.path):
1033 if os.path.isdir(self.path):
1034 raise util.Abort(_("patch queue directory already exists"))
1034 raise util.Abort(_("patch queue directory already exists"))
1035 os.mkdir(self.path)
1035 os.mkdir(self.path)
1036 if create:
1036 if create:
1037 return self.qrepo(create=True)
1037 return self.qrepo(create=True)
1038
1038
1039 def unapplied(self, repo, patch=None):
1039 def unapplied(self, repo, patch=None):
1040 if patch and patch not in self.series:
1040 if patch and patch not in self.series:
1041 raise util.Abort(_("patch %s is not in series file") % patch)
1041 raise util.Abort(_("patch %s is not in series file") % patch)
1042 if not patch:
1042 if not patch:
1043 start = self.series_end()
1043 start = self.series_end()
1044 else:
1044 else:
1045 start = self.series.index(patch) + 1
1045 start = self.series.index(patch) + 1
1046 unapplied = []
1046 unapplied = []
1047 for i in xrange(start, len(self.series)):
1047 for i in xrange(start, len(self.series)):
1048 pushable, reason = self.pushable(i)
1048 pushable, reason = self.pushable(i)
1049 if pushable:
1049 if pushable:
1050 unapplied.append((i, self.series[i]))
1050 unapplied.append((i, self.series[i]))
1051 self.explain_pushable(i)
1051 self.explain_pushable(i)
1052 return unapplied
1052 return unapplied
1053
1053
1054 def qseries(self, repo, missing=None, summary=False):
1054 def qseries(self, repo, missing=None, summary=False):
1055 start = self.series_end(all_patches=True)
1055 start = self.series_end(all_patches=True)
1056 if not missing:
1056 if not missing:
1057 for i in range(len(self.series)):
1057 for i in range(len(self.series)):
1058 patch = self.series[i]
1058 patch = self.series[i]
1059 if self.ui.verbose:
1059 if self.ui.verbose:
1060 if i < start:
1060 if i < start:
1061 status = 'A'
1061 status = 'A'
1062 elif self.pushable(i)[0]:
1062 elif self.pushable(i)[0]:
1063 status = 'U'
1063 status = 'U'
1064 else:
1064 else:
1065 status = 'G'
1065 status = 'G'
1066 self.ui.write('%d %s ' % (i, status))
1066 self.ui.write('%d %s ' % (i, status))
1067 if summary:
1067 if summary:
1068 msg = self.readheaders(patch)[0]
1068 msg = self.readheaders(patch)[0]
1069 msg = msg and ': ' + msg[0] or ': '
1069 msg = msg and ': ' + msg[0] or ': '
1070 else:
1070 else:
1071 msg = ''
1071 msg = ''
1072 self.ui.write('%s%s\n' % (patch, msg))
1072 self.ui.write('%s%s\n' % (patch, msg))
1073 else:
1073 else:
1074 msng_list = []
1074 msng_list = []
1075 for root, dirs, files in os.walk(self.path):
1075 for root, dirs, files in os.walk(self.path):
1076 d = root[len(self.path) + 1:]
1076 d = root[len(self.path) + 1:]
1077 for f in files:
1077 for f in files:
1078 fl = os.path.join(d, f)
1078 fl = os.path.join(d, f)
1079 if (fl not in self.series and
1079 if (fl not in self.series and
1080 fl not in (self.status_path, self.series_path)
1080 fl not in (self.status_path, self.series_path)
1081 and not fl.startswith('.')):
1081 and not fl.startswith('.')):
1082 msng_list.append(fl)
1082 msng_list.append(fl)
1083 msng_list.sort()
1083 msng_list.sort()
1084 for x in msng_list:
1084 for x in msng_list:
1085 if self.ui.verbose:
1085 if self.ui.verbose:
1086 self.ui.write("D ")
1086 self.ui.write("D ")
1087 self.ui.write("%s\n" % x)
1087 self.ui.write("%s\n" % x)
1088
1088
1089 def issaveline(self, l):
1089 def issaveline(self, l):
1090 if l.name == '.hg.patches.save.line':
1090 if l.name == '.hg.patches.save.line':
1091 return True
1091 return True
1092
1092
1093 def qrepo(self, create=False):
1093 def qrepo(self, create=False):
1094 if create or os.path.isdir(self.join(".hg")):
1094 if create or os.path.isdir(self.join(".hg")):
1095 return hg.repository(self.ui, path=self.path, create=create)
1095 return hg.repository(self.ui, path=self.path, create=create)
1096
1096
1097 def restore(self, repo, rev, delete=None, qupdate=None):
1097 def restore(self, repo, rev, delete=None, qupdate=None):
1098 c = repo.changelog.read(rev)
1098 c = repo.changelog.read(rev)
1099 desc = c[4].strip()
1099 desc = c[4].strip()
1100 lines = desc.splitlines()
1100 lines = desc.splitlines()
1101 i = 0
1101 i = 0
1102 datastart = None
1102 datastart = None
1103 series = []
1103 series = []
1104 applied = []
1104 applied = []
1105 qpp = None
1105 qpp = None
1106 for i in xrange(0, len(lines)):
1106 for i in xrange(0, len(lines)):
1107 if lines[i] == 'Patch Data:':
1107 if lines[i] == 'Patch Data:':
1108 datastart = i + 1
1108 datastart = i + 1
1109 elif lines[i].startswith('Dirstate:'):
1109 elif lines[i].startswith('Dirstate:'):
1110 l = lines[i].rstrip()
1110 l = lines[i].rstrip()
1111 l = l[10:].split(' ')
1111 l = l[10:].split(' ')
1112 qpp = [ hg.bin(x) for x in l ]
1112 qpp = [ hg.bin(x) for x in l ]
1113 elif datastart != None:
1113 elif datastart != None:
1114 l = lines[i].rstrip()
1114 l = lines[i].rstrip()
1115 se = statusentry(l)
1115 se = statusentry(l)
1116 file_ = se.name
1116 file_ = se.name
1117 if se.rev:
1117 if se.rev:
1118 applied.append(se)
1118 applied.append(se)
1119 series.append(file_)
1119 series.append(file_)
1120 if datastart == None:
1120 if datastart == None:
1121 self.ui.warn("No saved patch data found\n")
1121 self.ui.warn("No saved patch data found\n")
1122 return 1
1122 return 1
1123 self.ui.warn("restoring status: %s\n" % lines[0])
1123 self.ui.warn("restoring status: %s\n" % lines[0])
1124 self.full_series = series
1124 self.full_series = series
1125 self.applied = applied
1125 self.applied = applied
1126 self.parse_series()
1126 self.parse_series()
1127 self.series_dirty = 1
1127 self.series_dirty = 1
1128 self.applied_dirty = 1
1128 self.applied_dirty = 1
1129 heads = repo.changelog.heads()
1129 heads = repo.changelog.heads()
1130 if delete:
1130 if delete:
1131 if rev not in heads:
1131 if rev not in heads:
1132 self.ui.warn("save entry has children, leaving it alone\n")
1132 self.ui.warn("save entry has children, leaving it alone\n")
1133 else:
1133 else:
1134 self.ui.warn("removing save entry %s\n" % hg.short(rev))
1134 self.ui.warn("removing save entry %s\n" % hg.short(rev))
1135 pp = repo.dirstate.parents()
1135 pp = repo.dirstate.parents()
1136 if rev in pp:
1136 if rev in pp:
1137 update = True
1137 update = True
1138 else:
1138 else:
1139 update = False
1139 update = False
1140 self.strip(repo, rev, update=update, backup='strip')
1140 self.strip(repo, rev, update=update, backup='strip')
1141 if qpp:
1141 if qpp:
1142 self.ui.warn("saved queue repository parents: %s %s\n" %
1142 self.ui.warn("saved queue repository parents: %s %s\n" %
1143 (hg.short(qpp[0]), hg.short(qpp[1])))
1143 (hg.short(qpp[0]), hg.short(qpp[1])))
1144 if qupdate:
1144 if qupdate:
1145 print "queue directory updating"
1145 print "queue directory updating"
1146 r = self.qrepo()
1146 r = self.qrepo()
1147 if not r:
1147 if not r:
1148 self.ui.warn("Unable to load queue repository\n")
1148 self.ui.warn("Unable to load queue repository\n")
1149 return 1
1149 return 1
1150 hg.clean(r, qpp[0])
1150 hg.clean(r, qpp[0])
1151
1151
1152 def save(self, repo, msg=None):
1152 def save(self, repo, msg=None):
1153 if len(self.applied) == 0:
1153 if len(self.applied) == 0:
1154 self.ui.warn("save: no patches applied, exiting\n")
1154 self.ui.warn("save: no patches applied, exiting\n")
1155 return 1
1155 return 1
1156 if self.issaveline(self.applied[-1]):
1156 if self.issaveline(self.applied[-1]):
1157 self.ui.warn("status is already saved\n")
1157 self.ui.warn("status is already saved\n")
1158 return 1
1158 return 1
1159
1159
1160 ar = [ ':' + x for x in self.full_series ]
1160 ar = [ ':' + x for x in self.full_series ]
1161 if not msg:
1161 if not msg:
1162 msg = "hg patches saved state"
1162 msg = "hg patches saved state"
1163 else:
1163 else:
1164 msg = "hg patches: " + msg.rstrip('\r\n')
1164 msg = "hg patches: " + msg.rstrip('\r\n')
1165 r = self.qrepo()
1165 r = self.qrepo()
1166 if r:
1166 if r:
1167 pp = r.dirstate.parents()
1167 pp = r.dirstate.parents()
1168 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
1168 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1]))
1169 msg += "\n\nPatch Data:\n"
1169 msg += "\n\nPatch Data:\n"
1170 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1170 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1171 "\n".join(ar) + '\n' or "")
1171 "\n".join(ar) + '\n' or "")
1172 n = repo.commit(None, text, user=None, force=1)
1172 n = repo.commit(None, text, user=None, force=1)
1173 if not n:
1173 if not n:
1174 self.ui.warn("repo commit failed\n")
1174 self.ui.warn("repo commit failed\n")
1175 return 1
1175 return 1
1176 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1176 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1177 self.applied_dirty = 1
1177 self.applied_dirty = 1
1178
1178
1179 def full_series_end(self):
1179 def full_series_end(self):
1180 if len(self.applied) > 0:
1180 if len(self.applied) > 0:
1181 p = self.applied[-1].name
1181 p = self.applied[-1].name
1182 end = self.find_series(p)
1182 end = self.find_series(p)
1183 if end == None:
1183 if end == None:
1184 return len(self.full_series)
1184 return len(self.full_series)
1185 return end + 1
1185 return end + 1
1186 return 0
1186 return 0
1187
1187
1188 def series_end(self, all_patches=False):
1188 def series_end(self, all_patches=False):
1189 end = 0
1189 end = 0
1190 def next(start):
1190 def next(start):
1191 if all_patches:
1191 if all_patches:
1192 return start
1192 return start
1193 i = start
1193 i = start
1194 while i < len(self.series):
1194 while i < len(self.series):
1195 p, reason = self.pushable(i)
1195 p, reason = self.pushable(i)
1196 if p:
1196 if p:
1197 break
1197 break
1198 self.explain_pushable(i)
1198 self.explain_pushable(i)
1199 i += 1
1199 i += 1
1200 return i
1200 return i
1201 if len(self.applied) > 0:
1201 if len(self.applied) > 0:
1202 p = self.applied[-1].name
1202 p = self.applied[-1].name
1203 try:
1203 try:
1204 end = self.series.index(p)
1204 end = self.series.index(p)
1205 except ValueError:
1205 except ValueError:
1206 return 0
1206 return 0
1207 return next(end + 1)
1207 return next(end + 1)
1208 return next(end)
1208 return next(end)
1209
1209
1210 def qapplied(self, repo, patch=None):
1210 def qapplied(self, repo, patch=None):
1211 if patch and patch not in self.series:
1211 if patch and patch not in self.series:
1212 raise util.Abort(_("patch %s is not in series file") % patch)
1212 raise util.Abort(_("patch %s is not in series file") % patch)
1213 if not patch:
1213 if not patch:
1214 end = len(self.applied)
1214 end = len(self.applied)
1215 else:
1215 else:
1216 end = self.series.index(patch) + 1
1216 end = self.series.index(patch) + 1
1217 for x in xrange(end):
1217 for x in xrange(end):
1218 p = self.appliedname(x)
1218 p = self.appliedname(x)
1219 self.ui.write("%s\n" % p)
1219 self.ui.write("%s\n" % p)
1220
1220
1221 def appliedname(self, index):
1221 def appliedname(self, index):
1222 pname = self.applied[index].name
1222 pname = self.applied[index].name
1223 if not self.ui.verbose:
1223 if not self.ui.verbose:
1224 p = pname
1224 p = pname
1225 else:
1225 else:
1226 p = str(self.series.index(pname)) + " " + p
1226 p = str(self.series.index(pname)) + " " + p
1227 return p
1227 return p
1228
1228
1229 def top(self, repo):
1229 def top(self, repo):
1230 if len(self.applied):
1230 if len(self.applied):
1231 p = self.appliedname(-1)
1231 p = self.appliedname(-1)
1232 self.ui.write(p + '\n')
1232 self.ui.write(p + '\n')
1233 else:
1233 else:
1234 self.ui.write("No patches applied\n")
1234 self.ui.write("No patches applied\n")
1235
1235
1236 def next(self, repo):
1236 def next(self, repo):
1237 end = self.series_end()
1237 end = self.series_end()
1238 if end == len(self.series):
1238 if end == len(self.series):
1239 self.ui.write("All patches applied\n")
1239 self.ui.write("All patches applied\n")
1240 else:
1240 else:
1241 p = self.series[end]
1241 p = self.series[end]
1242 if self.ui.verbose:
1242 if self.ui.verbose:
1243 self.ui.write("%d " % self.series.index(p))
1243 self.ui.write("%d " % self.series.index(p))
1244 self.ui.write(p + '\n')
1244 self.ui.write(p + '\n')
1245
1245
1246 def prev(self, repo):
1246 def prev(self, repo):
1247 if len(self.applied) > 1:
1247 if len(self.applied) > 1:
1248 p = self.appliedname(-2)
1248 p = self.appliedname(-2)
1249 self.ui.write(p + '\n')
1249 self.ui.write(p + '\n')
1250 elif len(self.applied) == 1:
1250 elif len(self.applied) == 1:
1251 self.ui.write("Only one patch applied\n")
1251 self.ui.write("Only one patch applied\n")
1252 else:
1252 else:
1253 self.ui.write("No patches applied\n")
1253 self.ui.write("No patches applied\n")
1254
1254
1255 def qimport(self, repo, files, patch=None, existing=None, force=None):
1255 def qimport(self, repo, files, patch=None, existing=None, force=None):
1256 if len(files) > 1 and patch:
1256 if len(files) > 1 and patch:
1257 raise util.Abort(_('option "-n" not valid when importing multiple '
1257 raise util.Abort(_('option "-n" not valid when importing multiple '
1258 'files'))
1258 'files'))
1259 i = 0
1259 i = 0
1260 added = []
1260 added = []
1261 for filename in files:
1261 for filename in files:
1262 if existing:
1262 if existing:
1263 if not patch:
1263 if not patch:
1264 patch = filename
1264 patch = filename
1265 if not os.path.isfile(self.join(patch)):
1265 if not os.path.isfile(self.join(patch)):
1266 raise util.Abort(_("patch %s does not exist") % patch)
1266 raise util.Abort(_("patch %s does not exist") % patch)
1267 else:
1267 else:
1268 try:
1268 try:
1269 text = file(filename).read()
1269 text = file(filename).read()
1270 except IOError:
1270 except IOError:
1271 raise util.Abort(_("unable to read %s") % patch)
1271 raise util.Abort(_("unable to read %s") % patch)
1272 if not patch:
1272 if not patch:
1273 patch = os.path.split(filename)[1]
1273 patch = os.path.split(filename)[1]
1274 if not force and os.path.exists(self.join(patch)):
1274 if not force and os.path.exists(self.join(patch)):
1275 raise util.Abort(_('patch "%s" already exists') % patch)
1275 raise util.Abort(_('patch "%s" already exists') % patch)
1276 patchf = self.opener(patch, "w")
1276 patchf = self.opener(patch, "w")
1277 patchf.write(text)
1277 patchf.write(text)
1278 if patch in self.series:
1278 if patch in self.series:
1279 raise util.Abort(_('patch %s is already in the series file')
1279 raise util.Abort(_('patch %s is already in the series file')
1280 % patch)
1280 % patch)
1281 index = self.full_series_end() + i
1281 index = self.full_series_end() + i
1282 self.full_series[index:index] = [patch]
1282 self.full_series[index:index] = [patch]
1283 self.parse_series()
1283 self.parse_series()
1284 self.ui.warn("adding %s to series file\n" % patch)
1284 self.ui.warn("adding %s to series file\n" % patch)
1285 i += 1
1285 i += 1
1286 added.append(patch)
1286 added.append(patch)
1287 patch = None
1287 patch = None
1288 self.series_dirty = 1
1288 self.series_dirty = 1
1289 qrepo = self.qrepo()
1289 qrepo = self.qrepo()
1290 if qrepo:
1290 if qrepo:
1291 qrepo.add(added)
1291 qrepo.add(added)
1292
1292
1293 def delete(ui, repo, patch, **opts):
1293 def delete(ui, repo, patch, **opts):
1294 """remove a patch from the series file
1294 """remove a patch from the series file
1295
1295
1296 The patch must not be applied.
1296 The patch must not be applied.
1297 With -f, deletes the patch file as well as the series entry."""
1297 With -f, deletes the patch file as well as the series entry."""
1298 q = repo.mq
1298 q = repo.mq
1299 q.delete(repo, patch, force=opts.get('force'))
1299 q.delete(repo, patch, force=opts.get('force'))
1300 q.save_dirty()
1300 q.save_dirty()
1301 return 0
1301 return 0
1302
1302
1303 def applied(ui, repo, patch=None, **opts):
1303 def applied(ui, repo, patch=None, **opts):
1304 """print the patches already applied"""
1304 """print the patches already applied"""
1305 repo.mq.qapplied(repo, patch)
1305 repo.mq.qapplied(repo, patch)
1306 return 0
1306 return 0
1307
1307
1308 def unapplied(ui, repo, patch=None, **opts):
1308 def unapplied(ui, repo, patch=None, **opts):
1309 """print the patches not yet applied"""
1309 """print the patches not yet applied"""
1310 for i, p in repo.mq.unapplied(repo, patch):
1310 for i, p in repo.mq.unapplied(repo, patch):
1311 if ui.verbose:
1311 if ui.verbose:
1312 ui.write("%d " % i)
1312 ui.write("%d " % i)
1313 ui.write("%s\n" % p)
1313 ui.write("%s\n" % p)
1314
1314
1315 def qimport(ui, repo, *filename, **opts):
1315 def qimport(ui, repo, *filename, **opts):
1316 """import a patch"""
1316 """import a patch"""
1317 q = repo.mq
1317 q = repo.mq
1318 q.qimport(repo, filename, patch=opts['name'],
1318 q.qimport(repo, filename, patch=opts['name'],
1319 existing=opts['existing'], force=opts['force'])
1319 existing=opts['existing'], force=opts['force'])
1320 q.save_dirty()
1320 q.save_dirty()
1321 return 0
1321 return 0
1322
1322
1323 def init(ui, repo, **opts):
1323 def init(ui, repo, **opts):
1324 """init a new queue repository
1324 """init a new queue repository
1325
1325
1326 The queue repository is unversioned by default. If -c is
1326 The queue repository is unversioned by default. If -c is
1327 specified, qinit will create a separate nested repository
1327 specified, qinit will create a separate nested repository
1328 for patches. Use qcommit to commit changes to this queue
1328 for patches. Use qcommit to commit changes to this queue
1329 repository."""
1329 repository."""
1330 q = repo.mq
1330 q = repo.mq
1331 r = q.init(repo, create=opts['create_repo'])
1331 r = q.init(repo, create=opts['create_repo'])
1332 q.save_dirty()
1332 q.save_dirty()
1333 if r:
1333 if r:
1334 fp = r.wopener('.hgignore', 'w')
1334 fp = r.wopener('.hgignore', 'w')
1335 print >> fp, 'syntax: glob'
1335 print >> fp, 'syntax: glob'
1336 print >> fp, 'status'
1336 print >> fp, 'status'
1337 fp.close()
1337 fp.close()
1338 r.wopener('series', 'w').close()
1338 r.wopener('series', 'w').close()
1339 r.add(['.hgignore', 'series'])
1339 r.add(['.hgignore', 'series'])
1340 return 0
1340 return 0
1341
1341
1342 def clone(ui, source, dest=None, **opts):
1342 def clone(ui, source, dest=None, **opts):
1343 '''clone main and patch repository at same time
1343 '''clone main and patch repository at same time
1344
1344
1345 If source is local, destination will have no patches applied. If
1345 If source is local, destination will have no patches applied. If
1346 source is remote, this command can not check if patches are
1346 source is remote, this command can not check if patches are
1347 applied in source, so cannot guarantee that patches are not
1347 applied in source, so cannot guarantee that patches are not
1348 applied in destination. If you clone remote repository, be sure
1348 applied in destination. If you clone remote repository, be sure
1349 before that it has no patches applied.
1349 before that it has no patches applied.
1350
1350
1351 Source patch repository is looked for in <src>/.hg/patches by
1351 Source patch repository is looked for in <src>/.hg/patches by
1352 default. Use -p <url> to change.
1352 default. Use -p <url> to change.
1353 '''
1353 '''
1354 commands.setremoteconfig(ui, opts)
1354 commands.setremoteconfig(ui, opts)
1355 if dest is None:
1355 if dest is None:
1356 dest = hg.defaultdest(source)
1356 dest = hg.defaultdest(source)
1357 sr = hg.repository(ui, ui.expandpath(source))
1357 sr = hg.repository(ui, ui.expandpath(source))
1358 qbase, destrev = None, None
1358 qbase, destrev = None, None
1359 if sr.local():
1359 if sr.local():
1360 reposetup(ui, sr)
1360 reposetup(ui, sr)
1361 if sr.mq.applied:
1361 if sr.mq.applied:
1362 qbase = revlog.bin(sr.mq.applied[0].rev)
1362 qbase = revlog.bin(sr.mq.applied[0].rev)
1363 if not hg.islocal(dest):
1363 if not hg.islocal(dest):
1364 destrev = sr.parents(qbase)[0]
1364 destrev = sr.parents(qbase)[0]
1365 ui.note(_('cloning main repo\n'))
1365 ui.note(_('cloning main repo\n'))
1366 sr, dr = hg.clone(ui, sr, dest,
1366 sr, dr = hg.clone(ui, sr, dest,
1367 pull=opts['pull'],
1367 pull=opts['pull'],
1368 rev=destrev,
1368 rev=destrev,
1369 update=False,
1369 update=False,
1370 stream=opts['uncompressed'])
1370 stream=opts['uncompressed'])
1371 ui.note(_('cloning patch repo\n'))
1371 ui.note(_('cloning patch repo\n'))
1372 spr, dpr = hg.clone(ui, opts['patches'] or (sr.url() + '/.hg/patches'),
1372 spr, dpr = hg.clone(ui, opts['patches'] or (sr.url() + '/.hg/patches'),
1373 dr.url() + '/.hg/patches',
1373 dr.url() + '/.hg/patches',
1374 pull=opts['pull'],
1374 pull=opts['pull'],
1375 update=not opts['noupdate'],
1375 update=not opts['noupdate'],
1376 stream=opts['uncompressed'])
1376 stream=opts['uncompressed'])
1377 if dr.local():
1377 if dr.local():
1378 if qbase:
1378 if qbase:
1379 ui.note(_('stripping applied patches from destination repo\n'))
1379 ui.note(_('stripping applied patches from destination repo\n'))
1380 reposetup(ui, dr)
1380 reposetup(ui, dr)
1381 dr.mq.strip(dr, qbase, update=False, backup=None)
1381 dr.mq.strip(dr, qbase, update=False, backup=None)
1382 if not opts['noupdate']:
1382 if not opts['noupdate']:
1383 ui.note(_('updating destination repo\n'))
1383 ui.note(_('updating destination repo\n'))
1384 hg.update(dr, dr.changelog.tip())
1384 hg.update(dr, dr.changelog.tip())
1385
1385
1386 def commit(ui, repo, *pats, **opts):
1386 def commit(ui, repo, *pats, **opts):
1387 """commit changes in the queue repository"""
1387 """commit changes in the queue repository"""
1388 q = repo.mq
1388 q = repo.mq
1389 r = q.qrepo()
1389 r = q.qrepo()
1390 if not r: raise util.Abort('no queue repository')
1390 if not r: raise util.Abort('no queue repository')
1391 commands.commit(r.ui, r, *pats, **opts)
1391 commands.commit(r.ui, r, *pats, **opts)
1392
1392
1393 def series(ui, repo, **opts):
1393 def series(ui, repo, **opts):
1394 """print the entire series file"""
1394 """print the entire series file"""
1395 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1395 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1396 return 0
1396 return 0
1397
1397
1398 def top(ui, repo, **opts):
1398 def top(ui, repo, **opts):
1399 """print the name of the current patch"""
1399 """print the name of the current patch"""
1400 repo.mq.top(repo)
1400 repo.mq.top(repo)
1401 return 0
1401 return 0
1402
1402
1403 def next(ui, repo, **opts):
1403 def next(ui, repo, **opts):
1404 """print the name of the next patch"""
1404 """print the name of the next patch"""
1405 repo.mq.next(repo)
1405 repo.mq.next(repo)
1406 return 0
1406 return 0
1407
1407
1408 def prev(ui, repo, **opts):
1408 def prev(ui, repo, **opts):
1409 """print the name of the previous patch"""
1409 """print the name of the previous patch"""
1410 repo.mq.prev(repo)
1410 repo.mq.prev(repo)
1411 return 0
1411 return 0
1412
1412
1413 def new(ui, repo, patch, **opts):
1413 def new(ui, repo, patch, **opts):
1414 """create a new patch
1414 """create a new patch
1415
1415
1416 qnew creates a new patch on top of the currently-applied patch
1416 qnew creates a new patch on top of the currently-applied patch
1417 (if any). It will refuse to run if there are any outstanding
1417 (if any). It will refuse to run if there are any outstanding
1418 changes unless -f is specified, in which case the patch will
1418 changes unless -f is specified, in which case the patch will
1419 be initialised with them.
1419 be initialised with them.
1420
1420
1421 -m or -l set the patch header as well as the commit message.
1421 -m or -l set the patch header as well as the commit message.
1422 If neither is specified, the patch header is empty and the
1422 If neither is specified, the patch header is empty and the
1423 commit message is 'New patch: PATCH'"""
1423 commit message is 'New patch: PATCH'"""
1424 q = repo.mq
1424 q = repo.mq
1425 message = commands.logmessage(opts)
1425 message = commands.logmessage(opts)
1426 q.new(repo, patch, msg=message, force=opts['force'])
1426 q.new(repo, patch, msg=message, force=opts['force'])
1427 q.save_dirty()
1427 q.save_dirty()
1428 return 0
1428 return 0
1429
1429
1430 def refresh(ui, repo, **opts):
1430 def refresh(ui, repo, **opts):
1431 """update the current patch"""
1431 """update the current patch"""
1432 q = repo.mq
1432 q = repo.mq
1433 message = commands.logmessage(opts)
1433 message = commands.logmessage(opts)
1434 if opts['edit']:
1434 if opts['edit']:
1435 if message:
1435 if message:
1436 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1436 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1437 patch = q.applied[-1].name
1437 patch = q.applied[-1].name
1438 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1438 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1439 message = ui.edit('\n'.join(message), user or ui.username())
1439 message = ui.edit('\n'.join(message), user or ui.username())
1440 q.refresh(repo, msg=message, short=opts['short'])
1440 q.refresh(repo, msg=message, short=opts['short'])
1441 q.save_dirty()
1441 q.save_dirty()
1442 return 0
1442 return 0
1443
1443
1444 def diff(ui, repo, *files, **opts):
1444 def diff(ui, repo, *files, **opts):
1445 """diff of the current patch"""
1445 """diff of the current patch"""
1446 # deep in the dirstate code, the walkhelper method wants a list, not a tuple
1446 # deep in the dirstate code, the walkhelper method wants a list, not a tuple
1447 repo.mq.diff(repo, list(files))
1447 repo.mq.diff(repo, list(files))
1448 return 0
1448 return 0
1449
1449
1450 def fold(ui, repo, *files, **opts):
1450 def fold(ui, repo, *files, **opts):
1451 """fold the named patches into the current patch
1451 """fold the named patches into the current patch
1452
1452
1453 Patches must not yet be applied. Each patch will be successively
1453 Patches must not yet be applied. Each patch will be successively
1454 applied to the current patch in the order given. If all the
1454 applied to the current patch in the order given. If all the
1455 patches apply successfully, the current patch will be refreshed
1455 patches apply successfully, the current patch will be refreshed
1456 with the new cumulative patch, and the folded patches will
1456 with the new cumulative patch, and the folded patches will
1457 be deleted. With -f/--force, the folded patch files will
1457 be deleted. With -f/--force, the folded patch files will
1458 be removed afterwards.
1458 be removed afterwards.
1459
1459
1460 The header for each folded patch will be concatenated with
1460 The header for each folded patch will be concatenated with
1461 the current patch header, separated by a line of '* * *'."""
1461 the current patch header, separated by a line of '* * *'."""
1462
1462
1463 q = repo.mq
1463 q = repo.mq
1464
1464
1465 if not files:
1465 if not files:
1466 raise util.Abort(_('qfold requires at least one patch name'))
1466 raise util.Abort(_('qfold requires at least one patch name'))
1467 if not q.check_toppatch(repo):
1467 if not q.check_toppatch(repo):
1468 raise util.Abort(_('No patches applied\n'))
1468 raise util.Abort(_('No patches applied\n'))
1469
1469
1470 message = commands.logmessage(opts)
1470 message = commands.logmessage(opts)
1471 if opts['edit']:
1471 if opts['edit']:
1472 if message:
1472 if message:
1473 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1473 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1474
1474
1475 parent = q.lookup('qtip')
1475 parent = q.lookup('qtip')
1476 patches = []
1476 patches = []
1477 messages = []
1477 messages = []
1478 for f in files:
1478 for f in files:
1479 patch = q.lookup(f)
1479 patch = q.lookup(f)
1480 if patch in patches or patch == parent:
1480 if patch in patches or patch == parent:
1481 ui.warn(_('Skipping already folded patch %s') % patch)
1481 ui.warn(_('Skipping already folded patch %s') % patch)
1482 if q.isapplied(patch):
1482 if q.isapplied(patch):
1483 raise util.Abort(_('qfold cannot fold already applied patch %s') % patch)
1483 raise util.Abort(_('qfold cannot fold already applied patch %s') % patch)
1484 patches.append(patch)
1484 patches.append(patch)
1485
1485
1486 for patch in patches:
1486 for patch in patches:
1487 if not message:
1487 if not message:
1488 messages.append(q.readheaders(patch)[0])
1488 messages.append(q.readheaders(patch)[0])
1489 pf = q.join(patch)
1489 pf = q.join(patch)
1490 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1490 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1491 if not patchsuccess:
1491 if not patchsuccess:
1492 raise util.Abort(_('Error folding patch %s') % patch)
1492 raise util.Abort(_('Error folding patch %s') % patch)
1493
1493
1494 if not message:
1494 if not message:
1495 message, comments, user = q.readheaders(parent)[0:3]
1495 message, comments, user = q.readheaders(parent)[0:3]
1496 for msg in messages:
1496 for msg in messages:
1497 message.append('* * *')
1497 message.append('* * *')
1498 message.extend(msg)
1498 message.extend(msg)
1499 message = '\n'.join(message)
1499 message = '\n'.join(message)
1500
1500
1501 if opts['edit']:
1501 if opts['edit']:
1502 message = ui.edit(message, user or ui.username())
1502 message = ui.edit(message, user or ui.username())
1503
1503
1504 q.refresh(repo, msg=message)
1504 q.refresh(repo, msg=message)
1505
1505
1506 for patch in patches:
1506 for patch in patches:
1507 q.delete(repo, patch, force=opts['force'])
1507 q.delete(repo, patch, force=opts['force'])
1508
1508
1509 q.save_dirty()
1509 q.save_dirty()
1510
1510
1511 def guard(ui, repo, *args, **opts):
1511 def guard(ui, repo, *args, **opts):
1512 '''set or print guards for a patch
1512 '''set or print guards for a patch
1513
1513
1514 guards control whether a patch can be pushed. a patch with no
1514 guards control whether a patch can be pushed. a patch with no
1515 guards is aways pushed. a patch with posative guard ("+foo") is
1515 guards is aways pushed. a patch with posative guard ("+foo") is
1516 pushed only if qselect command enables guard "foo". a patch with
1516 pushed only if qselect command enables guard "foo". a patch with
1517 nagative guard ("-foo") is never pushed if qselect command enables
1517 nagative guard ("-foo") is never pushed if qselect command enables
1518 guard "foo".
1518 guard "foo".
1519
1519
1520 with no arguments, default is to print current active guards.
1520 with no arguments, default is to print current active guards.
1521 with arguments, set active guards for patch.
1521 with arguments, set active guards for patch.
1522
1522
1523 to set nagative guard "-foo" on topmost patch ("--" is needed so
1523 to set nagative guard "-foo" on topmost patch ("--" is needed so
1524 hg will not interpret "-foo" as argument):
1524 hg will not interpret "-foo" as argument):
1525 hg qguard -- -foo
1525 hg qguard -- -foo
1526
1526
1527 to set guards on other patch:
1527 to set guards on other patch:
1528 hg qguard other.patch +2.6.17 -stable
1528 hg qguard other.patch +2.6.17 -stable
1529 '''
1529 '''
1530 def status(idx):
1530 def status(idx):
1531 guards = q.series_guards[idx] or ['unguarded']
1531 guards = q.series_guards[idx] or ['unguarded']
1532 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1532 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1533 q = repo.mq
1533 q = repo.mq
1534 patch = None
1534 patch = None
1535 args = list(args)
1535 args = list(args)
1536 if opts['list']:
1536 if opts['list']:
1537 if args or opts['none']:
1537 if args or opts['none']:
1538 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1538 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1539 for i in xrange(len(q.series)):
1539 for i in xrange(len(q.series)):
1540 status(i)
1540 status(i)
1541 return
1541 return
1542 if not args or args[0][0:1] in '-+':
1542 if not args or args[0][0:1] in '-+':
1543 if not q.applied:
1543 if not q.applied:
1544 raise util.Abort(_('no patches applied'))
1544 raise util.Abort(_('no patches applied'))
1545 patch = q.applied[-1].name
1545 patch = q.applied[-1].name
1546 if patch is None and args[0][0:1] not in '-+':
1546 if patch is None and args[0][0:1] not in '-+':
1547 patch = args.pop(0)
1547 patch = args.pop(0)
1548 if patch is None:
1548 if patch is None:
1549 raise util.Abort(_('no patch to work with'))
1549 raise util.Abort(_('no patch to work with'))
1550 if args or opts['none']:
1550 if args or opts['none']:
1551 q.set_guards(q.find_series(patch), args)
1551 q.set_guards(q.find_series(patch), args)
1552 q.save_dirty()
1552 q.save_dirty()
1553 else:
1553 else:
1554 status(q.series.index(q.lookup(patch)))
1554 status(q.series.index(q.lookup(patch)))
1555
1555
1556 def header(ui, repo, patch=None):
1556 def header(ui, repo, patch=None):
1557 """Print the header of the topmost or specified patch"""
1557 """Print the header of the topmost or specified patch"""
1558 q = repo.mq
1558 q = repo.mq
1559
1559
1560 if patch:
1560 if patch:
1561 patch = q.lookup(patch)
1561 patch = q.lookup(patch)
1562 else:
1562 else:
1563 if not q.applied:
1563 if not q.applied:
1564 ui.write('No patches applied\n')
1564 ui.write('No patches applied\n')
1565 return
1565 return
1566 patch = q.lookup('qtip')
1566 patch = q.lookup('qtip')
1567 message = repo.mq.readheaders(patch)[0]
1567 message = repo.mq.readheaders(patch)[0]
1568
1568
1569 ui.write('\n'.join(message) + '\n')
1569 ui.write('\n'.join(message) + '\n')
1570
1570
1571 def lastsavename(path):
1571 def lastsavename(path):
1572 (directory, base) = os.path.split(path)
1572 (directory, base) = os.path.split(path)
1573 names = os.listdir(directory)
1573 names = os.listdir(directory)
1574 namere = re.compile("%s.([0-9]+)" % base)
1574 namere = re.compile("%s.([0-9]+)" % base)
1575 maxindex = None
1575 maxindex = None
1576 maxname = None
1576 maxname = None
1577 for f in names:
1577 for f in names:
1578 m = namere.match(f)
1578 m = namere.match(f)
1579 if m:
1579 if m:
1580 index = int(m.group(1))
1580 index = int(m.group(1))
1581 if maxindex == None or index > maxindex:
1581 if maxindex == None or index > maxindex:
1582 maxindex = index
1582 maxindex = index
1583 maxname = f
1583 maxname = f
1584 if maxname:
1584 if maxname:
1585 return (os.path.join(directory, maxname), maxindex)
1585 return (os.path.join(directory, maxname), maxindex)
1586 return (None, None)
1586 return (None, None)
1587
1587
1588 def savename(path):
1588 def savename(path):
1589 (last, index) = lastsavename(path)
1589 (last, index) = lastsavename(path)
1590 if last is None:
1590 if last is None:
1591 index = 0
1591 index = 0
1592 newpath = path + ".%d" % (index + 1)
1592 newpath = path + ".%d" % (index + 1)
1593 return newpath
1593 return newpath
1594
1594
1595 def push(ui, repo, patch=None, **opts):
1595 def push(ui, repo, patch=None, **opts):
1596 """push the next patch onto the stack"""
1596 """push the next patch onto the stack"""
1597 q = repo.mq
1597 q = repo.mq
1598 mergeq = None
1598 mergeq = None
1599
1599
1600 if opts['all']:
1600 if opts['all']:
1601 patch = q.series[-1]
1601 patch = q.series[-1]
1602 if opts['merge']:
1602 if opts['merge']:
1603 if opts['name']:
1603 if opts['name']:
1604 newpath = opts['name']
1604 newpath = opts['name']
1605 else:
1605 else:
1606 newpath, i = lastsavename(q.path)
1606 newpath, i = lastsavename(q.path)
1607 if not newpath:
1607 if not newpath:
1608 ui.warn("no saved queues found, please use -n\n")
1608 ui.warn("no saved queues found, please use -n\n")
1609 return 1
1609 return 1
1610 mergeq = queue(ui, repo.join(""), newpath)
1610 mergeq = queue(ui, repo.join(""), newpath)
1611 ui.warn("merging with queue at: %s\n" % mergeq.path)
1611 ui.warn("merging with queue at: %s\n" % mergeq.path)
1612 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1612 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1613 mergeq=mergeq)
1613 mergeq=mergeq)
1614 q.save_dirty()
1614 q.save_dirty()
1615 return ret
1615 return ret
1616
1616
1617 def pop(ui, repo, patch=None, **opts):
1617 def pop(ui, repo, patch=None, **opts):
1618 """pop the current patch off the stack"""
1618 """pop the current patch off the stack"""
1619 localupdate = True
1619 localupdate = True
1620 if opts['name']:
1620 if opts['name']:
1621 q = queue(ui, repo.join(""), repo.join(opts['name']))
1621 q = queue(ui, repo.join(""), repo.join(opts['name']))
1622 ui.warn('using patch queue: %s\n' % q.path)
1622 ui.warn('using patch queue: %s\n' % q.path)
1623 localupdate = False
1623 localupdate = False
1624 else:
1624 else:
1625 q = repo.mq
1625 q = repo.mq
1626 q.pop(repo, patch, force=opts['force'], update=localupdate, all=opts['all'])
1626 q.pop(repo, patch, force=opts['force'], update=localupdate, all=opts['all'])
1627 q.save_dirty()
1627 q.save_dirty()
1628 return 0
1628 return 0
1629
1629
1630 def rename(ui, repo, patch, name=None, **opts):
1630 def rename(ui, repo, patch, name=None, **opts):
1631 """rename a patch
1631 """rename a patch
1632
1632
1633 With one argument, renames the current patch to PATCH1.
1633 With one argument, renames the current patch to PATCH1.
1634 With two arguments, renames PATCH1 to PATCH2."""
1634 With two arguments, renames PATCH1 to PATCH2."""
1635
1635
1636 q = repo.mq
1636 q = repo.mq
1637
1637
1638 if not name:
1638 if not name:
1639 name = patch
1639 name = patch
1640 patch = None
1640 patch = None
1641
1641
1642 if name in q.series:
1642 if name in q.series:
1643 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1643 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1644
1644
1645 absdest = q.join(name)
1645 absdest = q.join(name)
1646 if os.path.exists(absdest):
1646 if os.path.exists(absdest):
1647 raise util.Abort(_('%s already exists') % absdest)
1647 raise util.Abort(_('%s already exists') % absdest)
1648
1648
1649 if patch:
1649 if patch:
1650 patch = q.lookup(patch)
1650 patch = q.lookup(patch)
1651 else:
1651 else:
1652 if not q.applied:
1652 if not q.applied:
1653 ui.write(_('No patches applied\n'))
1653 ui.write(_('No patches applied\n'))
1654 return
1654 return
1655 patch = q.lookup('qtip')
1655 patch = q.lookup('qtip')
1656
1656
1657 if ui.verbose:
1657 if ui.verbose:
1658 ui.write('Renaming %s to %s\n' % (patch, name))
1658 ui.write('Renaming %s to %s\n' % (patch, name))
1659 i = q.find_series(patch)
1659 i = q.find_series(patch)
1660 q.full_series[i] = name
1660 q.full_series[i] = name
1661 q.parse_series()
1661 q.parse_series()
1662 q.series_dirty = 1
1662 q.series_dirty = 1
1663
1663
1664 info = q.isapplied(patch)
1664 info = q.isapplied(patch)
1665 if info:
1665 if info:
1666 q.applied[info[0]] = statusentry(info[1], name)
1666 q.applied[info[0]] = statusentry(info[1], name)
1667 q.applied_dirty = 1
1667 q.applied_dirty = 1
1668
1668
1669 util.rename(q.join(patch), absdest)
1669 util.rename(q.join(patch), absdest)
1670 r = q.qrepo()
1670 r = q.qrepo()
1671 if r:
1671 if r:
1672 wlock = r.wlock()
1672 wlock = r.wlock()
1673 if r.dirstate.state(name) == 'r':
1673 if r.dirstate.state(name) == 'r':
1674 r.undelete([name], wlock)
1674 r.undelete([name], wlock)
1675 r.copy(patch, name, wlock)
1675 r.copy(patch, name, wlock)
1676 r.remove([patch], False, wlock)
1676 r.remove([patch], False, wlock)
1677
1677
1678 q.save_dirty()
1678 q.save_dirty()
1679
1679
1680 def restore(ui, repo, rev, **opts):
1680 def restore(ui, repo, rev, **opts):
1681 """restore the queue state saved by a rev"""
1681 """restore the queue state saved by a rev"""
1682 rev = repo.lookup(rev)
1682 rev = repo.lookup(rev)
1683 q = repo.mq
1683 q = repo.mq
1684 q.restore(repo, rev, delete=opts['delete'],
1684 q.restore(repo, rev, delete=opts['delete'],
1685 qupdate=opts['update'])
1685 qupdate=opts['update'])
1686 q.save_dirty()
1686 q.save_dirty()
1687 return 0
1687 return 0
1688
1688
1689 def save(ui, repo, **opts):
1689 def save(ui, repo, **opts):
1690 """save current queue state"""
1690 """save current queue state"""
1691 q = repo.mq
1691 q = repo.mq
1692 message = commands.logmessage(opts)
1692 message = commands.logmessage(opts)
1693 ret = q.save(repo, msg=message)
1693 ret = q.save(repo, msg=message)
1694 if ret:
1694 if ret:
1695 return ret
1695 return ret
1696 q.save_dirty()
1696 q.save_dirty()
1697 if opts['copy']:
1697 if opts['copy']:
1698 path = q.path
1698 path = q.path
1699 if opts['name']:
1699 if opts['name']:
1700 newpath = os.path.join(q.basepath, opts['name'])
1700 newpath = os.path.join(q.basepath, opts['name'])
1701 if os.path.exists(newpath):
1701 if os.path.exists(newpath):
1702 if not os.path.isdir(newpath):
1702 if not os.path.isdir(newpath):
1703 raise util.Abort(_('destination %s exists and is not '
1703 raise util.Abort(_('destination %s exists and is not '
1704 'a directory') % newpath)
1704 'a directory') % newpath)
1705 if not opts['force']:
1705 if not opts['force']:
1706 raise util.Abort(_('destination %s exists, '
1706 raise util.Abort(_('destination %s exists, '
1707 'use -f to force') % newpath)
1707 'use -f to force') % newpath)
1708 else:
1708 else:
1709 newpath = savename(path)
1709 newpath = savename(path)
1710 ui.warn("copy %s to %s\n" % (path, newpath))
1710 ui.warn("copy %s to %s\n" % (path, newpath))
1711 util.copyfiles(path, newpath)
1711 util.copyfiles(path, newpath)
1712 if opts['empty']:
1712 if opts['empty']:
1713 try:
1713 try:
1714 os.unlink(q.join(q.status_path))
1714 os.unlink(q.join(q.status_path))
1715 except:
1715 except:
1716 pass
1716 pass
1717 return 0
1717 return 0
1718
1718
1719 def strip(ui, repo, rev, **opts):
1719 def strip(ui, repo, rev, **opts):
1720 """strip a revision and all later revs on the same branch"""
1720 """strip a revision and all later revs on the same branch"""
1721 rev = repo.lookup(rev)
1721 rev = repo.lookup(rev)
1722 backup = 'all'
1722 backup = 'all'
1723 if opts['backup']:
1723 if opts['backup']:
1724 backup = 'strip'
1724 backup = 'strip'
1725 elif opts['nobackup']:
1725 elif opts['nobackup']:
1726 backup = 'none'
1726 backup = 'none'
1727 repo.mq.strip(repo, rev, backup=backup)
1727 repo.mq.strip(repo, rev, backup=backup)
1728 return 0
1728 return 0
1729
1729
1730 def select(ui, repo, *args, **opts):
1730 def select(ui, repo, *args, **opts):
1731 '''set or print guarded patches to push
1731 '''set or print guarded patches to push
1732
1732
1733 use qguard command to set or print guards on patch. then use
1733 use qguard command to set or print guards on patch. then use
1734 qselect to tell mq which guards to use. example:
1734 qselect to tell mq which guards to use. example:
1735
1735
1736 qguard foo.patch -stable (nagative guard)
1736 qguard foo.patch -stable (nagative guard)
1737 qguard bar.patch +stable (posative guard)
1737 qguard bar.patch +stable (posative guard)
1738 qselect stable
1738 qselect stable
1739
1739
1740 this sets "stable" guard. mq will skip foo.patch (because it has
1740 this sets "stable" guard. mq will skip foo.patch (because it has
1741 nagative match) but push bar.patch (because it has posative
1741 nagative match) but push bar.patch (because it has posative
1742 match). patch is pushed only if all posative guards match and no
1742 match). patch is pushed only if all posative guards match and no
1743 nagative guards match.
1743 nagative guards match.
1744
1744
1745 with no arguments, default is to print current active guards.
1745 with no arguments, default is to print current active guards.
1746 with arguments, set active guards as given.
1746 with arguments, set active guards as given.
1747
1747
1748 use -n/--none to deactivate guards (no other arguments needed).
1748 use -n/--none to deactivate guards (no other arguments needed).
1749 when no guards active, patches with posative guards are skipped,
1749 when no guards active, patches with posative guards are skipped,
1750 patches with nagative guards are pushed.
1750 patches with nagative guards are pushed.
1751
1751
1752 use -s/--series to print list of all guards in series file (no
1752 use -s/--series to print list of all guards in series file (no
1753 other arguments needed). use -v for more information.'''
1753 other arguments needed). use -v for more information.'''
1754
1754
1755 q = repo.mq
1755 q = repo.mq
1756 guards = q.active()
1756 guards = q.active()
1757 if args or opts['none']:
1757 if args or opts['none']:
1758 q.set_active(args)
1758 q.set_active(args)
1759 q.save_dirty()
1759 q.save_dirty()
1760 if not args:
1760 if not args:
1761 ui.status(_('guards deactivated\n'))
1761 ui.status(_('guards deactivated\n'))
1762 if q.series:
1762 if q.series:
1763 ui.status(_('%d of %d unapplied patches active\n') %
1763 ui.status(_('%d of %d unapplied patches active\n') %
1764 (len(q.unapplied(repo)), len(q.series)))
1764 (len(q.unapplied(repo)), len(q.series)))
1765 elif opts['series']:
1765 elif opts['series']:
1766 guards = {}
1766 guards = {}
1767 noguards = 0
1767 noguards = 0
1768 for gs in q.series_guards:
1768 for gs in q.series_guards:
1769 if not gs:
1769 if not gs:
1770 noguards += 1
1770 noguards += 1
1771 for g in gs:
1771 for g in gs:
1772 guards.setdefault(g, 0)
1772 guards.setdefault(g, 0)
1773 guards[g] += 1
1773 guards[g] += 1
1774 if ui.verbose:
1774 if ui.verbose:
1775 guards['NONE'] = noguards
1775 guards['NONE'] = noguards
1776 guards = guards.items()
1776 guards = guards.items()
1777 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
1777 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
1778 if guards:
1778 if guards:
1779 ui.note(_('guards in series file:\n'))
1779 ui.note(_('guards in series file:\n'))
1780 for guard, count in guards:
1780 for guard, count in guards:
1781 ui.note('%2d ' % count)
1781 ui.note('%2d ' % count)
1782 ui.write(guard, '\n')
1782 ui.write(guard, '\n')
1783 else:
1783 else:
1784 ui.note(_('no guards in series file\n'))
1784 ui.note(_('no guards in series file\n'))
1785 else:
1785 else:
1786 if guards:
1786 if guards:
1787 ui.note(_('active guards:\n'))
1787 ui.note(_('active guards:\n'))
1788 for g in guards:
1788 for g in guards:
1789 ui.write(g, '\n')
1789 ui.write(g, '\n')
1790 else:
1790 else:
1791 ui.write(_('no active guards\n'))
1791 ui.write(_('no active guards\n'))
1792
1792
1793 def reposetup(ui, repo):
1793 def reposetup(ui, repo):
1794 class mqrepo(repo.__class__):
1794 class mqrepo(repo.__class__):
1795 def tags(self):
1795 def tags(self):
1796 if self.tagscache:
1796 if self.tagscache:
1797 return self.tagscache
1797 return self.tagscache
1798
1798
1799 tagscache = super(mqrepo, self).tags()
1799 tagscache = super(mqrepo, self).tags()
1800
1800
1801 q = self.mq
1801 q = self.mq
1802 if not q.applied:
1802 if not q.applied:
1803 return tagscache
1803 return tagscache
1804
1804
1805 mqtags = [(patch.rev, patch.name) for patch in q.applied]
1805 mqtags = [(patch.rev, patch.name) for patch in q.applied]
1806 mqtags.append((mqtags[-1][0], 'qtip'))
1806 mqtags.append((mqtags[-1][0], 'qtip'))
1807 mqtags.append((mqtags[0][0], 'qbase'))
1807 mqtags.append((mqtags[0][0], 'qbase'))
1808 for patch in mqtags:
1808 for patch in mqtags:
1809 if patch[1] in tagscache:
1809 if patch[1] in tagscache:
1810 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
1810 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
1811 else:
1811 else:
1812 tagscache[patch[1]] = revlog.bin(patch[0])
1812 tagscache[patch[1]] = revlog.bin(patch[0])
1813
1813
1814 return tagscache
1814 return tagscache
1815
1815
1816 repo.__class__ = mqrepo
1816 repo.__class__ = mqrepo
1817 repo.mq = queue(ui, repo.join(""))
1817 repo.mq = queue(ui, repo.join(""))
1818
1818
1819 cmdtable = {
1819 cmdtable = {
1820 "qapplied": (applied, [], 'hg qapplied [PATCH]'),
1820 "qapplied": (applied, [], 'hg qapplied [PATCH]'),
1821 "qclone": (clone,
1821 "qclone": (clone,
1822 [('', 'pull', None, _('use pull protocol to copy metadata')),
1822 [('', 'pull', None, _('use pull protocol to copy metadata')),
1823 ('U', 'noupdate', None, _('do not update the new working directories')),
1823 ('U', 'noupdate', None, _('do not update the new working directories')),
1824 ('', 'uncompressed', None,
1824 ('', 'uncompressed', None,
1825 _('use uncompressed transfer (fast over LAN)')),
1825 _('use uncompressed transfer (fast over LAN)')),
1826 ('e', 'ssh', '', _('specify ssh command to use')),
1826 ('e', 'ssh', '', _('specify ssh command to use')),
1827 ('p', 'patches', '', _('location of source patch repo')),
1827 ('p', 'patches', '', _('location of source patch repo')),
1828 ('', 'remotecmd', '',
1828 ('', 'remotecmd', '',
1829 _('specify hg command to run on the remote side'))],
1829 _('specify hg command to run on the remote side'))],
1830 'hg qclone [OPTION]... SOURCE [DEST]'),
1830 'hg qclone [OPTION]... SOURCE [DEST]'),
1831 "qcommit|qci":
1831 "qcommit|qci":
1832 (commit,
1832 (commit,
1833 commands.table["^commit|ci"][1],
1833 commands.table["^commit|ci"][1],
1834 'hg qcommit [OPTION]... [FILE]...'),
1834 'hg qcommit [OPTION]... [FILE]...'),
1835 "^qdiff": (diff, [], 'hg qdiff [FILE]...'),
1835 "^qdiff": (diff, [], 'hg qdiff [FILE]...'),
1836 "qdelete":
1836 "qdelete":
1837 (delete,
1837 (delete,
1838 [('f', 'force', None, _('delete patch file'))],
1838 [('f', 'force', None, _('delete patch file'))],
1839 'hg qdelete [-f] PATCH'),
1839 'hg qdelete [-f] PATCH'),
1840 'qfold':
1840 'qfold':
1841 (fold,
1841 (fold,
1842 [('e', 'edit', None, _('edit patch header')),
1842 [('e', 'edit', None, _('edit patch header')),
1843 ('f', 'force', None, _('delete folded patch files')),
1843 ('f', 'force', None, _('delete folded patch files')),
1844 ('m', 'message', '', _('set patch header to <text>')),
1844 ('m', 'message', '', _('set patch header to <text>')),
1845 ('l', 'logfile', '', _('set patch header to contents of <file>'))],
1845 ('l', 'logfile', '', _('set patch header to contents of <file>'))],
1846 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
1846 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
1847 'qguard': (guard, [('l', 'list', None, _('list all patches and guards')),
1847 'qguard': (guard, [('l', 'list', None, _('list all patches and guards')),
1848 ('n', 'none', None, _('drop all guards'))],
1848 ('n', 'none', None, _('drop all guards'))],
1849 'hg qguard [PATCH] [+GUARD...] [-GUARD...]'),
1849 'hg qguard [PATCH] [+GUARD...] [-GUARD...]'),
1850 'qheader': (header, [],
1850 'qheader': (header, [],
1851 _('hg qheader [PATCH]')),
1851 _('hg qheader [PATCH]')),
1852 "^qimport":
1852 "^qimport":
1853 (qimport,
1853 (qimport,
1854 [('e', 'existing', None, 'import file in patch dir'),
1854 [('e', 'existing', None, 'import file in patch dir'),
1855 ('n', 'name', '', 'patch file name'),
1855 ('n', 'name', '', 'patch file name'),
1856 ('f', 'force', None, 'overwrite existing files')],
1856 ('f', 'force', None, 'overwrite existing files')],
1857 'hg qimport [-e] [-n NAME] [-f] FILE...'),
1857 'hg qimport [-e] [-n NAME] [-f] FILE...'),
1858 "^qinit":
1858 "^qinit":
1859 (init,
1859 (init,
1860 [('c', 'create-repo', None, 'create queue repository')],
1860 [('c', 'create-repo', None, 'create queue repository')],
1861 'hg qinit [-c]'),
1861 'hg qinit [-c]'),
1862 "qnew":
1862 "qnew":
1863 (new,
1863 (new,
1864 [('m', 'message', '', _('use <text> as commit message')),
1864 [('m', 'message', '', _('use <text> as commit message')),
1865 ('l', 'logfile', '', _('read the commit message from <file>')),
1865 ('l', 'logfile', '', _('read the commit message from <file>')),
1866 ('f', 'force', None, _('import uncommitted changes into patch'))],
1866 ('f', 'force', None, _('import uncommitted changes into patch'))],
1867 'hg qnew [-m TEXT] [-l FILE] [-f] PATCH'),
1867 'hg qnew [-m TEXT] [-l FILE] [-f] PATCH'),
1868 "qnext": (next, [], 'hg qnext'),
1868 "qnext": (next, [], 'hg qnext'),
1869 "qprev": (prev, [], 'hg qprev'),
1869 "qprev": (prev, [], 'hg qprev'),
1870 "^qpop":
1870 "^qpop":
1871 (pop,
1871 (pop,
1872 [('a', 'all', None, 'pop all patches'),
1872 [('a', 'all', None, 'pop all patches'),
1873 ('n', 'name', '', 'queue name to pop'),
1873 ('n', 'name', '', 'queue name to pop'),
1874 ('f', 'force', None, 'forget any local changes')],
1874 ('f', 'force', None, 'forget any local changes')],
1875 'hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]'),
1875 'hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]'),
1876 "^qpush":
1876 "^qpush":
1877 (push,
1877 (push,
1878 [('f', 'force', None, 'apply if the patch has rejects'),
1878 [('f', 'force', None, 'apply if the patch has rejects'),
1879 ('l', 'list', None, 'list patch name in commit text'),
1879 ('l', 'list', None, 'list patch name in commit text'),
1880 ('a', 'all', None, 'apply all patches'),
1880 ('a', 'all', None, 'apply all patches'),
1881 ('m', 'merge', None, 'merge from another queue'),
1881 ('m', 'merge', None, 'merge from another queue'),
1882 ('n', 'name', '', 'merge queue name')],
1882 ('n', 'name', '', 'merge queue name')],
1883 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'),
1883 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'),
1884 "^qrefresh":
1884 "^qrefresh":
1885 (refresh,
1885 (refresh,
1886 [('e', 'edit', None, _('edit commit message')),
1886 [('e', 'edit', None, _('edit commit message')),
1887 ('m', 'message', '', _('change commit message with <text>')),
1887 ('m', 'message', '', _('change commit message with <text>')),
1888 ('l', 'logfile', '', _('change commit message with <file> content')),
1888 ('l', 'logfile', '', _('change commit message with <file> content')),
1889 ('s', 'short', None, 'short refresh')],
1889 ('s', 'short', None, 'short refresh')],
1890 'hg qrefresh [-e] [-m TEXT] [-l FILE] [-s]'),
1890 'hg qrefresh [-e] [-m TEXT] [-l FILE] [-s]'),
1891 'qrename|qmv':
1891 'qrename|qmv':
1892 (rename, [], 'hg qrename PATCH1 [PATCH2]'),
1892 (rename, [], 'hg qrename PATCH1 [PATCH2]'),
1893 "qrestore":
1893 "qrestore":
1894 (restore,
1894 (restore,
1895 [('d', 'delete', None, 'delete save entry'),
1895 [('d', 'delete', None, 'delete save entry'),
1896 ('u', 'update', None, 'update queue working dir')],
1896 ('u', 'update', None, 'update queue working dir')],
1897 'hg qrestore [-d] [-u] REV'),
1897 'hg qrestore [-d] [-u] REV'),
1898 "qsave":
1898 "qsave":
1899 (save,
1899 (save,
1900 [('m', 'message', '', _('use <text> as commit message')),
1900 [('m', 'message', '', _('use <text> as commit message')),
1901 ('l', 'logfile', '', _('read the commit message from <file>')),
1901 ('l', 'logfile', '', _('read the commit message from <file>')),
1902 ('c', 'copy', None, 'copy patch directory'),
1902 ('c', 'copy', None, 'copy patch directory'),
1903 ('n', 'name', '', 'copy directory name'),
1903 ('n', 'name', '', 'copy directory name'),
1904 ('e', 'empty', None, 'clear queue status file'),
1904 ('e', 'empty', None, 'clear queue status file'),
1905 ('f', 'force', None, 'force copy')],
1905 ('f', 'force', None, 'force copy')],
1906 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
1906 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
1907 "qselect": (select,
1907 "qselect": (select,
1908 [('n', 'none', None, _('disable all guards')),
1908 [('n', 'none', None, _('disable all guards')),
1909 ('s', 'series', None, _('list all guards in series file'))],
1909 ('s', 'series', None, _('list all guards in series file'))],
1910 'hg qselect [GUARDS]'),
1910 'hg qselect [GUARDS]'),
1911 "qseries":
1911 "qseries":
1912 (series,
1912 (series,
1913 [('m', 'missing', None, 'print patches not in series'),
1913 [('m', 'missing', None, 'print patches not in series'),
1914 ('s', 'summary', None, _('print first line of patch header'))],
1914 ('s', 'summary', None, _('print first line of patch header'))],
1915 'hg qseries [-m]'),
1915 'hg qseries [-m]'),
1916 "^strip":
1916 "^strip":
1917 (strip,
1917 (strip,
1918 [('f', 'force', None, 'force multi-head removal'),
1918 [('f', 'force', None, 'force multi-head removal'),
1919 ('b', 'backup', None, 'bundle unrelated changesets'),
1919 ('b', 'backup', None, 'bundle unrelated changesets'),
1920 ('n', 'nobackup', None, 'no backups')],
1920 ('n', 'nobackup', None, 'no backups')],
1921 'hg strip [-f] [-b] [-n] REV'),
1921 'hg strip [-f] [-b] [-n] REV'),
1922 "qtop": (top, [], 'hg qtop'),
1922 "qtop": (top, [], 'hg qtop'),
1923 "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
1923 "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
1924 }
1924 }
1925
1925
General Comments 0
You need to be logged in to leave comments. Login now