##// END OF EJS Templates
allow qrefresh to take a list of files; closes #96.
Brendan Cully -
r2938:5b7a118f default
parent child Browse files
Show More
@@ -1,1983 +1,1994 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, msg='', short=False):
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 = 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 tip = repo.changelog.tip()
943 tip = repo.changelog.tip()
943 if top == tip:
944 if top == tip:
944 # 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
945 # optimization here. We update the dirstate in place and strip
946 # optimization here. We update the dirstate in place and strip
946 # off the tip commit. Then just commit the current directory
947 # off the tip commit. Then just commit the current directory
947 # tree. We can also send repo.commit the list of files
948 # tree. We can also send repo.commit the list of files
948 # changed to speed up the diff
949 # changed to speed up the diff
949 #
950 #
950 # in short mode, we only diff the files included in the
951 # in short mode, we only diff the files included in the
951 # patch already
952 # patch already
952 #
953 #
953 # this should really read:
954 # this should really read:
954 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
955 # mm, dd, aa, aa2, uu = repo.status(tip, patchparent)[:5]
955 # but we do it backwards to take advantage of manifest/chlog
956 # but we do it backwards to take advantage of manifest/chlog
956 # caching against the next repo.status call
957 # caching against the next repo.status call
957 #
958 #
958 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
959 mm, aa, dd, aa2, uu = repo.status(patchparent, tip)[:5]
959 if short:
960 if opts.get('short'):
960 filelist = mm + aa + dd
961 filelist = mm + aa + dd
961 else:
962 else:
962 filelist = None
963 filelist = None
963 m, a, r, d, u = repo.status(files=filelist)[:5]
964 m, a, r, d, u = repo.status(files=filelist)[:5]
964
965
965 # 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
966 # the dirstate parent, but then changed in the local dirstate.
967 # the dirstate parent, but then changed in the local dirstate.
967 # 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
968 for x in m:
969 for x in m:
969 if x not in aa:
970 if x not in aa:
970 mm.append(x)
971 mm.append(x)
971 # 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
972 # were deleted by the patch. In this case, they should only
973 # were deleted by the patch. In this case, they should only
973 # show up in the changed section.
974 # show up in the changed section.
974 for x in a:
975 for x in a:
975 if x in dd:
976 if x in dd:
976 del dd[dd.index(x)]
977 del dd[dd.index(x)]
977 mm.append(x)
978 mm.append(x)
978 else:
979 else:
979 aa.append(x)
980 aa.append(x)
980 # make sure any files deleted in the local dirstate
981 # make sure any files deleted in the local dirstate
981 # are not in the add or change column of the patch
982 # are not in the add or change column of the patch
982 forget = []
983 forget = []
983 for x in d + r:
984 for x in d + r:
984 if x in aa:
985 if x in aa:
985 del aa[aa.index(x)]
986 del aa[aa.index(x)]
986 forget.append(x)
987 forget.append(x)
987 continue
988 continue
988 elif x in mm:
989 elif x in mm:
989 del mm[mm.index(x)]
990 del mm[mm.index(x)]
990 dd.append(x)
991 dd.append(x)
991
992
992 m = list(util.unique(mm))
993 m = list(util.unique(mm))
993 r = list(util.unique(dd))
994 r = list(util.unique(dd))
994 a = list(util.unique(aa))
995 a = list(util.unique(aa))
995 filelist = list(util.unique(m + r + a))
996 filelist = filter(matchfn, util.unique(m + r + a))
996 self.printdiff(repo, patchparent, files=filelist,
997 self.printdiff(repo, patchparent, files=filelist,
997 changes=(m, a, r, [], u), fp=patchf)
998 changes=(m, a, r, [], u), fp=patchf)
998 patchf.close()
999 patchf.close()
999
1000
1000 changes = repo.changelog.read(tip)
1001 changes = repo.changelog.read(tip)
1001 repo.dirstate.setparents(*cparents)
1002 repo.dirstate.setparents(*cparents)
1002 copies = [(f, repo.dirstate.copied(f)) for f in a]
1003 copies = [(f, repo.dirstate.copied(f)) for f in a]
1003 repo.dirstate.update(a, 'a')
1004 repo.dirstate.update(a, 'a')
1004 for dst, src in copies:
1005 for dst, src in copies:
1005 repo.dirstate.copy(src, dst)
1006 repo.dirstate.copy(src, dst)
1006 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
1009 # so status can see it.
1010 mm = []
1011 for i in range(len(m)-1, -1, -1):
1012 if not matchfn(m[i]):
1013 mm.append(m[i])
1014 del m[i]
1007 repo.dirstate.update(m, 'n')
1015 repo.dirstate.update(m, 'n')
1016 repo.dirstate.update(mm, 'n', st_mtime=0)
1008 repo.dirstate.forget(forget)
1017 repo.dirstate.forget(forget)
1009
1018
1010 if not msg:
1019 if not msg:
1011 if not message:
1020 if not message:
1012 message = "patch queue: %s\n" % patch
1021 message = "patch queue: %s\n" % patch
1013 else:
1022 else:
1014 message = "\n".join(message)
1023 message = "\n".join(message)
1015 else:
1024 else:
1016 message = msg
1025 message = msg
1017
1026
1018 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
1027 self.strip(repo, top, update=False, backup='strip', wlock=wlock)
1019 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
1028 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock)
1020 self.applied[-1] = statusentry(revlog.hex(n), patch)
1029 self.applied[-1] = statusentry(revlog.hex(n), patch)
1021 self.applied_dirty = 1
1030 self.applied_dirty = 1
1022 else:
1031 else:
1023 self.printdiff(repo, patchparent, fp=patchf)
1032 self.printdiff(repo, patchparent, fp=patchf)
1024 patchf.close()
1033 patchf.close()
1025 self.pop(repo, force=True, wlock=wlock)
1034 self.pop(repo, force=True, wlock=wlock)
1026 self.push(repo, force=True, wlock=wlock)
1035 self.push(repo, force=True, wlock=wlock)
1027
1036
1028 def init(self, repo, create=False):
1037 def init(self, repo, create=False):
1029 if os.path.isdir(self.path):
1038 if os.path.isdir(self.path):
1030 raise util.Abort(_("patch queue directory already exists"))
1039 raise util.Abort(_("patch queue directory already exists"))
1031 os.mkdir(self.path)
1040 os.mkdir(self.path)
1032 if create:
1041 if create:
1033 return self.qrepo(create=True)
1042 return self.qrepo(create=True)
1034
1043
1035 def unapplied(self, repo, patch=None):
1044 def unapplied(self, repo, patch=None):
1036 if patch and patch not in self.series:
1045 if patch and patch not in self.series:
1037 raise util.Abort(_("patch %s is not in series file") % patch)
1046 raise util.Abort(_("patch %s is not in series file") % patch)
1038 if not patch:
1047 if not patch:
1039 start = self.series_end()
1048 start = self.series_end()
1040 else:
1049 else:
1041 start = self.series.index(patch) + 1
1050 start = self.series.index(patch) + 1
1042 unapplied = []
1051 unapplied = []
1043 for i in xrange(start, len(self.series)):
1052 for i in xrange(start, len(self.series)):
1044 pushable, reason = self.pushable(i)
1053 pushable, reason = self.pushable(i)
1045 if pushable:
1054 if pushable:
1046 unapplied.append((i, self.series[i]))
1055 unapplied.append((i, self.series[i]))
1047 self.explain_pushable(i)
1056 self.explain_pushable(i)
1048 return unapplied
1057 return unapplied
1049
1058
1050 def qseries(self, repo, missing=None, summary=False):
1059 def qseries(self, repo, missing=None, summary=False):
1051 start = self.series_end(all_patches=True)
1060 start = self.series_end(all_patches=True)
1052 if not missing:
1061 if not missing:
1053 for i in range(len(self.series)):
1062 for i in range(len(self.series)):
1054 patch = self.series[i]
1063 patch = self.series[i]
1055 if self.ui.verbose:
1064 if self.ui.verbose:
1056 if i < start:
1065 if i < start:
1057 status = 'A'
1066 status = 'A'
1058 elif self.pushable(i)[0]:
1067 elif self.pushable(i)[0]:
1059 status = 'U'
1068 status = 'U'
1060 else:
1069 else:
1061 status = 'G'
1070 status = 'G'
1062 self.ui.write('%d %s ' % (i, status))
1071 self.ui.write('%d %s ' % (i, status))
1063 if summary:
1072 if summary:
1064 msg = self.readheaders(patch)[0]
1073 msg = self.readheaders(patch)[0]
1065 msg = msg and ': ' + msg[0] or ': '
1074 msg = msg and ': ' + msg[0] or ': '
1066 else:
1075 else:
1067 msg = ''
1076 msg = ''
1068 self.ui.write('%s%s\n' % (patch, msg))
1077 self.ui.write('%s%s\n' % (patch, msg))
1069 else:
1078 else:
1070 msng_list = []
1079 msng_list = []
1071 for root, dirs, files in os.walk(self.path):
1080 for root, dirs, files in os.walk(self.path):
1072 d = root[len(self.path) + 1:]
1081 d = root[len(self.path) + 1:]
1073 for f in files:
1082 for f in files:
1074 fl = os.path.join(d, f)
1083 fl = os.path.join(d, f)
1075 if (fl not in self.series and
1084 if (fl not in self.series and
1076 fl not in (self.status_path, self.series_path)
1085 fl not in (self.status_path, self.series_path)
1077 and not fl.startswith('.')):
1086 and not fl.startswith('.')):
1078 msng_list.append(fl)
1087 msng_list.append(fl)
1079 msng_list.sort()
1088 msng_list.sort()
1080 for x in msng_list:
1089 for x in msng_list:
1081 if self.ui.verbose:
1090 if self.ui.verbose:
1082 self.ui.write("D ")
1091 self.ui.write("D ")
1083 self.ui.write("%s\n" % x)
1092 self.ui.write("%s\n" % x)
1084
1093
1085 def issaveline(self, l):
1094 def issaveline(self, l):
1086 if l.name == '.hg.patches.save.line':
1095 if l.name == '.hg.patches.save.line':
1087 return True
1096 return True
1088
1097
1089 def qrepo(self, create=False):
1098 def qrepo(self, create=False):
1090 if create or os.path.isdir(self.join(".hg")):
1099 if create or os.path.isdir(self.join(".hg")):
1091 return hg.repository(self.ui, path=self.path, create=create)
1100 return hg.repository(self.ui, path=self.path, create=create)
1092
1101
1093 def restore(self, repo, rev, delete=None, qupdate=None):
1102 def restore(self, repo, rev, delete=None, qupdate=None):
1094 c = repo.changelog.read(rev)
1103 c = repo.changelog.read(rev)
1095 desc = c[4].strip()
1104 desc = c[4].strip()
1096 lines = desc.splitlines()
1105 lines = desc.splitlines()
1097 i = 0
1106 i = 0
1098 datastart = None
1107 datastart = None
1099 series = []
1108 series = []
1100 applied = []
1109 applied = []
1101 qpp = None
1110 qpp = None
1102 for i in xrange(0, len(lines)):
1111 for i in xrange(0, len(lines)):
1103 if lines[i] == 'Patch Data:':
1112 if lines[i] == 'Patch Data:':
1104 datastart = i + 1
1113 datastart = i + 1
1105 elif lines[i].startswith('Dirstate:'):
1114 elif lines[i].startswith('Dirstate:'):
1106 l = lines[i].rstrip()
1115 l = lines[i].rstrip()
1107 l = l[10:].split(' ')
1116 l = l[10:].split(' ')
1108 qpp = [ hg.bin(x) for x in l ]
1117 qpp = [ hg.bin(x) for x in l ]
1109 elif datastart != None:
1118 elif datastart != None:
1110 l = lines[i].rstrip()
1119 l = lines[i].rstrip()
1111 se = statusentry(l)
1120 se = statusentry(l)
1112 file_ = se.name
1121 file_ = se.name
1113 if se.rev:
1122 if se.rev:
1114 applied.append(se)
1123 applied.append(se)
1115 series.append(file_)
1124 series.append(file_)
1116 if datastart == None:
1125 if datastart == None:
1117 self.ui.warn("No saved patch data found\n")
1126 self.ui.warn("No saved patch data found\n")
1118 return 1
1127 return 1
1119 self.ui.warn("restoring status: %s\n" % lines[0])
1128 self.ui.warn("restoring status: %s\n" % lines[0])
1120 self.full_series = series
1129 self.full_series = series
1121 self.applied = applied
1130 self.applied = applied
1122 self.parse_series()
1131 self.parse_series()
1123 self.series_dirty = 1
1132 self.series_dirty = 1
1124 self.applied_dirty = 1
1133 self.applied_dirty = 1
1125 heads = repo.changelog.heads()
1134 heads = repo.changelog.heads()
1126 if delete:
1135 if delete:
1127 if rev not in heads:
1136 if rev not in heads:
1128 self.ui.warn("save entry has children, leaving it alone\n")
1137 self.ui.warn("save entry has children, leaving it alone\n")
1129 else:
1138 else:
1130 self.ui.warn("removing save entry %s\n" % hg.short(rev))
1139 self.ui.warn("removing save entry %s\n" % hg.short(rev))
1131 pp = repo.dirstate.parents()
1140 pp = repo.dirstate.parents()
1132 if rev in pp:
1141 if rev in pp:
1133 update = True
1142 update = True
1134 else:
1143 else:
1135 update = False
1144 update = False
1136 self.strip(repo, rev, update=update, backup='strip')
1145 self.strip(repo, rev, update=update, backup='strip')
1137 if qpp:
1146 if qpp:
1138 self.ui.warn("saved queue repository parents: %s %s\n" %
1147 self.ui.warn("saved queue repository parents: %s %s\n" %
1139 (hg.short(qpp[0]), hg.short(qpp[1])))
1148 (hg.short(qpp[0]), hg.short(qpp[1])))
1140 if qupdate:
1149 if qupdate:
1141 print "queue directory updating"
1150 print "queue directory updating"
1142 r = self.qrepo()
1151 r = self.qrepo()
1143 if not r:
1152 if not r:
1144 self.ui.warn("Unable to load queue repository\n")
1153 self.ui.warn("Unable to load queue repository\n")
1145 return 1
1154 return 1
1146 hg.clean(r, qpp[0])
1155 hg.clean(r, qpp[0])
1147
1156
1148 def save(self, repo, msg=None):
1157 def save(self, repo, msg=None):
1149 if len(self.applied) == 0:
1158 if len(self.applied) == 0:
1150 self.ui.warn("save: no patches applied, exiting\n")
1159 self.ui.warn("save: no patches applied, exiting\n")
1151 return 1
1160 return 1
1152 if self.issaveline(self.applied[-1]):
1161 if self.issaveline(self.applied[-1]):
1153 self.ui.warn("status is already saved\n")
1162 self.ui.warn("status is already saved\n")
1154 return 1
1163 return 1
1155
1164
1156 ar = [ ':' + x for x in self.full_series ]
1165 ar = [ ':' + x for x in self.full_series ]
1157 if not msg:
1166 if not msg:
1158 msg = "hg patches saved state"
1167 msg = "hg patches saved state"
1159 else:
1168 else:
1160 msg = "hg patches: " + msg.rstrip('\r\n')
1169 msg = "hg patches: " + msg.rstrip('\r\n')
1161 r = self.qrepo()
1170 r = self.qrepo()
1162 if r:
1171 if r:
1163 pp = r.dirstate.parents()
1172 pp = r.dirstate.parents()
1164 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]))
1165 msg += "\n\nPatch Data:\n"
1174 msg += "\n\nPatch Data:\n"
1166 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
1167 "\n".join(ar) + '\n' or "")
1176 "\n".join(ar) + '\n' or "")
1168 n = repo.commit(None, text, user=None, force=1)
1177 n = repo.commit(None, text, user=None, force=1)
1169 if not n:
1178 if not n:
1170 self.ui.warn("repo commit failed\n")
1179 self.ui.warn("repo commit failed\n")
1171 return 1
1180 return 1
1172 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1181 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1173 self.applied_dirty = 1
1182 self.applied_dirty = 1
1174
1183
1175 def full_series_end(self):
1184 def full_series_end(self):
1176 if len(self.applied) > 0:
1185 if len(self.applied) > 0:
1177 p = self.applied[-1].name
1186 p = self.applied[-1].name
1178 end = self.find_series(p)
1187 end = self.find_series(p)
1179 if end == None:
1188 if end == None:
1180 return len(self.full_series)
1189 return len(self.full_series)
1181 return end + 1
1190 return end + 1
1182 return 0
1191 return 0
1183
1192
1184 def series_end(self, all_patches=False):
1193 def series_end(self, all_patches=False):
1185 end = 0
1194 end = 0
1186 def next(start):
1195 def next(start):
1187 if all_patches:
1196 if all_patches:
1188 return start
1197 return start
1189 i = start
1198 i = start
1190 while i < len(self.series):
1199 while i < len(self.series):
1191 p, reason = self.pushable(i)
1200 p, reason = self.pushable(i)
1192 if p:
1201 if p:
1193 break
1202 break
1194 self.explain_pushable(i)
1203 self.explain_pushable(i)
1195 i += 1
1204 i += 1
1196 return i
1205 return i
1197 if len(self.applied) > 0:
1206 if len(self.applied) > 0:
1198 p = self.applied[-1].name
1207 p = self.applied[-1].name
1199 try:
1208 try:
1200 end = self.series.index(p)
1209 end = self.series.index(p)
1201 except ValueError:
1210 except ValueError:
1202 return 0
1211 return 0
1203 return next(end + 1)
1212 return next(end + 1)
1204 return next(end)
1213 return next(end)
1205
1214
1206 def qapplied(self, repo, patch=None):
1215 def qapplied(self, repo, patch=None):
1207 if patch and patch not in self.series:
1216 if patch and patch not in self.series:
1208 raise util.Abort(_("patch %s is not in series file") % patch)
1217 raise util.Abort(_("patch %s is not in series file") % patch)
1209 if not patch:
1218 if not patch:
1210 end = len(self.applied)
1219 end = len(self.applied)
1211 else:
1220 else:
1212 end = self.series.index(patch) + 1
1221 end = self.series.index(patch) + 1
1213 for x in xrange(end):
1222 for x in xrange(end):
1214 p = self.appliedname(x)
1223 p = self.appliedname(x)
1215 self.ui.write("%s\n" % p)
1224 self.ui.write("%s\n" % p)
1216
1225
1217 def appliedname(self, index):
1226 def appliedname(self, index):
1218 pname = self.applied[index].name
1227 pname = self.applied[index].name
1219 if not self.ui.verbose:
1228 if not self.ui.verbose:
1220 p = pname
1229 p = pname
1221 else:
1230 else:
1222 p = str(self.series.index(pname)) + " " + p
1231 p = str(self.series.index(pname)) + " " + p
1223 return p
1232 return p
1224
1233
1225 def top(self, repo):
1234 def top(self, repo):
1226 if len(self.applied):
1235 if len(self.applied):
1227 p = self.appliedname(-1)
1236 p = self.appliedname(-1)
1228 self.ui.write(p + '\n')
1237 self.ui.write(p + '\n')
1229 else:
1238 else:
1230 self.ui.write("No patches applied\n")
1239 self.ui.write("No patches applied\n")
1231
1240
1232 def next(self, repo):
1241 def next(self, repo):
1233 end = self.series_end()
1242 end = self.series_end()
1234 if end == len(self.series):
1243 if end == len(self.series):
1235 self.ui.write("All patches applied\n")
1244 self.ui.write("All patches applied\n")
1236 else:
1245 else:
1237 p = self.series[end]
1246 p = self.series[end]
1238 if self.ui.verbose:
1247 if self.ui.verbose:
1239 self.ui.write("%d " % self.series.index(p))
1248 self.ui.write("%d " % self.series.index(p))
1240 self.ui.write(p + '\n')
1249 self.ui.write(p + '\n')
1241
1250
1242 def prev(self, repo):
1251 def prev(self, repo):
1243 if len(self.applied) > 1:
1252 if len(self.applied) > 1:
1244 p = self.appliedname(-2)
1253 p = self.appliedname(-2)
1245 self.ui.write(p + '\n')
1254 self.ui.write(p + '\n')
1246 elif len(self.applied) == 1:
1255 elif len(self.applied) == 1:
1247 self.ui.write("Only one patch applied\n")
1256 self.ui.write("Only one patch applied\n")
1248 else:
1257 else:
1249 self.ui.write("No patches applied\n")
1258 self.ui.write("No patches applied\n")
1250
1259
1251 def qimport(self, repo, files, patch=None, existing=None, force=None):
1260 def qimport(self, repo, files, patch=None, existing=None, force=None):
1252 if len(files) > 1 and patch:
1261 if len(files) > 1 and patch:
1253 raise util.Abort(_('option "-n" not valid when importing multiple '
1262 raise util.Abort(_('option "-n" not valid when importing multiple '
1254 'files'))
1263 'files'))
1255 i = 0
1264 i = 0
1256 added = []
1265 added = []
1257 for filename in files:
1266 for filename in files:
1258 if existing:
1267 if existing:
1259 if not patch:
1268 if not patch:
1260 patch = filename
1269 patch = filename
1261 if not os.path.isfile(self.join(patch)):
1270 if not os.path.isfile(self.join(patch)):
1262 raise util.Abort(_("patch %s does not exist") % patch)
1271 raise util.Abort(_("patch %s does not exist") % patch)
1263 else:
1272 else:
1264 try:
1273 try:
1265 text = file(filename).read()
1274 text = file(filename).read()
1266 except IOError:
1275 except IOError:
1267 raise util.Abort(_("unable to read %s") % patch)
1276 raise util.Abort(_("unable to read %s") % patch)
1268 if not patch:
1277 if not patch:
1269 patch = os.path.split(filename)[1]
1278 patch = os.path.split(filename)[1]
1270 if not force and os.path.exists(self.join(patch)):
1279 if not force and os.path.exists(self.join(patch)):
1271 raise util.Abort(_('patch "%s" already exists') % patch)
1280 raise util.Abort(_('patch "%s" already exists') % patch)
1272 patchf = self.opener(patch, "w")
1281 patchf = self.opener(patch, "w")
1273 patchf.write(text)
1282 patchf.write(text)
1274 if patch in self.series:
1283 if patch in self.series:
1275 raise util.Abort(_('patch %s is already in the series file')
1284 raise util.Abort(_('patch %s is already in the series file')
1276 % patch)
1285 % patch)
1277 index = self.full_series_end() + i
1286 index = self.full_series_end() + i
1278 self.full_series[index:index] = [patch]
1287 self.full_series[index:index] = [patch]
1279 self.parse_series()
1288 self.parse_series()
1280 self.ui.warn("adding %s to series file\n" % patch)
1289 self.ui.warn("adding %s to series file\n" % patch)
1281 i += 1
1290 i += 1
1282 added.append(patch)
1291 added.append(patch)
1283 patch = None
1292 patch = None
1284 self.series_dirty = 1
1293 self.series_dirty = 1
1285 qrepo = self.qrepo()
1294 qrepo = self.qrepo()
1286 if qrepo:
1295 if qrepo:
1287 qrepo.add(added)
1296 qrepo.add(added)
1288
1297
1289 def delete(ui, repo, patch, *patches, **opts):
1298 def delete(ui, repo, patch, *patches, **opts):
1290 """remove patches from queue
1299 """remove patches from queue
1291
1300
1292 The patches must not be applied.
1301 The patches must not be applied.
1293 With -k, the patch files are preserved in the patch directory."""
1302 With -k, the patch files are preserved in the patch directory."""
1294 q = repo.mq
1303 q = repo.mq
1295 q.delete(repo, (patch,) + patches, keep=opts.get('keep'))
1304 q.delete(repo, (patch,) + patches, keep=opts.get('keep'))
1296 q.save_dirty()
1305 q.save_dirty()
1297 return 0
1306 return 0
1298
1307
1299 def applied(ui, repo, patch=None, **opts):
1308 def applied(ui, repo, patch=None, **opts):
1300 """print the patches already applied"""
1309 """print the patches already applied"""
1301 repo.mq.qapplied(repo, patch)
1310 repo.mq.qapplied(repo, patch)
1302 return 0
1311 return 0
1303
1312
1304 def unapplied(ui, repo, patch=None, **opts):
1313 def unapplied(ui, repo, patch=None, **opts):
1305 """print the patches not yet applied"""
1314 """print the patches not yet applied"""
1306 for i, p in repo.mq.unapplied(repo, patch):
1315 for i, p in repo.mq.unapplied(repo, patch):
1307 if ui.verbose:
1316 if ui.verbose:
1308 ui.write("%d " % i)
1317 ui.write("%d " % i)
1309 ui.write("%s\n" % p)
1318 ui.write("%s\n" % p)
1310
1319
1311 def qimport(ui, repo, *filename, **opts):
1320 def qimport(ui, repo, *filename, **opts):
1312 """import a patch"""
1321 """import a patch"""
1313 q = repo.mq
1322 q = repo.mq
1314 q.qimport(repo, filename, patch=opts['name'],
1323 q.qimport(repo, filename, patch=opts['name'],
1315 existing=opts['existing'], force=opts['force'])
1324 existing=opts['existing'], force=opts['force'])
1316 q.save_dirty()
1325 q.save_dirty()
1317 return 0
1326 return 0
1318
1327
1319 def init(ui, repo, **opts):
1328 def init(ui, repo, **opts):
1320 """init a new queue repository
1329 """init a new queue repository
1321
1330
1322 The queue repository is unversioned by default. If -c is
1331 The queue repository is unversioned by default. If -c is
1323 specified, qinit will create a separate nested repository
1332 specified, qinit will create a separate nested repository
1324 for patches. Use qcommit to commit changes to this queue
1333 for patches. Use qcommit to commit changes to this queue
1325 repository."""
1334 repository."""
1326 q = repo.mq
1335 q = repo.mq
1327 r = q.init(repo, create=opts['create_repo'])
1336 r = q.init(repo, create=opts['create_repo'])
1328 q.save_dirty()
1337 q.save_dirty()
1329 if r:
1338 if r:
1330 fp = r.wopener('.hgignore', 'w')
1339 fp = r.wopener('.hgignore', 'w')
1331 print >> fp, 'syntax: glob'
1340 print >> fp, 'syntax: glob'
1332 print >> fp, 'status'
1341 print >> fp, 'status'
1333 fp.close()
1342 fp.close()
1334 r.wopener('series', 'w').close()
1343 r.wopener('series', 'w').close()
1335 r.add(['.hgignore', 'series'])
1344 r.add(['.hgignore', 'series'])
1336 return 0
1345 return 0
1337
1346
1338 def clone(ui, source, dest=None, **opts):
1347 def clone(ui, source, dest=None, **opts):
1339 '''clone main and patch repository at same time
1348 '''clone main and patch repository at same time
1340
1349
1341 If source is local, destination will have no patches applied. If
1350 If source is local, destination will have no patches applied. If
1342 source is remote, this command can not check if patches are
1351 source is remote, this command can not check if patches are
1343 applied in source, so cannot guarantee that patches are not
1352 applied in source, so cannot guarantee that patches are not
1344 applied in destination. If you clone remote repository, be sure
1353 applied in destination. If you clone remote repository, be sure
1345 before that it has no patches applied.
1354 before that it has no patches applied.
1346
1355
1347 Source patch repository is looked for in <src>/.hg/patches by
1356 Source patch repository is looked for in <src>/.hg/patches by
1348 default. Use -p <url> to change.
1357 default. Use -p <url> to change.
1349 '''
1358 '''
1350 commands.setremoteconfig(ui, opts)
1359 commands.setremoteconfig(ui, opts)
1351 if dest is None:
1360 if dest is None:
1352 dest = hg.defaultdest(source)
1361 dest = hg.defaultdest(source)
1353 sr = hg.repository(ui, ui.expandpath(source))
1362 sr = hg.repository(ui, ui.expandpath(source))
1354 qbase, destrev = None, None
1363 qbase, destrev = None, None
1355 if sr.local():
1364 if sr.local():
1356 reposetup(ui, sr)
1365 reposetup(ui, sr)
1357 if sr.mq.applied:
1366 if sr.mq.applied:
1358 qbase = revlog.bin(sr.mq.applied[0].rev)
1367 qbase = revlog.bin(sr.mq.applied[0].rev)
1359 if not hg.islocal(dest):
1368 if not hg.islocal(dest):
1360 destrev = sr.parents(qbase)[0]
1369 destrev = sr.parents(qbase)[0]
1361 ui.note(_('cloning main repo\n'))
1370 ui.note(_('cloning main repo\n'))
1362 sr, dr = hg.clone(ui, sr, dest,
1371 sr, dr = hg.clone(ui, sr, dest,
1363 pull=opts['pull'],
1372 pull=opts['pull'],
1364 rev=destrev,
1373 rev=destrev,
1365 update=False,
1374 update=False,
1366 stream=opts['uncompressed'])
1375 stream=opts['uncompressed'])
1367 ui.note(_('cloning patch repo\n'))
1376 ui.note(_('cloning patch repo\n'))
1368 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'),
1369 dr.url() + '/.hg/patches',
1378 dr.url() + '/.hg/patches',
1370 pull=opts['pull'],
1379 pull=opts['pull'],
1371 update=not opts['noupdate'],
1380 update=not opts['noupdate'],
1372 stream=opts['uncompressed'])
1381 stream=opts['uncompressed'])
1373 if dr.local():
1382 if dr.local():
1374 if qbase:
1383 if qbase:
1375 ui.note(_('stripping applied patches from destination repo\n'))
1384 ui.note(_('stripping applied patches from destination repo\n'))
1376 reposetup(ui, dr)
1385 reposetup(ui, dr)
1377 dr.mq.strip(dr, qbase, update=False, backup=None)
1386 dr.mq.strip(dr, qbase, update=False, backup=None)
1378 if not opts['noupdate']:
1387 if not opts['noupdate']:
1379 ui.note(_('updating destination repo\n'))
1388 ui.note(_('updating destination repo\n'))
1380 hg.update(dr, dr.changelog.tip())
1389 hg.update(dr, dr.changelog.tip())
1381
1390
1382 def commit(ui, repo, *pats, **opts):
1391 def commit(ui, repo, *pats, **opts):
1383 """commit changes in the queue repository"""
1392 """commit changes in the queue repository"""
1384 q = repo.mq
1393 q = repo.mq
1385 r = q.qrepo()
1394 r = q.qrepo()
1386 if not r: raise util.Abort('no queue repository')
1395 if not r: raise util.Abort('no queue repository')
1387 commands.commit(r.ui, r, *pats, **opts)
1396 commands.commit(r.ui, r, *pats, **opts)
1388
1397
1389 def series(ui, repo, **opts):
1398 def series(ui, repo, **opts):
1390 """print the entire series file"""
1399 """print the entire series file"""
1391 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1400 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1392 return 0
1401 return 0
1393
1402
1394 def top(ui, repo, **opts):
1403 def top(ui, repo, **opts):
1395 """print the name of the current patch"""
1404 """print the name of the current patch"""
1396 repo.mq.top(repo)
1405 repo.mq.top(repo)
1397 return 0
1406 return 0
1398
1407
1399 def next(ui, repo, **opts):
1408 def next(ui, repo, **opts):
1400 """print the name of the next patch"""
1409 """print the name of the next patch"""
1401 repo.mq.next(repo)
1410 repo.mq.next(repo)
1402 return 0
1411 return 0
1403
1412
1404 def prev(ui, repo, **opts):
1413 def prev(ui, repo, **opts):
1405 """print the name of the previous patch"""
1414 """print the name of the previous patch"""
1406 repo.mq.prev(repo)
1415 repo.mq.prev(repo)
1407 return 0
1416 return 0
1408
1417
1409 def new(ui, repo, patch, **opts):
1418 def new(ui, repo, patch, **opts):
1410 """create a new patch
1419 """create a new patch
1411
1420
1412 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
1413 (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
1414 changes unless -f is specified, in which case the patch will
1423 changes unless -f is specified, in which case the patch will
1415 be initialised with them.
1424 be initialised with them.
1416
1425
1417 -m or -l set the patch header as well as the commit message.
1426 -m or -l set the patch header as well as the commit message.
1418 If neither is specified, the patch header is empty and the
1427 If neither is specified, the patch header is empty and the
1419 commit message is 'New patch: PATCH'"""
1428 commit message is 'New patch: PATCH'"""
1420 q = repo.mq
1429 q = repo.mq
1421 message = commands.logmessage(opts)
1430 message = commands.logmessage(opts)
1422 q.new(repo, patch, msg=message, force=opts['force'])
1431 q.new(repo, patch, msg=message, force=opts['force'])
1423 q.save_dirty()
1432 q.save_dirty()
1424 return 0
1433 return 0
1425
1434
1426 def refresh(ui, repo, **opts):
1435 def refresh(ui, repo, *pats, **opts):
1427 """update the current patch"""
1436 """update the current patch"""
1428 q = repo.mq
1437 q = repo.mq
1429 message = commands.logmessage(opts)
1438 message = commands.logmessage(opts)
1430 if opts['edit']:
1439 if opts['edit']:
1431 if message:
1440 if message:
1432 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1441 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1433 patch = q.applied[-1].name
1442 patch = q.applied[-1].name
1434 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1443 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1435 message = ui.edit('\n'.join(message), user or ui.username())
1444 message = ui.edit('\n'.join(message), user or ui.username())
1436 q.refresh(repo, msg=message, short=opts['short'])
1445 q.refresh(repo, pats, msg=message, **opts)
1437 q.save_dirty()
1446 q.save_dirty()
1438 return 0
1447 return 0
1439
1448
1440 def diff(ui, repo, *pats, **opts):
1449 def diff(ui, repo, *pats, **opts):
1441 """diff of the current patch"""
1450 """diff of the current patch"""
1442 repo.mq.diff(repo, pats, opts)
1451 repo.mq.diff(repo, pats, opts)
1443 return 0
1452 return 0
1444
1453
1445 def fold(ui, repo, *files, **opts):
1454 def fold(ui, repo, *files, **opts):
1446 """fold the named patches into the current patch
1455 """fold the named patches into the current patch
1447
1456
1448 Patches must not yet be applied. Each patch will be successively
1457 Patches must not yet be applied. Each patch will be successively
1449 applied to the current patch in the order given. If all the
1458 applied to the current patch in the order given. If all the
1450 patches apply successfully, the current patch will be refreshed
1459 patches apply successfully, the current patch will be refreshed
1451 with the new cumulative patch, and the folded patches will
1460 with the new cumulative patch, and the folded patches will
1452 be deleted. With -k/--keep, the folded patch files will not
1461 be deleted. With -k/--keep, the folded patch files will not
1453 be removed afterwards.
1462 be removed afterwards.
1454
1463
1455 The header for each folded patch will be concatenated with
1464 The header for each folded patch will be concatenated with
1456 the current patch header, separated by a line of '* * *'."""
1465 the current patch header, separated by a line of '* * *'."""
1457
1466
1458 q = repo.mq
1467 q = repo.mq
1459
1468
1460 if not files:
1469 if not files:
1461 raise util.Abort(_('qfold requires at least one patch name'))
1470 raise util.Abort(_('qfold requires at least one patch name'))
1462 if not q.check_toppatch(repo):
1471 if not q.check_toppatch(repo):
1463 raise util.Abort(_('No patches applied\n'))
1472 raise util.Abort(_('No patches applied\n'))
1464
1473
1465 message = commands.logmessage(opts)
1474 message = commands.logmessage(opts)
1466 if opts['edit']:
1475 if opts['edit']:
1467 if message:
1476 if message:
1468 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1477 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1469
1478
1470 parent = q.lookup('qtip')
1479 parent = q.lookup('qtip')
1471 patches = []
1480 patches = []
1472 messages = []
1481 messages = []
1473 for f in files:
1482 for f in files:
1474 p = q.lookup(f)
1483 p = q.lookup(f)
1475 if p in patches or p == parent:
1484 if p in patches or p == parent:
1476 ui.warn(_('Skipping already folded patch %s') % p)
1485 ui.warn(_('Skipping already folded patch %s') % p)
1477 if q.isapplied(p):
1486 if q.isapplied(p):
1478 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1487 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1479 patches.append(p)
1488 patches.append(p)
1480
1489
1481 for p in patches:
1490 for p in patches:
1482 if not message:
1491 if not message:
1483 messages.append(q.readheaders(p)[0])
1492 messages.append(q.readheaders(p)[0])
1484 pf = q.join(p)
1493 pf = q.join(p)
1485 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1494 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1486 if not patchsuccess:
1495 if not patchsuccess:
1487 raise util.Abort(_('Error folding patch %s') % p)
1496 raise util.Abort(_('Error folding patch %s') % p)
1488 patch.updatedir(ui, repo, files)
1497 patch.updatedir(ui, repo, files)
1489
1498
1490 if not message:
1499 if not message:
1491 message, comments, user = q.readheaders(parent)[0:3]
1500 message, comments, user = q.readheaders(parent)[0:3]
1492 for msg in messages:
1501 for msg in messages:
1493 message.append('* * *')
1502 message.append('* * *')
1494 message.extend(msg)
1503 message.extend(msg)
1495 message = '\n'.join(message)
1504 message = '\n'.join(message)
1496
1505
1497 if opts['edit']:
1506 if opts['edit']:
1498 message = ui.edit(message, user or ui.username())
1507 message = ui.edit(message, user or ui.username())
1499
1508
1500 q.refresh(repo, msg=message)
1509 q.refresh(repo, msg=message)
1501 q.delete(repo, patches, keep=opts['keep'])
1510 q.delete(repo, patches, keep=opts['keep'])
1502 q.save_dirty()
1511 q.save_dirty()
1503
1512
1504 def guard(ui, repo, *args, **opts):
1513 def guard(ui, repo, *args, **opts):
1505 '''set or print guards for a patch
1514 '''set or print guards for a patch
1506
1515
1507 guards control whether a patch can be pushed. a patch with no
1516 guards control whether a patch can be pushed. a patch with no
1508 guards is aways pushed. a patch with posative guard ("+foo") is
1517 guards is aways pushed. a patch with posative guard ("+foo") is
1509 pushed only if qselect command enables guard "foo". a patch with
1518 pushed only if qselect command enables guard "foo". a patch with
1510 nagative guard ("-foo") is never pushed if qselect command enables
1519 nagative guard ("-foo") is never pushed if qselect command enables
1511 guard "foo".
1520 guard "foo".
1512
1521
1513 with no arguments, default is to print current active guards.
1522 with no arguments, default is to print current active guards.
1514 with arguments, set active guards for patch.
1523 with arguments, set active guards for patch.
1515
1524
1516 to set nagative guard "-foo" on topmost patch ("--" is needed so
1525 to set nagative guard "-foo" on topmost patch ("--" is needed so
1517 hg will not interpret "-foo" as argument):
1526 hg will not interpret "-foo" as argument):
1518 hg qguard -- -foo
1527 hg qguard -- -foo
1519
1528
1520 to set guards on other patch:
1529 to set guards on other patch:
1521 hg qguard other.patch +2.6.17 -stable
1530 hg qguard other.patch +2.6.17 -stable
1522 '''
1531 '''
1523 def status(idx):
1532 def status(idx):
1524 guards = q.series_guards[idx] or ['unguarded']
1533 guards = q.series_guards[idx] or ['unguarded']
1525 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1534 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1526 q = repo.mq
1535 q = repo.mq
1527 patch = None
1536 patch = None
1528 args = list(args)
1537 args = list(args)
1529 if opts['list']:
1538 if opts['list']:
1530 if args or opts['none']:
1539 if args or opts['none']:
1531 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1540 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1532 for i in xrange(len(q.series)):
1541 for i in xrange(len(q.series)):
1533 status(i)
1542 status(i)
1534 return
1543 return
1535 if not args or args[0][0:1] in '-+':
1544 if not args or args[0][0:1] in '-+':
1536 if not q.applied:
1545 if not q.applied:
1537 raise util.Abort(_('no patches applied'))
1546 raise util.Abort(_('no patches applied'))
1538 patch = q.applied[-1].name
1547 patch = q.applied[-1].name
1539 if patch is None and args[0][0:1] not in '-+':
1548 if patch is None and args[0][0:1] not in '-+':
1540 patch = args.pop(0)
1549 patch = args.pop(0)
1541 if patch is None:
1550 if patch is None:
1542 raise util.Abort(_('no patch to work with'))
1551 raise util.Abort(_('no patch to work with'))
1543 if args or opts['none']:
1552 if args or opts['none']:
1544 q.set_guards(q.find_series(patch), args)
1553 q.set_guards(q.find_series(patch), args)
1545 q.save_dirty()
1554 q.save_dirty()
1546 else:
1555 else:
1547 status(q.series.index(q.lookup(patch)))
1556 status(q.series.index(q.lookup(patch)))
1548
1557
1549 def header(ui, repo, patch=None):
1558 def header(ui, repo, patch=None):
1550 """Print the header of the topmost or specified patch"""
1559 """Print the header of the topmost or specified patch"""
1551 q = repo.mq
1560 q = repo.mq
1552
1561
1553 if patch:
1562 if patch:
1554 patch = q.lookup(patch)
1563 patch = q.lookup(patch)
1555 else:
1564 else:
1556 if not q.applied:
1565 if not q.applied:
1557 ui.write('No patches applied\n')
1566 ui.write('No patches applied\n')
1558 return
1567 return
1559 patch = q.lookup('qtip')
1568 patch = q.lookup('qtip')
1560 message = repo.mq.readheaders(patch)[0]
1569 message = repo.mq.readheaders(patch)[0]
1561
1570
1562 ui.write('\n'.join(message) + '\n')
1571 ui.write('\n'.join(message) + '\n')
1563
1572
1564 def lastsavename(path):
1573 def lastsavename(path):
1565 (directory, base) = os.path.split(path)
1574 (directory, base) = os.path.split(path)
1566 names = os.listdir(directory)
1575 names = os.listdir(directory)
1567 namere = re.compile("%s.([0-9]+)" % base)
1576 namere = re.compile("%s.([0-9]+)" % base)
1568 maxindex = None
1577 maxindex = None
1569 maxname = None
1578 maxname = None
1570 for f in names:
1579 for f in names:
1571 m = namere.match(f)
1580 m = namere.match(f)
1572 if m:
1581 if m:
1573 index = int(m.group(1))
1582 index = int(m.group(1))
1574 if maxindex == None or index > maxindex:
1583 if maxindex == None or index > maxindex:
1575 maxindex = index
1584 maxindex = index
1576 maxname = f
1585 maxname = f
1577 if maxname:
1586 if maxname:
1578 return (os.path.join(directory, maxname), maxindex)
1587 return (os.path.join(directory, maxname), maxindex)
1579 return (None, None)
1588 return (None, None)
1580
1589
1581 def savename(path):
1590 def savename(path):
1582 (last, index) = lastsavename(path)
1591 (last, index) = lastsavename(path)
1583 if last is None:
1592 if last is None:
1584 index = 0
1593 index = 0
1585 newpath = path + ".%d" % (index + 1)
1594 newpath = path + ".%d" % (index + 1)
1586 return newpath
1595 return newpath
1587
1596
1588 def push(ui, repo, patch=None, **opts):
1597 def push(ui, repo, patch=None, **opts):
1589 """push the next patch onto the stack"""
1598 """push the next patch onto the stack"""
1590 q = repo.mq
1599 q = repo.mq
1591 mergeq = None
1600 mergeq = None
1592
1601
1593 if opts['all']:
1602 if opts['all']:
1594 patch = q.series[-1]
1603 patch = q.series[-1]
1595 if opts['merge']:
1604 if opts['merge']:
1596 if opts['name']:
1605 if opts['name']:
1597 newpath = opts['name']
1606 newpath = opts['name']
1598 else:
1607 else:
1599 newpath, i = lastsavename(q.path)
1608 newpath, i = lastsavename(q.path)
1600 if not newpath:
1609 if not newpath:
1601 ui.warn("no saved queues found, please use -n\n")
1610 ui.warn("no saved queues found, please use -n\n")
1602 return 1
1611 return 1
1603 mergeq = queue(ui, repo.join(""), newpath)
1612 mergeq = queue(ui, repo.join(""), newpath)
1604 ui.warn("merging with queue at: %s\n" % mergeq.path)
1613 ui.warn("merging with queue at: %s\n" % mergeq.path)
1605 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1614 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
1606 mergeq=mergeq)
1615 mergeq=mergeq)
1607 q.save_dirty()
1616 q.save_dirty()
1608 return ret
1617 return ret
1609
1618
1610 def pop(ui, repo, patch=None, **opts):
1619 def pop(ui, repo, patch=None, **opts):
1611 """pop the current patch off the stack"""
1620 """pop the current patch off the stack"""
1612 localupdate = True
1621 localupdate = True
1613 if opts['name']:
1622 if opts['name']:
1614 q = queue(ui, repo.join(""), repo.join(opts['name']))
1623 q = queue(ui, repo.join(""), repo.join(opts['name']))
1615 ui.warn('using patch queue: %s\n' % q.path)
1624 ui.warn('using patch queue: %s\n' % q.path)
1616 localupdate = False
1625 localupdate = False
1617 else:
1626 else:
1618 q = repo.mq
1627 q = repo.mq
1619 q.pop(repo, patch, force=opts['force'], update=localupdate, all=opts['all'])
1628 q.pop(repo, patch, force=opts['force'], update=localupdate, all=opts['all'])
1620 q.save_dirty()
1629 q.save_dirty()
1621 return 0
1630 return 0
1622
1631
1623 def rename(ui, repo, patch, name=None, **opts):
1632 def rename(ui, repo, patch, name=None, **opts):
1624 """rename a patch
1633 """rename a patch
1625
1634
1626 With one argument, renames the current patch to PATCH1.
1635 With one argument, renames the current patch to PATCH1.
1627 With two arguments, renames PATCH1 to PATCH2."""
1636 With two arguments, renames PATCH1 to PATCH2."""
1628
1637
1629 q = repo.mq
1638 q = repo.mq
1630
1639
1631 if not name:
1640 if not name:
1632 name = patch
1641 name = patch
1633 patch = None
1642 patch = None
1634
1643
1635 if name in q.series:
1644 if name in q.series:
1636 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1645 raise util.Abort(_('A patch named %s already exists in the series file') % name)
1637
1646
1638 absdest = q.join(name)
1647 absdest = q.join(name)
1639 if os.path.exists(absdest):
1648 if os.path.exists(absdest):
1640 raise util.Abort(_('%s already exists') % absdest)
1649 raise util.Abort(_('%s already exists') % absdest)
1641
1650
1642 if patch:
1651 if patch:
1643 patch = q.lookup(patch)
1652 patch = q.lookup(patch)
1644 else:
1653 else:
1645 if not q.applied:
1654 if not q.applied:
1646 ui.write(_('No patches applied\n'))
1655 ui.write(_('No patches applied\n'))
1647 return
1656 return
1648 patch = q.lookup('qtip')
1657 patch = q.lookup('qtip')
1649
1658
1650 if ui.verbose:
1659 if ui.verbose:
1651 ui.write('Renaming %s to %s\n' % (patch, name))
1660 ui.write('Renaming %s to %s\n' % (patch, name))
1652 i = q.find_series(patch)
1661 i = q.find_series(patch)
1653 q.full_series[i] = name
1662 q.full_series[i] = name
1654 q.parse_series()
1663 q.parse_series()
1655 q.series_dirty = 1
1664 q.series_dirty = 1
1656
1665
1657 info = q.isapplied(patch)
1666 info = q.isapplied(patch)
1658 if info:
1667 if info:
1659 q.applied[info[0]] = statusentry(info[1], name)
1668 q.applied[info[0]] = statusentry(info[1], name)
1660 q.applied_dirty = 1
1669 q.applied_dirty = 1
1661
1670
1662 util.rename(q.join(patch), absdest)
1671 util.rename(q.join(patch), absdest)
1663 r = q.qrepo()
1672 r = q.qrepo()
1664 if r:
1673 if r:
1665 wlock = r.wlock()
1674 wlock = r.wlock()
1666 if r.dirstate.state(name) == 'r':
1675 if r.dirstate.state(name) == 'r':
1667 r.undelete([name], wlock)
1676 r.undelete([name], wlock)
1668 r.copy(patch, name, wlock)
1677 r.copy(patch, name, wlock)
1669 r.remove([patch], False, wlock)
1678 r.remove([patch], False, wlock)
1670
1679
1671 q.save_dirty()
1680 q.save_dirty()
1672
1681
1673 def restore(ui, repo, rev, **opts):
1682 def restore(ui, repo, rev, **opts):
1674 """restore the queue state saved by a rev"""
1683 """restore the queue state saved by a rev"""
1675 rev = repo.lookup(rev)
1684 rev = repo.lookup(rev)
1676 q = repo.mq
1685 q = repo.mq
1677 q.restore(repo, rev, delete=opts['delete'],
1686 q.restore(repo, rev, delete=opts['delete'],
1678 qupdate=opts['update'])
1687 qupdate=opts['update'])
1679 q.save_dirty()
1688 q.save_dirty()
1680 return 0
1689 return 0
1681
1690
1682 def save(ui, repo, **opts):
1691 def save(ui, repo, **opts):
1683 """save current queue state"""
1692 """save current queue state"""
1684 q = repo.mq
1693 q = repo.mq
1685 message = commands.logmessage(opts)
1694 message = commands.logmessage(opts)
1686 ret = q.save(repo, msg=message)
1695 ret = q.save(repo, msg=message)
1687 if ret:
1696 if ret:
1688 return ret
1697 return ret
1689 q.save_dirty()
1698 q.save_dirty()
1690 if opts['copy']:
1699 if opts['copy']:
1691 path = q.path
1700 path = q.path
1692 if opts['name']:
1701 if opts['name']:
1693 newpath = os.path.join(q.basepath, opts['name'])
1702 newpath = os.path.join(q.basepath, opts['name'])
1694 if os.path.exists(newpath):
1703 if os.path.exists(newpath):
1695 if not os.path.isdir(newpath):
1704 if not os.path.isdir(newpath):
1696 raise util.Abort(_('destination %s exists and is not '
1705 raise util.Abort(_('destination %s exists and is not '
1697 'a directory') % newpath)
1706 'a directory') % newpath)
1698 if not opts['force']:
1707 if not opts['force']:
1699 raise util.Abort(_('destination %s exists, '
1708 raise util.Abort(_('destination %s exists, '
1700 'use -f to force') % newpath)
1709 'use -f to force') % newpath)
1701 else:
1710 else:
1702 newpath = savename(path)
1711 newpath = savename(path)
1703 ui.warn("copy %s to %s\n" % (path, newpath))
1712 ui.warn("copy %s to %s\n" % (path, newpath))
1704 util.copyfiles(path, newpath)
1713 util.copyfiles(path, newpath)
1705 if opts['empty']:
1714 if opts['empty']:
1706 try:
1715 try:
1707 os.unlink(q.join(q.status_path))
1716 os.unlink(q.join(q.status_path))
1708 except:
1717 except:
1709 pass
1718 pass
1710 return 0
1719 return 0
1711
1720
1712 def strip(ui, repo, rev, **opts):
1721 def strip(ui, repo, rev, **opts):
1713 """strip a revision and all later revs on the same branch"""
1722 """strip a revision and all later revs on the same branch"""
1714 rev = repo.lookup(rev)
1723 rev = repo.lookup(rev)
1715 backup = 'all'
1724 backup = 'all'
1716 if opts['backup']:
1725 if opts['backup']:
1717 backup = 'strip'
1726 backup = 'strip'
1718 elif opts['nobackup']:
1727 elif opts['nobackup']:
1719 backup = 'none'
1728 backup = 'none'
1720 repo.mq.strip(repo, rev, backup=backup)
1729 repo.mq.strip(repo, rev, backup=backup)
1721 return 0
1730 return 0
1722
1731
1723 def select(ui, repo, *args, **opts):
1732 def select(ui, repo, *args, **opts):
1724 '''set or print guarded patches to push
1733 '''set or print guarded patches to push
1725
1734
1726 use qguard command to set or print guards on patch. then use
1735 use qguard command to set or print guards on patch. then use
1727 qselect to tell mq which guards to use. example:
1736 qselect to tell mq which guards to use. example:
1728
1737
1729 qguard foo.patch -stable (nagative guard)
1738 qguard foo.patch -stable (nagative guard)
1730 qguard bar.patch +stable (posative guard)
1739 qguard bar.patch +stable (posative guard)
1731 qselect stable
1740 qselect stable
1732
1741
1733 this sets "stable" guard. mq will skip foo.patch (because it has
1742 this sets "stable" guard. mq will skip foo.patch (because it has
1734 nagative match) but push bar.patch (because it has posative
1743 nagative match) but push bar.patch (because it has posative
1735 match). patch is pushed if any posative guards match and no
1744 match). patch is pushed if any posative guards match and no
1736 nagative guards match.
1745 nagative guards match.
1737
1746
1738 with no arguments, default is to print current active guards.
1747 with no arguments, default is to print current active guards.
1739 with arguments, set active guards as given.
1748 with arguments, set active guards as given.
1740
1749
1741 use -n/--none to deactivate guards (no other arguments needed).
1750 use -n/--none to deactivate guards (no other arguments needed).
1742 when no guards active, patches with posative guards are skipped,
1751 when no guards active, patches with posative guards are skipped,
1743 patches with nagative guards are pushed.
1752 patches with nagative guards are pushed.
1744
1753
1745 qselect can change guards of applied patches. it does not pop
1754 qselect can change guards of applied patches. it does not pop
1746 guarded patches by default. use --pop to pop back to last applied
1755 guarded patches by default. use --pop to pop back to last applied
1747 patch that is not guarded. use --reapply (implies --pop) to push
1756 patch that is not guarded. use --reapply (implies --pop) to push
1748 back to current patch afterwards, but skip guarded patches.
1757 back to current patch afterwards, but skip guarded patches.
1749
1758
1750 use -s/--series to print list of all guards in series file (no
1759 use -s/--series to print list of all guards in series file (no
1751 other arguments needed). use -v for more information.'''
1760 other arguments needed). use -v for more information.'''
1752
1761
1753 q = repo.mq
1762 q = repo.mq
1754 guards = q.active()
1763 guards = q.active()
1755 if args or opts['none']:
1764 if args or opts['none']:
1756 old_unapplied = q.unapplied(repo)
1765 old_unapplied = q.unapplied(repo)
1757 old_guarded = [i for i in xrange(len(q.applied)) if
1766 old_guarded = [i for i in xrange(len(q.applied)) if
1758 not q.pushable(i)[0]]
1767 not q.pushable(i)[0]]
1759 q.set_active(args)
1768 q.set_active(args)
1760 q.save_dirty()
1769 q.save_dirty()
1761 if not args:
1770 if not args:
1762 ui.status(_('guards deactivated\n'))
1771 ui.status(_('guards deactivated\n'))
1763 if not opts['pop'] and not opts['reapply']:
1772 if not opts['pop'] and not opts['reapply']:
1764 unapplied = q.unapplied(repo)
1773 unapplied = q.unapplied(repo)
1765 guarded = [i for i in xrange(len(q.applied))
1774 guarded = [i for i in xrange(len(q.applied))
1766 if not q.pushable(i)[0]]
1775 if not q.pushable(i)[0]]
1767 if len(unapplied) != len(old_unapplied):
1776 if len(unapplied) != len(old_unapplied):
1768 ui.status(_('number of unguarded, unapplied patches has '
1777 ui.status(_('number of unguarded, unapplied patches has '
1769 'changed from %d to %d\n') %
1778 'changed from %d to %d\n') %
1770 (len(old_unapplied), len(unapplied)))
1779 (len(old_unapplied), len(unapplied)))
1771 if len(guarded) != len(old_guarded):
1780 if len(guarded) != len(old_guarded):
1772 ui.status(_('number of guarded, applied patches has changed '
1781 ui.status(_('number of guarded, applied patches has changed '
1773 'from %d to %d\n') %
1782 'from %d to %d\n') %
1774 (len(old_guarded), len(guarded)))
1783 (len(old_guarded), len(guarded)))
1775 elif opts['series']:
1784 elif opts['series']:
1776 guards = {}
1785 guards = {}
1777 noguards = 0
1786 noguards = 0
1778 for gs in q.series_guards:
1787 for gs in q.series_guards:
1779 if not gs:
1788 if not gs:
1780 noguards += 1
1789 noguards += 1
1781 for g in gs:
1790 for g in gs:
1782 guards.setdefault(g, 0)
1791 guards.setdefault(g, 0)
1783 guards[g] += 1
1792 guards[g] += 1
1784 if ui.verbose:
1793 if ui.verbose:
1785 guards['NONE'] = noguards
1794 guards['NONE'] = noguards
1786 guards = guards.items()
1795 guards = guards.items()
1787 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
1796 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
1788 if guards:
1797 if guards:
1789 ui.note(_('guards in series file:\n'))
1798 ui.note(_('guards in series file:\n'))
1790 for guard, count in guards:
1799 for guard, count in guards:
1791 ui.note('%2d ' % count)
1800 ui.note('%2d ' % count)
1792 ui.write(guard, '\n')
1801 ui.write(guard, '\n')
1793 else:
1802 else:
1794 ui.note(_('no guards in series file\n'))
1803 ui.note(_('no guards in series file\n'))
1795 else:
1804 else:
1796 if guards:
1805 if guards:
1797 ui.note(_('active guards:\n'))
1806 ui.note(_('active guards:\n'))
1798 for g in guards:
1807 for g in guards:
1799 ui.write(g, '\n')
1808 ui.write(g, '\n')
1800 else:
1809 else:
1801 ui.write(_('no active guards\n'))
1810 ui.write(_('no active guards\n'))
1802 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
1811 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
1803 popped = False
1812 popped = False
1804 if opts['pop'] or opts['reapply']:
1813 if opts['pop'] or opts['reapply']:
1805 for i in xrange(len(q.applied)):
1814 for i in xrange(len(q.applied)):
1806 pushable, reason = q.pushable(i)
1815 pushable, reason = q.pushable(i)
1807 if not pushable:
1816 if not pushable:
1808 ui.status(_('popping guarded patches\n'))
1817 ui.status(_('popping guarded patches\n'))
1809 popped = True
1818 popped = True
1810 if i == 0:
1819 if i == 0:
1811 q.pop(repo, all=True)
1820 q.pop(repo, all=True)
1812 else:
1821 else:
1813 q.pop(repo, i-1)
1822 q.pop(repo, i-1)
1814 break
1823 break
1815 if popped:
1824 if popped:
1816 try:
1825 try:
1817 if reapply:
1826 if reapply:
1818 ui.status(_('reapplying unguarded patches\n'))
1827 ui.status(_('reapplying unguarded patches\n'))
1819 q.push(repo, reapply)
1828 q.push(repo, reapply)
1820 finally:
1829 finally:
1821 q.save_dirty()
1830 q.save_dirty()
1822
1831
1823 def reposetup(ui, repo):
1832 def reposetup(ui, repo):
1824 class mqrepo(repo.__class__):
1833 class mqrepo(repo.__class__):
1825 def abort_if_wdir_patched(self, errmsg, force=False):
1834 def abort_if_wdir_patched(self, errmsg, force=False):
1826 if self.mq.applied and not force:
1835 if self.mq.applied and not force:
1827 parent = revlog.hex(self.dirstate.parents()[0])
1836 parent = revlog.hex(self.dirstate.parents()[0])
1828 if parent in [s.rev for s in self.mq.applied]:
1837 if parent in [s.rev for s in self.mq.applied]:
1829 raise util.Abort(errmsg)
1838 raise util.Abort(errmsg)
1830
1839
1831 def commit(self, *args, **opts):
1840 def commit(self, *args, **opts):
1832 if len(args) >= 6:
1841 if len(args) >= 6:
1833 force = args[5]
1842 force = args[5]
1834 else:
1843 else:
1835 force = opts.get('force')
1844 force = opts.get('force')
1836 self.abort_if_wdir_patched(
1845 self.abort_if_wdir_patched(
1837 _('cannot commit over an applied mq patch'),
1846 _('cannot commit over an applied mq patch'),
1838 force)
1847 force)
1839
1848
1840 return super(mqrepo, self).commit(*args, **opts)
1849 return super(mqrepo, self).commit(*args, **opts)
1841
1850
1842 def push(self, remote, force=False, revs=None):
1851 def push(self, remote, force=False, revs=None):
1843 if self.mq.applied and not force:
1852 if self.mq.applied and not force:
1844 raise util.Abort(_('source has mq patches applied'))
1853 raise util.Abort(_('source has mq patches applied'))
1845 return super(mqrepo, self).push(remote, force, revs)
1854 return super(mqrepo, self).push(remote, force, revs)
1846
1855
1847 def tags(self):
1856 def tags(self):
1848 if self.tagscache:
1857 if self.tagscache:
1849 return self.tagscache
1858 return self.tagscache
1850
1859
1851 tagscache = super(mqrepo, self).tags()
1860 tagscache = super(mqrepo, self).tags()
1852
1861
1853 q = self.mq
1862 q = self.mq
1854 if not q.applied:
1863 if not q.applied:
1855 return tagscache
1864 return tagscache
1856
1865
1857 mqtags = [(patch.rev, patch.name) for patch in q.applied]
1866 mqtags = [(patch.rev, patch.name) for patch in q.applied]
1858 mqtags.append((mqtags[-1][0], 'qtip'))
1867 mqtags.append((mqtags[-1][0], 'qtip'))
1859 mqtags.append((mqtags[0][0], 'qbase'))
1868 mqtags.append((mqtags[0][0], 'qbase'))
1860 for patch in mqtags:
1869 for patch in mqtags:
1861 if patch[1] in tagscache:
1870 if patch[1] in tagscache:
1862 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
1871 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1])
1863 else:
1872 else:
1864 tagscache[patch[1]] = revlog.bin(patch[0])
1873 tagscache[patch[1]] = revlog.bin(patch[0])
1865
1874
1866 return tagscache
1875 return tagscache
1867
1876
1868 if repo.local():
1877 if repo.local():
1869 repo.__class__ = mqrepo
1878 repo.__class__ = mqrepo
1870 repo.mq = queue(ui, repo.join(""))
1879 repo.mq = queue(ui, repo.join(""))
1871
1880
1872 cmdtable = {
1881 cmdtable = {
1873 "qapplied": (applied, [], 'hg qapplied [PATCH]'),
1882 "qapplied": (applied, [], 'hg qapplied [PATCH]'),
1874 "qclone": (clone,
1883 "qclone": (clone,
1875 [('', 'pull', None, _('use pull protocol to copy metadata')),
1884 [('', 'pull', None, _('use pull protocol to copy metadata')),
1876 ('U', 'noupdate', None, _('do not update the new working directories')),
1885 ('U', 'noupdate', None, _('do not update the new working directories')),
1877 ('', 'uncompressed', None,
1886 ('', 'uncompressed', None,
1878 _('use uncompressed transfer (fast over LAN)')),
1887 _('use uncompressed transfer (fast over LAN)')),
1879 ('e', 'ssh', '', _('specify ssh command to use')),
1888 ('e', 'ssh', '', _('specify ssh command to use')),
1880 ('p', 'patches', '', _('location of source patch repo')),
1889 ('p', 'patches', '', _('location of source patch repo')),
1881 ('', 'remotecmd', '',
1890 ('', 'remotecmd', '',
1882 _('specify hg command to run on the remote side'))],
1891 _('specify hg command to run on the remote side'))],
1883 'hg qclone [OPTION]... SOURCE [DEST]'),
1892 'hg qclone [OPTION]... SOURCE [DEST]'),
1884 "qcommit|qci":
1893 "qcommit|qci":
1885 (commit,
1894 (commit,
1886 commands.table["^commit|ci"][1],
1895 commands.table["^commit|ci"][1],
1887 'hg qcommit [OPTION]... [FILE]...'),
1896 'hg qcommit [OPTION]... [FILE]...'),
1888 "^qdiff": (diff,
1897 "^qdiff": (diff,
1889 [('I', 'include', [], _('include names matching the given patterns')),
1898 [('I', 'include', [], _('include names matching the given patterns')),
1890 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
1899 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
1891 'hg qdiff [-I] [-X] [FILE]...'),
1900 'hg qdiff [-I] [-X] [FILE]...'),
1892 "qdelete|qremove|qrm":
1901 "qdelete|qremove|qrm":
1893 (delete,
1902 (delete,
1894 [('k', 'keep', None, _('keep patch file'))],
1903 [('k', 'keep', None, _('keep patch file'))],
1895 'hg qdelete [-k] PATCH'),
1904 'hg qdelete [-k] PATCH'),
1896 'qfold':
1905 'qfold':
1897 (fold,
1906 (fold,
1898 [('e', 'edit', None, _('edit patch header')),
1907 [('e', 'edit', None, _('edit patch header')),
1899 ('k', 'keep', None, _('keep folded patch files')),
1908 ('k', 'keep', None, _('keep folded patch files')),
1900 ('m', 'message', '', _('set patch header to <text>')),
1909 ('m', 'message', '', _('set patch header to <text>')),
1901 ('l', 'logfile', '', _('set patch header to contents of <file>'))],
1910 ('l', 'logfile', '', _('set patch header to contents of <file>'))],
1902 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
1911 'hg qfold [-e] [-m <text>] [-l <file] PATCH...'),
1903 'qguard': (guard, [('l', 'list', None, _('list all patches and guards')),
1912 'qguard': (guard, [('l', 'list', None, _('list all patches and guards')),
1904 ('n', 'none', None, _('drop all guards'))],
1913 ('n', 'none', None, _('drop all guards'))],
1905 'hg qguard [PATCH] [+GUARD...] [-GUARD...]'),
1914 'hg qguard [PATCH] [+GUARD...] [-GUARD...]'),
1906 'qheader': (header, [],
1915 'qheader': (header, [],
1907 _('hg qheader [PATCH]')),
1916 _('hg qheader [PATCH]')),
1908 "^qimport":
1917 "^qimport":
1909 (qimport,
1918 (qimport,
1910 [('e', 'existing', None, 'import file in patch dir'),
1919 [('e', 'existing', None, 'import file in patch dir'),
1911 ('n', 'name', '', 'patch file name'),
1920 ('n', 'name', '', 'patch file name'),
1912 ('f', 'force', None, 'overwrite existing files')],
1921 ('f', 'force', None, 'overwrite existing files')],
1913 'hg qimport [-e] [-n NAME] [-f] FILE...'),
1922 'hg qimport [-e] [-n NAME] [-f] FILE...'),
1914 "^qinit":
1923 "^qinit":
1915 (init,
1924 (init,
1916 [('c', 'create-repo', None, 'create queue repository')],
1925 [('c', 'create-repo', None, 'create queue repository')],
1917 'hg qinit [-c]'),
1926 'hg qinit [-c]'),
1918 "qnew":
1927 "qnew":
1919 (new,
1928 (new,
1920 [('m', 'message', '', _('use <text> as commit message')),
1929 [('m', 'message', '', _('use <text> as commit message')),
1921 ('l', 'logfile', '', _('read the commit message from <file>')),
1930 ('l', 'logfile', '', _('read the commit message from <file>')),
1922 ('f', 'force', None, _('import uncommitted changes into patch'))],
1931 ('f', 'force', None, _('import uncommitted changes into patch'))],
1923 'hg qnew [-m TEXT] [-l FILE] [-f] PATCH'),
1932 'hg qnew [-m TEXT] [-l FILE] [-f] PATCH'),
1924 "qnext": (next, [], 'hg qnext'),
1933 "qnext": (next, [], 'hg qnext'),
1925 "qprev": (prev, [], 'hg qprev'),
1934 "qprev": (prev, [], 'hg qprev'),
1926 "^qpop":
1935 "^qpop":
1927 (pop,
1936 (pop,
1928 [('a', 'all', None, 'pop all patches'),
1937 [('a', 'all', None, 'pop all patches'),
1929 ('n', 'name', '', 'queue name to pop'),
1938 ('n', 'name', '', 'queue name to pop'),
1930 ('f', 'force', None, 'forget any local changes')],
1939 ('f', 'force', None, 'forget any local changes')],
1931 'hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]'),
1940 'hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]'),
1932 "^qpush":
1941 "^qpush":
1933 (push,
1942 (push,
1934 [('f', 'force', None, 'apply if the patch has rejects'),
1943 [('f', 'force', None, 'apply if the patch has rejects'),
1935 ('l', 'list', None, 'list patch name in commit text'),
1944 ('l', 'list', None, 'list patch name in commit text'),
1936 ('a', 'all', None, 'apply all patches'),
1945 ('a', 'all', None, 'apply all patches'),
1937 ('m', 'merge', None, 'merge from another queue'),
1946 ('m', 'merge', None, 'merge from another queue'),
1938 ('n', 'name', '', 'merge queue name')],
1947 ('n', 'name', '', 'merge queue name')],
1939 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'),
1948 'hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]'),
1940 "^qrefresh":
1949 "^qrefresh":
1941 (refresh,
1950 (refresh,
1942 [('e', 'edit', None, _('edit commit message')),
1951 [('e', 'edit', None, _('edit commit message')),
1943 ('m', 'message', '', _('change commit message with <text>')),
1952 ('m', 'message', '', _('change commit message with <text>')),
1944 ('l', 'logfile', '', _('change commit message with <file> content')),
1953 ('l', 'logfile', '', _('change commit message with <file> content')),
1945 ('s', 'short', None, 'short refresh')],
1954 ('s', 'short', None, 'short refresh'),
1946 'hg qrefresh [-e] [-m TEXT] [-l FILE] [-s]'),
1955 ('I', 'include', [], _('include names matching the given patterns')),
1956 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
1957 'hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] FILES...'),
1947 'qrename|qmv':
1958 'qrename|qmv':
1948 (rename, [], 'hg qrename PATCH1 [PATCH2]'),
1959 (rename, [], 'hg qrename PATCH1 [PATCH2]'),
1949 "qrestore":
1960 "qrestore":
1950 (restore,
1961 (restore,
1951 [('d', 'delete', None, 'delete save entry'),
1962 [('d', 'delete', None, 'delete save entry'),
1952 ('u', 'update', None, 'update queue working dir')],
1963 ('u', 'update', None, 'update queue working dir')],
1953 'hg qrestore [-d] [-u] REV'),
1964 'hg qrestore [-d] [-u] REV'),
1954 "qsave":
1965 "qsave":
1955 (save,
1966 (save,
1956 [('m', 'message', '', _('use <text> as commit message')),
1967 [('m', 'message', '', _('use <text> as commit message')),
1957 ('l', 'logfile', '', _('read the commit message from <file>')),
1968 ('l', 'logfile', '', _('read the commit message from <file>')),
1958 ('c', 'copy', None, 'copy patch directory'),
1969 ('c', 'copy', None, 'copy patch directory'),
1959 ('n', 'name', '', 'copy directory name'),
1970 ('n', 'name', '', 'copy directory name'),
1960 ('e', 'empty', None, 'clear queue status file'),
1971 ('e', 'empty', None, 'clear queue status file'),
1961 ('f', 'force', None, 'force copy')],
1972 ('f', 'force', None, 'force copy')],
1962 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
1973 'hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]'),
1963 "qselect": (select,
1974 "qselect": (select,
1964 [('n', 'none', None, _('disable all guards')),
1975 [('n', 'none', None, _('disable all guards')),
1965 ('s', 'series', None, _('list all guards in series file')),
1976 ('s', 'series', None, _('list all guards in series file')),
1966 ('', 'pop', None,
1977 ('', 'pop', None,
1967 _('pop to before first guarded applied patch')),
1978 _('pop to before first guarded applied patch')),
1968 ('', 'reapply', None, _('pop, then reapply patches'))],
1979 ('', 'reapply', None, _('pop, then reapply patches'))],
1969 'hg qselect [OPTION...] [GUARD...]'),
1980 'hg qselect [OPTION...] [GUARD...]'),
1970 "qseries":
1981 "qseries":
1971 (series,
1982 (series,
1972 [('m', 'missing', None, 'print patches not in series'),
1983 [('m', 'missing', None, 'print patches not in series'),
1973 ('s', 'summary', None, _('print first line of patch header'))],
1984 ('s', 'summary', None, _('print first line of patch header'))],
1974 'hg qseries [-m]'),
1985 'hg qseries [-m]'),
1975 "^strip":
1986 "^strip":
1976 (strip,
1987 (strip,
1977 [('f', 'force', None, 'force multi-head removal'),
1988 [('f', 'force', None, 'force multi-head removal'),
1978 ('b', 'backup', None, 'bundle unrelated changesets'),
1989 ('b', 'backup', None, 'bundle unrelated changesets'),
1979 ('n', 'nobackup', None, 'no backups')],
1990 ('n', 'nobackup', None, 'no backups')],
1980 'hg strip [-f] [-b] [-n] REV'),
1991 'hg strip [-f] [-b] [-n] REV'),
1981 "qtop": (top, [], 'hg qtop'),
1992 "qtop": (top, [], 'hg qtop'),
1982 "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
1993 "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
1983 }
1994 }
General Comments 0
You need to be logged in to leave comments. Login now