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