mercurial/commands.py
changeset 14163 38184a72d793
parent 14157 a8f136f430da
child 14164 cb98fed52495
equal deleted inserted replaced
14162:301725c3df9a 14163:38184a72d793
    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
   960     a = r.ancestor(lookup(rev1), lookup(rev2))
   960     a = r.ancestor(lookup(rev1), lookup(rev2))
   961     ui.write("%d:%s\n" % (r.rev(a), hex(a)))
   961     ui.write("%d:%s\n" % (r.rev(a), hex(a)))
   962 
   962 
   963 def debugbuilddag(ui, repo, text,
   963 def debugbuilddag(ui, repo, text,
   964                   mergeable_file=False,
   964                   mergeable_file=False,
   965                   appended_file=False,
       
   966                   overwritten_file=False,
   965                   overwritten_file=False,
   967                   new_file=False):
   966                   new_file=False):
   968     """builds a repo with a given dag from scratch in the current empty repo
   967     """builds a repo with a given dag from scratch in the current empty repo
   969 
   968 
   970     Elements:
   969     Elements:
   977      - "*p" is a fork at parent p, which is a backref
   976      - "*p" is a fork at parent p, which is a backref
   978      - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
   977      - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
   979      - "/p2" is a merge of the preceding node and p2
   978      - "/p2" is a merge of the preceding node and p2
   980      - ":tag" defines a local tag for the preceding node
   979      - ":tag" defines a local tag for the preceding node
   981      - "@branch" sets the named branch for subsequent nodes
   980      - "@branch" sets the named branch for subsequent nodes
   982      - "!command" runs the command using your shell
       
   983      - "!!my command\\n" is like "!", but to the end of the line
       
   984      - "#...\\n" is a comment up to the end of the line
   981      - "#...\\n" is a comment up to the end of the line
   985 
   982 
   986     Whitespace between the above elements is ignored.
   983     Whitespace between the above elements is ignored.
   987 
   984 
   988     A backref is either
   985     A backref is either
   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":