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