comparison mercurial/commands.py @ 11337:0f3c8a47960e

debugbuilddag: build a changelog dag from a concise description Useful in tests to quickly build a complex DAG in an empty repo. Handles local tags and named branches. Options to, at each rev, - create a new file, - overwrite the same file, - append to the same file, - write to a specific line in a mergeable file. Can run shell commands during DAG buildup.
author Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
date Thu, 10 Jun 2010 11:49:48 +0200
parents 3dfbe26cfded
children 285bcf40e04b
comparison
equal deleted inserted replaced
11336:3dfbe26cfded 11337:0f3c8a47960e
846 lookup = repo.lookup 846 lookup = repo.lookup
847 else: 847 else:
848 raise util.Abort(_('either two or three arguments required')) 848 raise util.Abort(_('either two or three arguments required'))
849 a = r.ancestor(lookup(rev1), lookup(rev2)) 849 a = r.ancestor(lookup(rev1), lookup(rev2))
850 ui.write("%d:%s\n" % (r.rev(a), hex(a))) 850 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
851
852 def debugbuilddag(ui, repo, text,
853 mergeable_file=False,
854 appended_file=False,
855 overwritten_file=False,
856 new_file=False):
857 """builds a repo with a given dag from scratch in the current empty repo
858
859 Elements:
860
861 - "+n" is a linear run of n nodes based on the current default parent
862 - "." is a single node based on the current default parent
863 - "$" resets the default parent to null (implied at the start);
864 otherwise the default parent is always the last node created
865 - "<p" sets the default parent to the backref p
866 - "*p" is a fork at parent p, which is a backref
867 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
868 - "/p2" is a merge of the preceding node and p2
869 - ":tag" defines a local tag for the preceding node
870 - "@branch" sets the named branch for subsequent nodes
871 - "!command" runs the command using your shell
872 - "!!my command\\n" is like "!", but to the end of the line
873 - "#...\\n" is a comment up to the end of the line
874
875 Whitespace between the above elements is ignored.
876
877 A backref is either
878
879 - a number n, which references the node curr-n, where curr is the current
880 node, or
881 - the name of a local tag you placed earlier using ":tag", or
882 - empty to denote the default parent.
883
884 All string valued-elements are either strictly alphanumeric, or must
885 be enclosed in double quotes ("..."), with "\" as escape character.
886
887 Note that the --overwritten-file and --appended-file options imply the
888 use of "HGMERGE=internal:local" during DAG buildup.
889 """
890
891 if not (mergeable_file or appended_file or overwritten_file or new_file):
892 raise Exception(_('need at least one of -m, -a, -o, -n'))
893
894 if len(repo.changelog) > 0:
895 raise Exception(_('repository is not empty'))
896
897 if overwritten_file or appended_file:
898 # we don't want to fail in merges during buildup
899 os.environ['HGMERGE'] = 'internal:local'
900
901 def writefile(fname, text, fmode="w"):
902 f = open(fname, fmode)
903 try:
904 f.write(text)
905 finally:
906 f.close()
907
908 if mergeable_file:
909 linesperrev = 2
910 # determine number of revs in DAG
911 n = 0
912 for type, data in dagparser.parsedag(text):
913 if type == 'n':
914 n += 1
915 # make a file with k lines per rev
916 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
917 + "\n")
918
919 at = -1
920 atbranch = 'default'
921 for type, data in dagparser.parsedag(text):
922 if type == 'n':
923 ui.status('node %s\n' % format(data))
924 id, ps = data
925 p1 = ps[0]
926 if p1 != at:
927 update(ui, repo, node=p1, clean=True)
928 at = p1
929 if repo.dirstate.branch() != atbranch:
930 branch(ui, repo, atbranch, force=True)
931 if len(ps) > 1:
932 p2 = ps[1]
933 merge(ui, repo, node=p2)
934
935 if mergeable_file:
936 f = open("mf", "r+")
937 try:
938 lines = f.read().split("\n")
939 lines[id * linesperrev] += " r%i" % id
940 f.seek(0)
941 f.write("\n".join(lines))
942 finally:
943 f.close()
944
945 if appended_file:
946 writefile("af", "r%i\n" % id, "a")
947
948 if overwritten_file:
949 writefile("of", "r%i\n" % id)
950
951 if new_file:
952 writefile("nf%i" % id, "r%i\n" % id)
953
954 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
955 at = id
956 elif type == 'l':
957 id, name = data
958 ui.status('tag %s\n' % name)
959 tag(ui, repo, name, local=True)
960 elif type == 'a':
961 ui.status('branch %s\n' % data)
962 atbranch = data
963 elif type in 'cC':
964 r = util.system(data, cwd=repo.root)
965 if r:
966 desc, r = util.explain_exit(r)
967 raise util.Abort(_('%s command %s') % (data, desc))
851 968
852 def debugcommands(ui, cmd='', *args): 969 def debugcommands(ui, cmd='', *args):
853 """list all available commands and options""" 970 """list all available commands and options"""
854 for cmd, vals in sorted(table.iteritems()): 971 for cmd, vals in sorted(table.iteritems()):
855 cmd = cmd.split('|')[0].strip('^') 972 cmd = cmd.split('|')[0].strip('^')
3921 ('f', 'force', None, 4038 ('f', 'force', None,
3922 _('forcibly copy over an existing managed file')), 4039 _('forcibly copy over an existing managed file')),
3923 ] + walkopts + dryrunopts, 4040 ] + walkopts + dryrunopts,
3924 _('[OPTION]... [SOURCE]... DEST')), 4041 _('[OPTION]... [SOURCE]... DEST')),
3925 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')), 4042 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4043 "debugbuilddag":
4044 (debugbuilddag,
4045 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4046 ('a', 'appended-file', None, _('add single file all revs append to')),
4047 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4048 ('n', 'new-file', None, _('add new file at each rev')),
4049 ],
4050 _('[OPTION]... TEXT')),
3926 "debugcheckstate": (debugcheckstate, [], ''), 4051 "debugcheckstate": (debugcheckstate, [], ''),
3927 "debugcommands": (debugcommands, [], _('[COMMAND]')), 4052 "debugcommands": (debugcommands, [], _('[COMMAND]')),
3928 "debugcomplete": 4053 "debugcomplete":
3929 (debugcomplete, 4054 (debugcomplete,
3930 [('o', 'options', None, _('show the command options'))], 4055 [('o', 'options', None, _('show the command options'))],