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.parse_series() |
70 self.parse_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: |
86 def write_list(items, path): |
97 def write_list(items, path): |
87 fp = self.opener(path, 'w') |
98 fp = self.opener(path, 'w') |
88 for i in items: |
99 for i in items: |
89 print >> fp, i |
100 print >> fp, i |
90 fp.close() |
101 fp.close() |
91 if self.applied_dirty: write_list(self.applied, self.status_path) |
102 if self.applied_dirty: write_list(map(str, self.applied), self.status_path) |
92 if self.series_dirty: write_list(self.full_series, self.series_path) |
103 if self.series_dirty: write_list(self.full_series, self.series_path) |
93 |
104 |
94 def readheaders(self, patch): |
105 def readheaders(self, patch): |
95 def eatdiff(lines): |
106 def eatdiff(lines): |
96 while lines: |
107 while lines: |
207 (p1, p2) = repo.dirstate.parents() |
218 (p1, p2) = repo.dirstate.parents() |
208 if p2 == revlog.nullid: |
219 if p2 == revlog.nullid: |
209 return p1 |
220 return p1 |
210 if len(self.applied) == 0: |
221 if len(self.applied) == 0: |
211 return None |
222 return None |
212 (top, patch) = self.applied[-1].split(':') |
223 return revlog.bin(self.applied[-1].rev) |
213 top = revlog.bin(top) |
|
214 return top |
|
215 pp = repo.changelog.parents(rev) |
224 pp = repo.changelog.parents(rev) |
216 if pp[1] != revlog.nullid: |
225 if pp[1] != revlog.nullid: |
217 arevs = [ x.split(':')[0] for x in self.applied ] |
226 arevs = [ x.rev for x in self.applied ] |
218 p0 = revlog.hex(pp[0]) |
227 p0 = revlog.hex(pp[0]) |
219 p1 = revlog.hex(pp[1]) |
228 p1 = revlog.hex(pp[1]) |
220 if p0 in arevs: |
229 if p0 in arevs: |
221 return pp[0] |
230 return pp[0] |
222 if p1 in arevs: |
231 if p1 in arevs: |
232 # the first patch in the queue is never a merge patch |
241 # the first patch in the queue is never a merge patch |
233 # |
242 # |
234 pname = ".hg.patches.merge.marker" |
243 pname = ".hg.patches.merge.marker" |
235 n = repo.commit(None, '[mq]: merge marker', user=None, force=1, |
244 n = repo.commit(None, '[mq]: merge marker', user=None, force=1, |
236 wlock=wlock) |
245 wlock=wlock) |
237 self.applied.append(revlog.hex(n) + ":" + pname) |
246 self.applied.append(StatusEntry(revlog.hex(n), pname)) |
238 self.applied_dirty = 1 |
247 self.applied_dirty = 1 |
239 |
248 |
240 head = self.qparents(repo) |
249 head = self.qparents(repo) |
241 |
250 |
242 for patch in series: |
251 for patch in series: |
250 self.ui.warn("patch %s is not applied\n" % patch) |
259 self.ui.warn("patch %s is not applied\n" % patch) |
251 return (1, None) |
260 return (1, None) |
252 rev = revlog.bin(info[1]) |
261 rev = revlog.bin(info[1]) |
253 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock) |
262 (err, head) = self.mergeone(repo, mergeq, head, patch, rev, wlock) |
254 if head: |
263 if head: |
255 self.applied.append(revlog.hex(head) + ":" + patch) |
264 self.applied.append(StatusEntry(revlog.hex(head), patch)) |
256 self.applied_dirty = 1 |
265 self.applied_dirty = 1 |
257 if err: |
266 if err: |
258 return (err, head) |
267 return (err, head) |
259 return (0, head) |
268 return (0, head) |
260 |
269 |
261 def patch(self, repo, patchfile): |
270 def patch(self, repo, patchfile): |
262 '''Apply patchfile to the working directory. |
271 '''Apply patchfile to the working directory. |
263 patchfile: file name of patch''' |
272 patchfile: file name of patch''' |
264 try: |
273 try: |
265 pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') |
274 pp = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch') |
266 f = os.popen("%s -d '%s' -p1 --no-backup-if-mismatch < '%s'" % |
275 f = os.popen("%s -d %s -p1 --no-backup-if-mismatch < %s" % |
267 (pp, repo.root, patchfile)) |
276 (pp, util.shellquote(repo.root), util.shellquote(patchfile))) |
268 except: |
277 except: |
269 self.ui.warn("patch failed, unable to continue (try -v)\n") |
278 self.ui.warn("patch failed, unable to continue (try -v)\n") |
270 return (None, [], False) |
279 return (None, [], False) |
271 files = [] |
280 files = [] |
272 fuzz = False |
281 fuzz = False |
273 for l in f: |
282 for l in f: |
274 l = l.rstrip('\r\n'); |
283 l = l.rstrip('\r\n'); |
275 if self.ui.verbose: |
284 if self.ui.verbose: |
276 self.ui.warn(l + "\n") |
285 self.ui.warn(l + "\n") |
277 if l[:14] == 'patching file ': |
286 if l[:14] == 'patching file ': |
278 pf = os.path.normpath(l[14:]) |
287 pf = os.path.normpath(util.parse_patch_output(l)) |
279 # when patch finds a space in the file name, it puts |
|
280 # single quotes around the filename. strip them off |
|
281 if pf[0] == "'" and pf[-1] == "'": |
|
282 pf = pf[1:-1] |
|
283 if pf not in files: |
288 if pf not in files: |
284 files.append(pf) |
289 files.append(pf) |
285 printed_file = False |
290 printed_file = False |
286 file_str = l |
291 file_str = l |
287 elif l.find('with fuzz') >= 0: |
292 elif l.find('with fuzz') >= 0: |
387 self.parse_series() |
392 self.parse_series() |
388 self.series_dirty = 1 |
393 self.series_dirty = 1 |
389 |
394 |
390 def check_toppatch(self, repo): |
395 def check_toppatch(self, repo): |
391 if len(self.applied) > 0: |
396 if len(self.applied) > 0: |
392 (top, patch) = self.applied[-1].split(':') |
397 top = revlog.bin(self.applied[-1].rev) |
393 top = revlog.bin(top) |
|
394 pp = repo.dirstate.parents() |
398 pp = repo.dirstate.parents() |
395 if top not in pp: |
399 if top not in pp: |
396 raise util.Abort(_("queue top not at same revision as working directory")) |
400 raise util.Abort(_("queue top not at same revision as working directory")) |
397 return top |
401 return top |
398 return None |
402 return None |
419 n = repo.commit(commitfiles, |
423 n = repo.commit(commitfiles, |
420 "New patch: %s" % patch, force=True, wlock=wlock) |
424 "New patch: %s" % patch, force=True, wlock=wlock) |
421 if n == None: |
425 if n == None: |
422 raise util.Abort(_("repo commit failed")) |
426 raise util.Abort(_("repo commit failed")) |
423 self.full_series[insert:insert] = [patch] |
427 self.full_series[insert:insert] = [patch] |
424 self.applied.append(revlog.hex(n) + ":" + patch) |
428 self.applied.append(StatusEntry(revlog.hex(n), patch)) |
425 self.parse_series() |
429 self.parse_series() |
426 self.series_dirty = 1 |
430 self.series_dirty = 1 |
427 self.applied_dirty = 1 |
431 self.applied_dirty = 1 |
428 p = self.opener(patch, "w") |
432 p = self.opener(patch, "w") |
429 if msg: |
433 if msg: |
499 filerev = 0 |
503 filerev = 0 |
500 seen[f] = filerev |
504 seen[f] = filerev |
501 # we go in two steps here so the strip loop happens in a |
505 # we go in two steps here so the strip loop happens in a |
502 # sensible order. When stripping many files, this helps keep |
506 # sensible order. When stripping many files, this helps keep |
503 # our disk access patterns under control. |
507 # our disk access patterns under control. |
504 list = seen.keys() |
508 seen_list = seen.keys() |
505 list.sort() |
509 seen_list.sort() |
506 for f in list: |
510 for f in seen_list: |
507 ff = repo.file(f) |
511 ff = repo.file(f) |
508 filerev = seen[f] |
512 filerev = seen[f] |
509 if filerev != 0: |
513 if filerev != 0: |
510 if filerev in ff.nodemap: |
514 if filerev in ff.nodemap: |
511 filerev = ff.rev(filerev) |
515 filerev = ff.rev(filerev) |
533 # that we actually want to keep. changegroup will be used |
537 # that we actually want to keep. changegroup will be used |
534 # to preserve them and add them back after the truncate |
538 # to preserve them and add them back after the truncate |
535 saveheads = [] |
539 saveheads = [] |
536 savebases = {} |
540 savebases = {} |
537 |
541 |
538 tip = chlog.tip() |
|
539 heads = limitheads(chlog, rev) |
542 heads = limitheads(chlog, rev) |
540 seen = {} |
543 seen = {} |
541 |
544 |
542 # search through all the heads, finding those where the revision |
545 # search through all the heads, finding those where the revision |
543 # we want to strip away is an ancestor. Also look for merges |
546 # we want to strip away is an ancestor. Also look for merges |
564 for x in r: |
567 for x in r: |
565 if chlog.rev(x) > revnum: |
568 if chlog.rev(x) > revnum: |
566 savebases[x] = 1 |
569 savebases[x] = 1 |
567 |
570 |
568 # create a changegroup for all the branches we need to keep |
571 # create a changegroup for all the branches we need to keep |
569 if backup is "all": |
572 if backup == "all": |
570 backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip') |
573 backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip') |
571 bundle(backupch) |
574 bundle(backupch) |
572 if saveheads: |
575 if saveheads: |
573 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip') |
576 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip') |
574 chgrpfile = bundle(backupch) |
577 chgrpfile = bundle(backupch) |
579 repo.manifest.strip(repo.manifest.rev(change[0]), revnum) |
582 repo.manifest.strip(repo.manifest.rev(change[0]), revnum) |
580 chlog.strip(revnum, revnum) |
583 chlog.strip(revnum, revnum) |
581 if saveheads: |
584 if saveheads: |
582 self.ui.status("adding branch\n") |
585 self.ui.status("adding branch\n") |
583 commands.unbundle(self.ui, repo, chgrpfile, update=False) |
586 commands.unbundle(self.ui, repo, chgrpfile, update=False) |
584 if backup is not "strip": |
587 if backup != "strip": |
585 os.unlink(chgrpfile) |
588 os.unlink(chgrpfile) |
586 |
589 |
587 def isapplied(self, patch): |
590 def isapplied(self, patch): |
588 """returns (index, rev, patch)""" |
591 """returns (index, rev, patch)""" |
589 for i in xrange(len(self.applied)): |
592 for i in xrange(len(self.applied)): |
590 p = self.applied[i] |
593 a = self.applied[i] |
591 a = p.split(':') |
594 if a.name == patch: |
592 if a[1] == patch: |
595 return (i, a.rev, a.name) |
593 return (i, a[0], a[1]) |
|
594 return None |
596 return None |
595 |
597 |
596 # if the exact patch name does not exist, we try a few |
598 # if the exact patch name does not exist, we try a few |
597 # variations. If strict is passed, we try only #1 |
599 # variations. If strict is passed, we try only #1 |
598 # |
600 # |
691 s = self.series[start:end] |
693 s = self.series[start:end] |
692 if mergeq: |
694 if mergeq: |
693 ret = self.mergepatch(repo, mergeq, s, wlock) |
695 ret = self.mergepatch(repo, mergeq, s, wlock) |
694 else: |
696 else: |
695 ret = self.apply(repo, s, list, wlock=wlock) |
697 ret = self.apply(repo, s, list, wlock=wlock) |
696 top = self.applied[-1].split(':')[1] |
698 top = self.applied[-1].name |
697 if ret[0]: |
699 if ret[0]: |
698 self.ui.write("Errors during apply, please fix and refresh %s\n" % |
700 self.ui.write("Errors during apply, please fix and refresh %s\n" % |
699 top) |
701 top) |
700 else: |
702 else: |
701 self.ui.write("Now at: %s\n" % top) |
703 self.ui.write("Now at: %s\n" % top) |
782 repo.dirstate.forget(a) |
784 repo.dirstate.forget(a) |
783 repo.dirstate.setparents(qp, revlog.nullid) |
785 repo.dirstate.setparents(qp, revlog.nullid) |
784 self.strip(repo, rev, update=False, backup='strip', wlock=wlock) |
786 self.strip(repo, rev, update=False, backup='strip', wlock=wlock) |
785 del self.applied[start:end] |
787 del self.applied[start:end] |
786 if len(self.applied): |
788 if len(self.applied): |
787 self.ui.write("Now at: %s\n" % self.applied[-1].split(':')[1]) |
789 self.ui.write("Now at: %s\n" % self.applied[-1].name) |
788 else: |
790 else: |
789 self.ui.write("Patch queue now empty\n") |
791 self.ui.write("Patch queue now empty\n") |
790 |
792 |
791 def diff(self, repo, files): |
793 def diff(self, repo, files): |
792 top = self.check_toppatch(repo) |
794 top = self.check_toppatch(repo) |
800 if len(self.applied) == 0: |
802 if len(self.applied) == 0: |
801 self.ui.write("No patches applied\n") |
803 self.ui.write("No patches applied\n") |
802 return |
804 return |
803 wlock = repo.wlock() |
805 wlock = repo.wlock() |
804 self.check_toppatch(repo) |
806 self.check_toppatch(repo) |
805 qp = self.qparents(repo) |
807 (top, patch) = (self.applied[-1].rev, self.applied[-1].name) |
806 (top, patch) = self.applied[-1].split(':') |
|
807 top = revlog.bin(top) |
808 top = revlog.bin(top) |
808 cparents = repo.changelog.parents(top) |
809 cparents = repo.changelog.parents(top) |
809 patchparent = self.qparents(repo, top) |
810 patchparent = self.qparents(repo, top) |
810 message, comments, user, date, patchfound = self.readheaders(patch) |
811 message, comments, user, date, patchfound = self.readheaders(patch) |
811 |
812 |
897 else: |
898 else: |
898 message = msg |
899 message = msg |
899 |
900 |
900 self.strip(repo, top, update=False, backup='strip', wlock=wlock) |
901 self.strip(repo, top, update=False, backup='strip', wlock=wlock) |
901 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) |
902 n = repo.commit(filelist, message, changes[1], force=1, wlock=wlock) |
902 self.applied[-1] = revlog.hex(n) + ':' + patch |
903 self.applied[-1] = StatusEntry(revlog.hex(n), patch) |
903 self.applied_dirty = 1 |
904 self.applied_dirty = 1 |
904 else: |
905 else: |
905 commands.dodiff(patchf, self.ui, repo, patchparent, None) |
906 commands.dodiff(patchf, self.ui, repo, patchparent, None) |
906 patchf.close() |
907 patchf.close() |
907 self.pop(repo, force=True, wlock=wlock) |
908 self.pop(repo, force=True, wlock=wlock) |
919 raise util.Abort(_("patch %s is not in series file") % patch) |
920 raise util.Abort(_("patch %s is not in series file") % patch) |
920 if not patch: |
921 if not patch: |
921 start = self.series_end() |
922 start = self.series_end() |
922 else: |
923 else: |
923 start = self.series.index(patch) + 1 |
924 start = self.series.index(patch) + 1 |
924 for p in self.series[start:]: |
925 return [(i, self.series[i]) for i in xrange(start, len(self.series))] |
925 if self.ui.verbose: |
|
926 self.ui.write("%d " % self.series.index(p)) |
|
927 self.ui.write("%s\n" % p) |
|
928 |
926 |
929 def qseries(self, repo, missing=None, summary=False): |
927 def qseries(self, repo, missing=None, summary=False): |
930 start = self.series_end() |
928 start = self.series_end() |
931 if not missing: |
929 if not missing: |
932 for i in range(len(self.series)): |
930 for i in range(len(self.series)): |
942 msg = msg and ': ' + msg[0] or ': ' |
940 msg = msg and ': ' + msg[0] or ': ' |
943 else: |
941 else: |
944 msg = '' |
942 msg = '' |
945 self.ui.write('%s%s\n' % (patch, msg)) |
943 self.ui.write('%s%s\n' % (patch, msg)) |
946 else: |
944 else: |
947 list = [] |
945 msng_list = [] |
948 for root, dirs, files in os.walk(self.path): |
946 for root, dirs, files in os.walk(self.path): |
949 d = root[len(self.path) + 1:] |
947 d = root[len(self.path) + 1:] |
950 for f in files: |
948 for f in files: |
951 fl = os.path.join(d, f) |
949 fl = os.path.join(d, f) |
952 if (fl not in self.series and |
950 if (fl not in self.series and |
953 fl not in (self.status_path, self.series_path) |
951 fl not in (self.status_path, self.series_path) |
954 and not fl.startswith('.')): |
952 and not fl.startswith('.')): |
955 list.append(fl) |
953 msng_list.append(fl) |
956 list.sort() |
954 msng_list.sort() |
957 if list: |
955 for x in msng_list: |
958 for x in list: |
956 if self.ui.verbose: |
959 if self.ui.verbose: |
957 self.ui.write("D ") |
960 self.ui.write("D ") |
958 self.ui.write("%s\n" % x) |
961 self.ui.write("%s\n" % x) |
|
962 |
959 |
963 def issaveline(self, l): |
960 def issaveline(self, l): |
964 name = l.split(':')[1] |
961 name = l.split(':')[1] |
965 if name == '.hg.patches.save.line': |
962 if name == '.hg.patches.save.line': |
966 return True |
963 return True |
985 l = lines[i].rstrip() |
982 l = lines[i].rstrip() |
986 l = l[10:].split(' ') |
983 l = l[10:].split(' ') |
987 qpp = [ hg.bin(x) for x in l ] |
984 qpp = [ hg.bin(x) for x in l ] |
988 elif datastart != None: |
985 elif datastart != None: |
989 l = lines[i].rstrip() |
986 l = lines[i].rstrip() |
990 index = l.index(':') |
987 se = StatusEntry(l) |
991 id = l[:index] |
988 file_ = se.name |
992 file = l[index + 1:] |
989 if se.rev: |
993 if id: |
990 applied.append(se) |
994 applied.append(l) |
991 series.append(file_) |
995 series.append(file) |
|
996 if datastart == None: |
992 if datastart == None: |
997 self.ui.warn("No saved patch data found\n") |
993 self.ui.warn("No saved patch data found\n") |
998 return 1 |
994 return 1 |
999 self.ui.warn("restoring status: %s\n" % lines[0]) |
995 self.ui.warn("restoring status: %s\n" % lines[0]) |
1000 self.full_series = series |
996 self.full_series = series |
1041 r = self.qrepo() |
1037 r = self.qrepo() |
1042 if r: |
1038 if r: |
1043 pp = r.dirstate.parents() |
1039 pp = r.dirstate.parents() |
1044 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1])) |
1040 msg += "\nDirstate: %s %s" % (hg.hex(pp[0]), hg.hex(pp[1])) |
1045 msg += "\n\nPatch Data:\n" |
1041 msg += "\n\nPatch Data:\n" |
1046 text = msg + "\n".join(self.applied) + '\n' + (ar and "\n".join(ar) |
1042 text = msg + "\n".join(str(self.applied)) + '\n' + (ar and "\n".join(ar) |
1047 + '\n' or "") |
1043 + '\n' or "") |
1048 n = repo.commit(None, text, user=None, force=1) |
1044 n = repo.commit(None, text, user=None, force=1) |
1049 if not n: |
1045 if not n: |
1050 self.ui.warn("repo commit failed\n") |
1046 self.ui.warn("repo commit failed\n") |
1051 return 1 |
1047 return 1 |
1052 self.applied.append(revlog.hex(n) + ":" + '.hg.patches.save.line') |
1048 self.applied.append(StatusEntry(revlog.hex(n),'.hg.patches.save.line')) |
1053 self.applied_dirty = 1 |
1049 self.applied_dirty = 1 |
1054 |
1050 |
1055 def full_series_end(self): |
1051 def full_series_end(self): |
1056 if len(self.applied) > 0: |
1052 if len(self.applied) > 0: |
1057 (top, p) = self.applied[-1].split(':') |
1053 p = self.applied[-1].name |
1058 end = self.find_series(p) |
1054 end = self.find_series(p) |
1059 if end == None: |
1055 if end == None: |
1060 return len(self.full_series) |
1056 return len(self.full_series) |
1061 return end + 1 |
1057 return end + 1 |
1062 return 0 |
1058 return 0 |
1063 |
1059 |
1064 def series_end(self): |
1060 def series_end(self): |
1065 end = 0 |
1061 end = 0 |
1066 if len(self.applied) > 0: |
1062 if len(self.applied) > 0: |
1067 (top, p) = self.applied[-1].split(':') |
1063 p = self.applied[-1].name |
1068 try: |
1064 try: |
1069 end = self.series.index(p) |
1065 end = self.series.index(p) |
1070 except ValueError: |
1066 except ValueError: |
1071 return 0 |
1067 return 0 |
1072 return end + 1 |
1068 return end + 1 |
1082 for x in xrange(end): |
1078 for x in xrange(end): |
1083 p = self.appliedname(x) |
1079 p = self.appliedname(x) |
1084 self.ui.write("%s\n" % p) |
1080 self.ui.write("%s\n" % p) |
1085 |
1081 |
1086 def appliedname(self, index): |
1082 def appliedname(self, index): |
1087 p = self.applied[index] |
1083 pname = self.applied[index].name |
1088 pname = p.split(':')[1] |
|
1089 if not self.ui.verbose: |
1084 if not self.ui.verbose: |
1090 p = pname |
1085 p = pname |
1091 else: |
1086 else: |
1092 p = str(self.series.index(pname)) + " " + p |
1087 p = str(self.series.index(pname)) + " " + p |
1093 return p |
1088 return p |
1171 repo.mq.qapplied(repo, patch) |
1166 repo.mq.qapplied(repo, patch) |
1172 return 0 |
1167 return 0 |
1173 |
1168 |
1174 def unapplied(ui, repo, patch=None, **opts): |
1169 def unapplied(ui, repo, patch=None, **opts): |
1175 """print the patches not yet applied""" |
1170 """print the patches not yet applied""" |
1176 repo.mq.unapplied(repo, patch) |
1171 for i, p in repo.mq.unapplied(repo, patch): |
1177 return 0 |
1172 if ui.verbose: |
|
1173 ui.write("%d " % i) |
|
1174 ui.write("%s\n" % p) |
1178 |
1175 |
1179 def qimport(ui, repo, *filename, **opts): |
1176 def qimport(ui, repo, *filename, **opts): |
1180 """import a patch""" |
1177 """import a patch""" |
1181 q = repo.mq |
1178 q = repo.mq |
1182 q.qimport(repo, filename, patch=opts['name'], |
1179 q.qimport(repo, filename, patch=opts['name'], |
1221 sr = hg.repository(ui, ui.expandpath(source)) |
1218 sr = hg.repository(ui, ui.expandpath(source)) |
1222 qbase, destrev = None, None |
1219 qbase, destrev = None, None |
1223 if sr.local(): |
1220 if sr.local(): |
1224 reposetup(ui, sr) |
1221 reposetup(ui, sr) |
1225 if sr.mq.applied: |
1222 if sr.mq.applied: |
1226 qbase = revlog.bin(sr.mq.applied[0].split(':')[0]) |
1223 qbase = revlog.bin(sr.mq.applied[0].rev) |
1227 if not hg.islocal(dest): |
1224 if not hg.islocal(dest): |
1228 destrev = sr.parents(qbase)[0] |
1225 destrev = sr.parents(qbase)[0] |
1229 ui.note(_('cloning main repo\n')) |
1226 ui.note(_('cloning main repo\n')) |
1230 sr, dr = hg.clone(ui, sr, dest, |
1227 sr, dr = hg.clone(ui, sr, dest, |
1231 pull=opts['pull'], |
1228 pull=opts['pull'], |
1284 |
1281 |
1285 -m or -l set the patch header as well as the commit message. |
1282 -m or -l set the patch header as well as the commit message. |
1286 If neither is specified, the patch header is empty and the |
1283 If neither is specified, the patch header is empty and the |
1287 commit message is 'New patch: PATCH'""" |
1284 commit message is 'New patch: PATCH'""" |
1288 q = repo.mq |
1285 q = repo.mq |
1289 message=commands.logmessage(**opts) |
1286 message = commands.logmessage(**opts) |
1290 q.new(repo, patch, msg=message, force=opts['force']) |
1287 q.new(repo, patch, msg=message, force=opts['force']) |
1291 q.save_dirty() |
1288 q.save_dirty() |
1292 return 0 |
1289 return 0 |
1293 |
1290 |
1294 def refresh(ui, repo, **opts): |
1291 def refresh(ui, repo, **opts): |
1295 """update the current patch""" |
1292 """update the current patch""" |
1296 q = repo.mq |
1293 q = repo.mq |
1297 message=commands.logmessage(**opts) |
1294 message = commands.logmessage(**opts) |
1298 if opts['edit']: |
1295 if opts['edit']: |
1299 if message: |
1296 if message: |
1300 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) |
1297 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) |
1301 patch = q.applied[-1].split(':')[1] |
1298 patch = q.applied[-1].name |
1302 (message, comment, user, date, hasdiff) = q.readheaders(patch) |
1299 (message, comment, user, date, hasdiff) = q.readheaders(patch) |
1303 message = ui.edit('\n'.join(message), user or ui.username()) |
1300 message = ui.edit('\n'.join(message), user or ui.username()) |
1304 q.refresh(repo, msg=message, short=opts['short']) |
1301 q.refresh(repo, msg=message, short=opts['short']) |
1305 q.save_dirty() |
1302 q.save_dirty() |
1306 return 0 |
1303 return 0 |
1329 if not files: |
1326 if not files: |
1330 raise util.Abort(_('qfold requires at least one patch name')) |
1327 raise util.Abort(_('qfold requires at least one patch name')) |
1331 if not q.check_toppatch(repo): |
1328 if not q.check_toppatch(repo): |
1332 raise util.Abort(_('No patches applied\n')) |
1329 raise util.Abort(_('No patches applied\n')) |
1333 |
1330 |
1334 message=commands.logmessage(**opts) |
1331 message = commands.logmessage(**opts) |
1335 if opts['edit']: |
1332 if opts['edit']: |
1336 if message: |
1333 if message: |
1337 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) |
1334 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"')) |
1338 |
1335 |
1339 parent = q.lookup('qtip') |
1336 parent = q.lookup('qtip') |
1340 patches = [] |
1337 patches = [] |
1341 messages = [] |
1338 messages = [] |
1342 for f in files: |
1339 for f in files: |
1343 patch = q.lookup(f) |
1340 patch = q.lookup(f) |
1344 if patch in patches or patch == parent: |
1341 if patch in patches or patch == parent: |
1345 self.ui.warn(_('Skipping already folded patch %s') % patch) |
1342 ui.warn(_('Skipping already folded patch %s') % patch) |
1346 if q.isapplied(patch): |
1343 if q.isapplied(patch): |
1347 raise util.Abort(_('qfold cannot fold already applied patch %s') % patch) |
1344 raise util.Abort(_('qfold cannot fold already applied patch %s') % patch) |
1348 patches.append(patch) |
1345 patches.append(patch) |
1349 |
1346 |
1350 for patch in patches: |
1347 for patch in patches: |
1386 message = repo.mq.readheaders(patch)[0] |
1383 message = repo.mq.readheaders(patch)[0] |
1387 |
1384 |
1388 ui.write('\n'.join(message) + '\n') |
1385 ui.write('\n'.join(message) + '\n') |
1389 |
1386 |
1390 def lastsavename(path): |
1387 def lastsavename(path): |
1391 (dir, base) = os.path.split(path) |
1388 (directory, base) = os.path.split(path) |
1392 names = os.listdir(dir) |
1389 names = os.listdir(directory) |
1393 namere = re.compile("%s.([0-9]+)" % base) |
1390 namere = re.compile("%s.([0-9]+)" % base) |
1394 max = None |
1391 maxindex = None |
1395 maxname = None |
1392 maxname = None |
1396 for f in names: |
1393 for f in names: |
1397 m = namere.match(f) |
1394 m = namere.match(f) |
1398 if m: |
1395 if m: |
1399 index = int(m.group(1)) |
1396 index = int(m.group(1)) |
1400 if max == None or index > max: |
1397 if maxindex == None or index > maxindex: |
1401 max = index |
1398 maxindex = index |
1402 maxname = f |
1399 maxname = f |
1403 if maxname: |
1400 if maxname: |
1404 return (os.path.join(dir, maxname), max) |
1401 return (os.path.join(directory, maxname), maxindex) |
1405 return (None, None) |
1402 return (None, None) |
1406 |
1403 |
1407 def savename(path): |
1404 def savename(path): |
1408 (last, index) = lastsavename(path) |
1405 (last, index) = lastsavename(path) |
1409 if last is None: |
1406 if last is None: |
1561 |
1558 |
1562 q = self.mq |
1559 q = self.mq |
1563 if not q.applied: |
1560 if not q.applied: |
1564 return tagscache |
1561 return tagscache |
1565 |
1562 |
1566 mqtags = [patch.split(':') for patch in q.applied] |
1563 mqtags = [(patch.rev, patch.name) for patch in q.applied] |
1567 mqtags.append((mqtags[-1][0], 'qtip')) |
1564 mqtags.append((mqtags[-1][0], 'qtip')) |
1568 mqtags.append((mqtags[0][0], 'qbase')) |
1565 mqtags.append((mqtags[0][0], 'qbase')) |
1569 for patch in mqtags: |
1566 for patch in mqtags: |
1570 if patch[1] in tagscache: |
1567 if patch[1] in tagscache: |
1571 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1]) |
1568 self.ui.warn('Tag %s overrides mq patch of the same name\n' % patch[1]) |