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