36 from mercurial import ui, hg, revlog, commands, util |
36 from mercurial import ui, hg, revlog, commands, util |
37 |
37 |
38 versionstr = "0.45" |
38 versionstr = "0.45" |
39 |
39 |
40 commands.norepo += " qclone qversion" |
40 commands.norepo += " qclone qversion" |
|
41 |
|
42 class StatusEntry: |
|
43 def __init__(self, rev, name=None): |
|
44 if not name: |
|
45 self.rev, self.name = rev.split(':') |
|
46 else: |
|
47 self.rev, self.name = rev, name |
|
48 |
|
49 def __str__(self): |
|
50 return self.rev + ':' + self.name |
41 |
51 |
42 class queue: |
52 class queue: |
43 def __init__(self, ui, path, patchdir=None): |
53 def __init__(self, ui, path, patchdir=None): |
44 self.basepath = path |
54 self.basepath = path |
45 if patchdir: |
55 if patchdir: |
58 if os.path.exists(os.path.join(self.path, self.series_path)): |
68 if os.path.exists(os.path.join(self.path, self.series_path)): |
59 self.full_series = self.opener(self.series_path).read().splitlines() |
69 self.full_series = self.opener(self.series_path).read().splitlines() |
60 self.read_series(self.full_series) |
70 self.read_series(self.full_series) |
61 |
71 |
62 if os.path.exists(os.path.join(self.path, self.status_path)): |
72 if os.path.exists(os.path.join(self.path, self.status_path)): |
63 self.applied = self.opener(self.status_path).read().splitlines() |
73 self.applied = [StatusEntry(l) |
|
74 for l in self.opener(self.status_path).read().splitlines()] |
64 |
75 |
65 def find_series(self, patch): |
76 def find_series(self, patch): |
66 pre = re.compile("(\s*)([^#]+)") |
77 pre = re.compile("(\s*)([^#]+)") |
67 index = 0 |
78 index = 0 |
68 for l in self.full_series: |
79 for l in self.full_series: |
93 if len(self.applied) > 0: |
104 if len(self.applied) > 0: |
94 nl = "\n" |
105 nl = "\n" |
95 else: |
106 else: |
96 nl = "" |
107 nl = "" |
97 f = self.opener(self.status_path, "w") |
108 f = self.opener(self.status_path, "w") |
98 f.write("\n".join(self.applied) + nl) |
109 f.write("\n".join([str(x) for x in self.applied]) + nl) |
99 if self.series_dirty: |
110 if self.series_dirty: |
100 if len(self.full_series) > 0: |
111 if len(self.full_series) > 0: |
101 nl = "\n" |
112 nl = "\n" |
102 else: |
113 else: |
103 nl = "" |
114 nl = "" |
220 (p1, p2) = repo.dirstate.parents() |
231 (p1, p2) = repo.dirstate.parents() |
221 if p2 == revlog.nullid: |
232 if p2 == revlog.nullid: |
222 return p1 |
233 return p1 |
223 if len(self.applied) == 0: |
234 if len(self.applied) == 0: |
224 return None |
235 return None |
225 (top, patch) = self.applied[-1].split(':') |
236 return revlog.bin(self.applied[-1].rev) |
226 top = revlog.bin(top) |
|
227 return top |
|
228 pp = repo.changelog.parents(rev) |
237 pp = repo.changelog.parents(rev) |
229 if pp[1] != revlog.nullid: |
238 if pp[1] != revlog.nullid: |
230 arevs = [ x.split(':')[0] for x in self.applied ] |
239 arevs = [ x.rev for x in self.applied ] |
231 p0 = revlog.hex(pp[0]) |
240 p0 = revlog.hex(pp[0]) |
232 p1 = revlog.hex(pp[1]) |
241 p1 = revlog.hex(pp[1]) |
233 if p0 in arevs: |
242 if p0 in arevs: |
234 return pp[0] |
243 return pp[0] |
235 if p1 in arevs: |
244 if p1 in arevs: |
245 # the first patch in the queue is never a merge patch |
254 # the first patch in the queue is never a merge patch |
246 # |
255 # |
247 pname = ".hg.patches.merge.marker" |
256 pname = ".hg.patches.merge.marker" |
248 n = repo.commit(None, '[mq]: merge marker', user=None, force=1, |
257 n = repo.commit(None, '[mq]: merge marker', user=None, force=1, |
249 wlock=wlock) |
258 wlock=wlock) |
250 self.applied.append(revlog.hex(n) + ":" + pname) |
259 self.applied.append(StatusEntry(revlog.hex(n), pname)) |
251 self.applied_dirty = 1 |
260 self.applied_dirty = 1 |
252 |
261 |
253 head = self.qparents(repo) |
262 head = self.qparents(repo) |
254 |
263 |
255 for patch in series: |
264 for patch in series: |
263 self.ui.warn("patch %s is not applied\n" % patch) |
272 self.ui.warn("patch %s is not applied\n" % patch) |
264 return (1, None) |
273 return (1, None) |
265 rev = revlog.bin(info[1]) |
274 rev = revlog.bin(info[1]) |
266 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock) |
275 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock) |
267 if head: |
276 if head: |
268 self.applied.append(revlog.hex(head) + ":" + patch) |
277 self.applied.append(StatusEntry(revlog.hex(head), patch)) |
269 self.applied_dirty = 1 |
278 self.applied_dirty = 1 |
270 if err: |
279 if err: |
271 return (err, head) |
280 return (err, head) |
272 return (0, head) |
281 return (0, head) |
273 |
282 |
400 self.read_series(self.full_series) |
409 self.read_series(self.full_series) |
401 self.series_dirty = 1 |
410 self.series_dirty = 1 |
402 |
411 |
403 def check_toppatch(self, repo): |
412 def check_toppatch(self, repo): |
404 if len(self.applied) > 0: |
413 if len(self.applied) > 0: |
405 (top, patch) = self.applied[-1].split(':') |
414 top = revlog.bin(self.applied[-1].rev) |
406 top = revlog.bin(top) |
|
407 pp = repo.dirstate.parents() |
415 pp = repo.dirstate.parents() |
408 if top not in pp: |
416 if top not in pp: |
409 raise util.Abort(_("queue top not at same revision as working directory")) |
417 raise util.Abort(_("queue top not at same revision as working directory")) |
410 return top |
418 return top |
411 return None |
419 return None |
432 n = repo.commit(commitfiles, |
440 n = repo.commit(commitfiles, |
433 "New patch: %s" % patch, force=True, wlock=wlock) |
441 "New patch: %s" % patch, force=True, wlock=wlock) |
434 if n == None: |
442 if n == None: |
435 raise util.Abort(_("repo commit failed")) |
443 raise util.Abort(_("repo commit failed")) |
436 self.full_series[insert:insert] = [patch] |
444 self.full_series[insert:insert] = [patch] |
437 self.applied.append(revlog.hex(n) + ":" + patch) |
445 self.applied.append(StatusEntry(revlog.hex(n), patch)) |
438 self.read_series(self.full_series) |
446 self.read_series(self.full_series) |
439 self.series_dirty = 1 |
447 self.series_dirty = 1 |
440 self.applied_dirty = 1 |
448 self.applied_dirty = 1 |
441 p = self.opener(patch, "w") |
449 p = self.opener(patch, "w") |
442 if msg: |
450 if msg: |
598 os.unlink(chgrpfile) |
606 os.unlink(chgrpfile) |
599 |
607 |
600 def isapplied(self, patch): |
608 def isapplied(self, patch): |
601 """returns (index, rev, patch)""" |
609 """returns (index, rev, patch)""" |
602 for i in xrange(len(self.applied)): |
610 for i in xrange(len(self.applied)): |
603 p = self.applied[i] |
611 a = self.applied[i] |
604 a = p.split(':') |
612 if a.name == patch: |
605 if a[1] == patch: |
613 return (i, a.rev, a.name) |
606 return (i, a[0], a[1]) |
|
607 return None |
614 return None |
608 |
615 |
609 # if the exact patch name does not exist, we try a few |
616 # if the exact patch name does not exist, we try a few |
610 # variations. If strict is passed, we try only #1 |
617 # variations. If strict is passed, we try only #1 |
611 # |
618 # |
704 s = self.series[start:end] |
711 s = self.series[start:end] |
705 if mergeq: |
712 if mergeq: |
706 ret = self.mergepatch(repo, mergeq, s, wlock) |
713 ret = self.mergepatch(repo, mergeq, s, wlock) |
707 else: |
714 else: |
708 ret = self.apply(repo, s, list, wlock=wlock) |
715 ret = self.apply(repo, s, list, wlock=wlock) |
709 top = self.applied[-1].split(':')[1] |
716 top = self.applied[-1].name |
710 if ret[0]: |
717 if ret[0]: |
711 self.ui.write("Errors during apply, please fix and refresh %s\n" % |
718 self.ui.write("Errors during apply, please fix and refresh %s\n" % |
712 top) |
719 top) |
713 else: |
720 else: |
714 self.ui.write("Now at: %s\n" % top) |
721 self.ui.write("Now at: %s\n" % top) |
762 else: |
769 else: |
763 popi = info[0] + 1 |
770 popi = info[0] + 1 |
764 if popi >= end: |
771 if popi >= end: |
765 self.ui.warn("qpop: %s is already at the top\n" % patch) |
772 self.ui.warn("qpop: %s is already at the top\n" % patch) |
766 return |
773 return |
767 info = [ popi ] + self.applied[popi].split(':') |
774 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name] |
768 |
775 |
769 start = info[0] |
776 start = info[0] |
770 rev = revlog.bin(info[1]) |
777 rev = revlog.bin(info[1]) |
771 |
778 |
772 # we know there are no local changes, so we can make a simplified |
779 # we know there are no local changes, so we can make a simplified |
795 repo.dirstate.forget(a) |
802 repo.dirstate.forget(a) |
796 repo.dirstate.setparents(qp, revlog.nullid) |
803 repo.dirstate.setparents(qp, revlog.nullid) |
797 self.strip(repo, rev, update=False, backup='strip', wlock=wlock) |
804 self.strip(repo, rev, update=False, backup='strip', wlock=wlock) |
798 del self.applied[start:end] |
805 del self.applied[start:end] |
799 if len(self.applied): |
806 if len(self.applied): |
800 self.ui.write("Now at: %s\n" % self.applied[-1].split(':')[1]) |
807 self.ui.write("Now at: %s\n" % self.applied[-1].name) |
801 else: |
808 else: |
802 self.ui.write("Patch queue now empty\n") |
809 self.ui.write("Patch queue now empty\n") |
803 |
810 |
804 def diff(self, repo, files): |
811 def diff(self, repo, files): |
805 top = self.check_toppatch(repo) |
812 top = self.check_toppatch(repo) |
814 self.ui.write("No patches applied\n") |
821 self.ui.write("No patches applied\n") |
815 return |
822 return |
816 wlock = repo.wlock() |
823 wlock = repo.wlock() |
817 self.check_toppatch(repo) |
824 self.check_toppatch(repo) |
818 qp = self.qparents(repo) |
825 qp = self.qparents(repo) |
819 (top, patch) = self.applied[-1].split(':') |
826 (top, patch) = (self.applied[-1].rev, self.applied[-1].name) |
820 top = revlog.bin(top) |
827 top = revlog.bin(top) |
821 cparents = repo.changelog.parents(top) |
828 cparents = repo.changelog.parents(top) |
822 patchparent = self.qparents(repo, top) |
829 patchparent = self.qparents(repo, top) |
823 message, comments, user, date, patchfound = self.readheaders(patch) |
830 message, comments, user, date, patchfound = self.readheaders(patch) |
824 |
831 |
910 else: |
917 else: |
911 message = msg |
918 message = msg |
912 |
919 |
913 self.strip(repo, top, update=False, backup='strip', wlock=wlock) |
920 self.strip(repo, top, update=False, backup='strip', wlock=wlock) |
914 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) |
921 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) |
915 self.applied[-1] = revlog.hex(n) + ':' + patch |
922 self.applied[-1] = StatusEntry(revlog.hex(n), patch) |
916 self.applied_dirty = 1 |
923 self.applied_dirty = 1 |
917 else: |
924 else: |
918 commands.dodiff(patchf, self.ui, repo, patchparent, None) |
925 commands.dodiff(patchf, self.ui, repo, patchparent, None) |
919 patchf.close() |
926 patchf.close() |
920 self.pop(repo, force=True, wlock=wlock) |
927 self.pop(repo, force=True, wlock=wlock) |
998 l = lines[i].rstrip() |
1005 l = lines[i].rstrip() |
999 l = l[10:].split(' ') |
1006 l = l[10:].split(' ') |
1000 qpp = [ hg.bin(x) for x in l ] |
1007 qpp = [ hg.bin(x) for x in l ] |
1001 elif datastart != None: |
1008 elif datastart != None: |
1002 l = lines[i].rstrip() |
1009 l = lines[i].rstrip() |
1003 index = l.index(':') |
1010 se = StatusEntry(l) |
1004 id = l[:index] |
1011 id = se.rev |
1005 file = l[index + 1:] |
1012 file = se.name |
1006 if id: |
1013 if id: |
1007 applied.append(l) |
1014 applied.append(se) |
1008 series.append(file) |
1015 series.append(file) |
1009 if datastart == None: |
1016 if datastart == None: |
1010 self.ui.warn("No saved patch data found\n") |
1017 self.ui.warn("No saved patch data found\n") |
1011 return 1 |
1018 return 1 |
1012 self.ui.warn("restoring status: %s\n" % lines[0]) |
1019 self.ui.warn("restoring status: %s\n" % lines[0]) |
1054 r = self.qrepo() |
1061 r = self.qrepo() |
1055 if r: |
1062 if r: |
1056 pp = r.dirstate.parents() |
1063 pp = r.dirstate.parents() |
1057 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1])) |
1064 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1])) |
1058 msg += "\n\nPatch Data:\n" |
1065 msg += "\n\nPatch Data:\n" |
1059 text = msg + "\n".join(self.applied) + '\n' + (ar and "\n".join(ar) |
1066 text = msg + "\n".join(str(self.applied)) + '\n' + (ar and "\n".join(ar) |
1060 + '\n' or "") |
1067 + '\n' or "") |
1061 n = repo.commit(None, text, user=None, force=1) |
1068 n = repo.commit(None, text, user=None, force=1) |
1062 if not n: |
1069 if not n: |
1063 self.ui.warn("repo commit failed\n") |
1070 self.ui.warn("repo commit failed\n") |
1064 return 1 |
1071 return 1 |
1065 self.applied.append(revlog.hex(n) + ":" + '.hg.patches.save.line') |
1072 self.applied.append(StatusEntry(revlog.hex(n),'.hg.patches.save.line')) |
1066 self.applied_dirty = 1 |
1073 self.applied_dirty = 1 |
1067 |
1074 |
1068 def full_series_end(self): |
1075 def full_series_end(self): |
1069 if len(self.applied) > 0: |
1076 if len(self.applied) > 0: |
1070 (top, p) = self.applied[-1].split(':') |
1077 p = self.applied[-1].name |
1071 end = self.find_series(p) |
1078 end = self.find_series(p) |
1072 if end == None: |
1079 if end == None: |
1073 return len(self.full_series) |
1080 return len(self.full_series) |
1074 return end + 1 |
1081 return end + 1 |
1075 return 0 |
1082 return 0 |
1076 |
1083 |
1077 def series_end(self): |
1084 def series_end(self): |
1078 end = 0 |
1085 end = 0 |
1079 if len(self.applied) > 0: |
1086 if len(self.applied) > 0: |
1080 (top, p) = self.applied[-1].split(':') |
1087 p = self.applied[-1].name |
1081 try: |
1088 try: |
1082 end = self.series.index(p) |
1089 end = self.series.index(p) |
1083 except ValueError: |
1090 except ValueError: |
1084 return 0 |
1091 return 0 |
1085 return end + 1 |
1092 return end + 1 |
1095 for x in xrange(end): |
1102 for x in xrange(end): |
1096 p = self.appliedname(x) |
1103 p = self.appliedname(x) |
1097 self.ui.write("%s\n" % p) |
1104 self.ui.write("%s\n" % p) |
1098 |
1105 |
1099 def appliedname(self, index): |
1106 def appliedname(self, index): |
1100 p = self.applied[index] |
1107 pname = self.applied[index].name |
1101 pname = p.split(':')[1] |
|
1102 if not self.ui.verbose: |
1108 if not self.ui.verbose: |
1103 p = pname |
1109 p = pname |
1104 else: |
1110 else: |
1105 p = str(self.series.index(pname)) + " " + p |
1111 p = str(self.series.index(pname)) + " " + p |
1106 return p |
1112 return p |
1234 sr = hg.repository(ui, ui.expandpath(source)) |
1240 sr = hg.repository(ui, ui.expandpath(source)) |
1235 qbase, destrev = None, None |
1241 qbase, destrev = None, None |
1236 if sr.local(): |
1242 if sr.local(): |
1237 reposetup(ui, sr) |
1243 reposetup(ui, sr) |
1238 if sr.mq.applied: |
1244 if sr.mq.applied: |
1239 qbase = revlog.bin(sr.mq.applied[0].split(':')[0]) |
1245 qbase = revlog.bin(sr.mq.applied[0].rev) |
1240 if not hg.islocal(dest): |
1246 if not hg.islocal(dest): |
1241 destrev = sr.parents(qbase)[0] |
1247 destrev = sr.parents(qbase)[0] |
1242 ui.note(_('cloning main repo\n')) |
1248 ui.note(_('cloning main repo\n')) |
1243 sr, dr = hg.clone(ui, sr, dest, |
1249 sr, dr = hg.clone(ui, sr, dest, |
1244 pull=opts['pull'], |
1250 pull=opts['pull'], |
1312 q = repo.mq |
1318 q = repo.mq |
1313 message=commands.logmessage(**opts) |
1319 message=commands.logmessage(**opts) |
1314 if opts['edit']: |
1320 if opts['edit']: |
1315 if message: |
1321 if message: |
1316 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) |
1322 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) |
1317 patch = q.applied[-1].split(':')[1] |
1323 patch = q.applied[-1].name |
1318 (message, comment, user, date, hasdiff) = q.readheaders(patch) |
1324 (message, comment, user, date, hasdiff) = q.readheaders(patch) |
1319 message = ui.edit('\n'.join(message), user or ui.username()) |
1325 message = ui.edit('\n'.join(message), user or ui.username()) |
1320 q.refresh(repo, msg=message, short=opts['short']) |
1326 q.refresh(repo, msg=message, short=opts['short']) |
1321 q.save_dirty() |
1327 q.save_dirty() |
1322 return 0 |
1328 return 0 |
1490 q.read_series(q.full_series) |
1496 q.read_series(q.full_series) |
1491 q.series_dirty = 1 |
1497 q.series_dirty = 1 |
1492 |
1498 |
1493 info = q.isapplied(patch) |
1499 info = q.isapplied(patch) |
1494 if info: |
1500 if info: |
1495 q.applied[info[0]] = info[1] + ':' + name |
1501 q.applied[info[0]] = StatusEntry(info[1], name) |
1496 q.applied_dirty = 1 |
1502 q.applied_dirty = 1 |
1497 |
1503 |
1498 util.rename(os.path.join(q.path, patch), absdest) |
1504 util.rename(os.path.join(q.path, patch), absdest) |
1499 r = q.qrepo() |
1505 r = q.qrepo() |
1500 if r: |
1506 if r: |
1571 |
1577 |
1572 q = self.mq |
1578 q = self.mq |
1573 if not q.applied: |
1579 if not q.applied: |
1574 return tagscache |
1580 return tagscache |
1575 |
1581 |
1576 mqtags = [patch.split(':') for patch in q.applied] |
1582 mqtags = [(patch.rev, patch.name) for patch in q.applied] |
1577 mqtags.append((mqtags[-1][0], 'qtip')) |
1583 mqtags.append((mqtags[-1][0], 'qtip')) |
1578 mqtags.append((mqtags[0][0], 'qbase')) |
1584 mqtags.append((mqtags[0][0], 'qbase')) |
1579 for patch in mqtags: |
1585 for patch in mqtags: |
1580 if patch[1] in tagscache: |
1586 if patch[1] in tagscache: |
1581 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1]) |
1587 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1]) |