12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks |
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks |
13 import patch, help, url, encoding, templatekw, discovery |
13 import patch, help, url, encoding, templatekw, discovery |
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server |
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server |
15 import merge as mergemod |
15 import merge as mergemod |
16 import minirst, revset, templatefilters |
16 import minirst, revset, templatefilters |
17 import dagparser |
17 import dagparser, context, simplemerge |
18 |
18 |
19 # Commands start here, listed alphabetically |
19 # Commands start here, listed alphabetically |
20 |
20 |
21 def add(ui, repo, *pats, **opts): |
21 def add(ui, repo, *pats, **opts): |
22 """add the specified files on the next commit |
22 """add the specified files on the next commit |
992 - the name of a local tag you placed earlier using ":tag", or |
989 - the name of a local tag you placed earlier using ":tag", or |
993 - empty to denote the default parent. |
990 - empty to denote the default parent. |
994 |
991 |
995 All string valued-elements are either strictly alphanumeric, or must |
992 All string valued-elements are either strictly alphanumeric, or must |
996 be enclosed in double quotes ("..."), with "\\" as escape character. |
993 be enclosed in double quotes ("..."), with "\\" as escape character. |
997 |
994 """ |
998 Note that the --overwritten-file and --appended-file options imply the |
995 |
999 use of "HGMERGE=internal:local" during DAG buildup. |
996 cl = repo.changelog |
1000 """ |
997 if len(cl) > 0: |
1001 |
|
1002 if not (mergeable_file or appended_file or overwritten_file or new_file): |
|
1003 raise util.Abort(_('need at least one of -m, -a, -o, -n')) |
|
1004 |
|
1005 if len(repo.changelog) > 0: |
|
1006 raise util.Abort(_('repository is not empty')) |
998 raise util.Abort(_('repository is not empty')) |
1007 |
|
1008 if overwritten_file or appended_file: |
|
1009 # we don't want to fail in merges during buildup |
|
1010 os.environ['HGMERGE'] = 'internal:local' |
|
1011 |
|
1012 def writefile(fname, text, fmode="wb"): |
|
1013 f = open(fname, fmode) |
|
1014 try: |
|
1015 f.write(text) |
|
1016 finally: |
|
1017 f.close() |
|
1018 |
999 |
1019 if mergeable_file: |
1000 if mergeable_file: |
1020 linesperrev = 2 |
1001 linesperrev = 2 |
1021 # determine number of revs in DAG |
1002 # determine number of revs in DAG |
1022 n = 0 |
1003 n = 0 |
1023 for type, data in dagparser.parsedag(text): |
1004 for type, data in dagparser.parsedag(text): |
1024 if type == 'n': |
1005 if type == 'n': |
1025 n += 1 |
1006 n += 1 |
1026 # make a file with k lines per rev |
1007 # make a file with k lines per rev |
1027 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev)) |
1008 initialmergedlines = [str(i) for i in xrange(0, n * linesperrev)] |
1028 + "\n") |
1009 initialmergedlines.append("") |
1029 |
1010 |
1030 at = -1 |
1011 tags = [] |
1031 atbranch = 'default' |
1012 |
1032 for type, data in dagparser.parsedag(text): |
1013 tr = repo.transaction("builddag") |
1033 if type == 'n': |
1014 try: |
1034 ui.status('node %s\n' % str(data)) |
1015 |
1035 id, ps = data |
1016 at = -1 |
1036 p1 = ps[0] |
1017 atbranch = 'default' |
1037 if p1 != at: |
1018 nodeids = [] |
1038 update(ui, repo, node=str(p1), clean=True) |
1019 for type, data in dagparser.parsedag(text): |
1039 at = p1 |
1020 if type == 'n': |
1040 if repo.dirstate.branch() != atbranch: |
1021 ui.note('node %s\n' % str(data)) |
1041 branch(ui, repo, atbranch, force=True) |
1022 id, ps = data |
1042 if len(ps) > 1: |
1023 |
1043 p2 = ps[1] |
1024 files = [] |
1044 merge(ui, repo, node=p2) |
1025 fctxs = {} |
1045 |
1026 |
1046 if mergeable_file: |
1027 p2 = None |
1047 f = open("mf", "rb+") |
1028 if mergeable_file: |
1048 try: |
1029 fn = "mf" |
1049 lines = f.read().split("\n") |
1030 p1 = repo[ps[0]] |
1050 lines[id * linesperrev] += " r%i" % id |
1031 if len(ps) > 1: |
1051 f.seek(0) |
1032 p2 = repo[ps[1]] |
1052 f.write("\n".join(lines)) |
1033 pa = p1.ancestor(p2) |
1053 finally: |
1034 base, local, other = [x[fn].data() for x in pa, p1, p2] |
1054 f.close() |
1035 m3 = simplemerge.Merge3Text(base, local, other) |
1055 |
1036 ml = [l.strip() for l in m3.merge_lines()] |
1056 if appended_file: |
1037 ml.append("") |
1057 writefile("af", "r%i\n" % id, "ab") |
1038 elif at > 0: |
1058 |
1039 ml = p1[fn].data().split("\n") |
1059 if overwritten_file: |
1040 else: |
1060 writefile("of", "r%i\n" % id) |
1041 ml = initialmergedlines |
1061 |
1042 ml[id * linesperrev] += " r%i" % id |
1062 if new_file: |
1043 mergedtext = "\n".join(ml) |
1063 writefile("nf%i" % id, "r%i\n" % id) |
1044 files.append(fn) |
1064 |
1045 fctxs[fn] = context.memfilectx(fn, mergedtext) |
1065 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0)) |
1046 |
1066 at = id |
1047 if overwritten_file: |
1067 elif type == 'l': |
1048 fn = "of" |
1068 id, name = data |
1049 files.append(fn) |
1069 ui.status('tag %s\n' % name) |
1050 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id) |
1070 tag(ui, repo, name, local=True) |
1051 |
1071 elif type == 'a': |
1052 if new_file: |
1072 ui.status('branch %s\n' % data) |
1053 fn = "nf%i" % id |
1073 atbranch = data |
1054 files.append(fn) |
1074 elif type in 'cC': |
1055 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id) |
1075 r = util.system(data, cwd=repo.root) |
1056 if len(ps) > 1: |
1076 if r: |
1057 if not p2: |
1077 desc, r = util.explain_exit(r) |
1058 p2 = repo[ps[1]] |
1078 raise util.Abort(_('%s command %s') % (data, desc)) |
1059 for fn in p2: |
|
1060 if fn.startswith("nf"): |
|
1061 files.append(fn) |
|
1062 fctxs[fn] = p2[fn] |
|
1063 |
|
1064 def fctxfn(repo, cx, path): |
|
1065 return fctxs.get(path) |
|
1066 |
|
1067 if len(ps) == 0 or ps[0] < 0: |
|
1068 pars = [None, None] |
|
1069 elif len(ps) == 1: |
|
1070 pars = [nodeids[ps[0]], None] |
|
1071 else: |
|
1072 pars = [nodeids[p] for p in ps] |
|
1073 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn, |
|
1074 date=(id, 0), |
|
1075 user="debugbuilddag", |
|
1076 extra={'branch': atbranch}) |
|
1077 nodeid = repo.commitctx(cx) |
|
1078 nodeids.append(nodeid) |
|
1079 at = id |
|
1080 elif type == 'l': |
|
1081 id, name = data |
|
1082 ui.note('tag %s\n' % name) |
|
1083 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name)) |
|
1084 elif type == 'a': |
|
1085 ui.note('branch %s\n' % data) |
|
1086 atbranch = data |
|
1087 tr.close() |
|
1088 finally: |
|
1089 tr.release() |
|
1090 |
|
1091 if tags: |
|
1092 tagsf = repo.opener("localtags", "w") |
|
1093 try: |
|
1094 tagsf.write("".join(tags)) |
|
1095 finally: |
|
1096 tagsf.close() |
1079 |
1097 |
1080 def debugcommands(ui, cmd='', *args): |
1098 def debugcommands(ui, cmd='', *args): |
1081 """list all available commands and options""" |
1099 """list all available commands and options""" |
1082 for cmd, vals in sorted(table.iteritems()): |
1100 for cmd, vals in sorted(table.iteritems()): |
1083 cmd = cmd.split('|')[0].strip('^') |
1101 cmd = cmd.split('|')[0].strip('^') |
4465 _('[OPTION]... [SOURCE]... DEST')), |
4483 _('[OPTION]... [SOURCE]... DEST')), |
4466 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')), |
4484 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')), |
4467 "debugbuilddag": |
4485 "debugbuilddag": |
4468 (debugbuilddag, |
4486 (debugbuilddag, |
4469 [('m', 'mergeable-file', None, _('add single file mergeable changes')), |
4487 [('m', 'mergeable-file', None, _('add single file mergeable changes')), |
4470 ('a', 'appended-file', None, _('add single file all revs append to')), |
|
4471 ('o', 'overwritten-file', None, _('add single file all revs overwrite')), |
4488 ('o', 'overwritten-file', None, _('add single file all revs overwrite')), |
4472 ('n', 'new-file', None, _('add new file at each rev')), |
4489 ('n', 'new-file', None, _('add new file at each rev')), |
4473 ], |
4490 ], |
4474 _('[OPTION]... TEXT')), |
4491 _('[OPTION]... TEXT')), |
4475 "debugbundle": |
4492 "debugbundle": |