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