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