Added #INSERT parameter for batch-code processor. This should resolve the issue of wanting to combine several batch files. Also improved traceback feedback from the batch-code processor.
This commit is contained in:
parent
1ca8df9e70
commit
8b99b8a130
2 changed files with 68 additions and 20 deletions
|
|
@ -27,6 +27,10 @@
|
||||||
# debugging the script). E.g., if the code contains the command
|
# debugging the script). E.g., if the code contains the command
|
||||||
# myobj = create.create_object(...), you could put 'myobj' in the #CODE header
|
# myobj = create.create_object(...), you could put 'myobj' in the #CODE header
|
||||||
# regardless of what the created object is actually called in-game.
|
# regardless of what the created object is actually called in-game.
|
||||||
|
# #INSERT filename - this includes another code batch file. The named file will be loaded and
|
||||||
|
# run at this point. Note that code from the inserted file will NOT share #HEADERs
|
||||||
|
# with the importing file, but will only use the headers in the importing file.
|
||||||
|
# make sure to not create a cyclic import here!
|
||||||
|
|
||||||
# The following variable is automatically made available for the script:
|
# The following variable is automatically made available for the script:
|
||||||
|
|
||||||
|
|
@ -61,7 +65,6 @@ red_button = create.create_object(red_button.RedButton, key="Red button",
|
||||||
# we take a look at what we created
|
# we take a look at what we created
|
||||||
caller.msg("A %s was created." % red_button.key)
|
caller.msg("A %s was created." % red_button.key)
|
||||||
|
|
||||||
|
|
||||||
#CODE (create table and chair) table, chair
|
#CODE (create table and chair) table, chair
|
||||||
|
|
||||||
# this code block has 'table' and 'chair' set as deletable
|
# this code block has 'table' and 'chair' set as deletable
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,7 @@ script = create.create_script()
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import codecs
|
import codecs
|
||||||
|
import traceback, sys
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.management import setup_environ
|
from django.core.management import setup_environ
|
||||||
|
|
@ -302,6 +303,13 @@ class BatchCommandProcessor(object):
|
||||||
#
|
#
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
||||||
|
def tb_filename(tb):
|
||||||
|
"Helper to get filename from traceback"
|
||||||
|
return tb.tb_frame.f_code.co_filename
|
||||||
|
def tb_iter(tb):
|
||||||
|
while tb is not None:
|
||||||
|
yield tb
|
||||||
|
tb = tb.tb_next
|
||||||
|
|
||||||
class BatchCodeProcessor(object):
|
class BatchCodeProcessor(object):
|
||||||
"""
|
"""
|
||||||
|
|
@ -316,7 +324,8 @@ class BatchCodeProcessor(object):
|
||||||
|
|
||||||
1) Lines starting with #HEADER starts a header block (ends other blocks)
|
1) Lines starting with #HEADER starts a header block (ends other blocks)
|
||||||
2) Lines starting with #CODE begins a code block (ends other blocks)
|
2) Lines starting with #CODE begins a code block (ends other blocks)
|
||||||
3) #CODE headers may be of the following form: #CODE (info) objname, objname2, ...
|
3) #CODE headers may be of the following form: #CODE (info) objname, objname2, ...
|
||||||
|
4) Lines starting with #INSERT are on form #INSERT filename.
|
||||||
3) All lines outside blocks are stripped.
|
3) All lines outside blocks are stripped.
|
||||||
4) All excess whitespace beginning/ending a block is stripped.
|
4) All excess whitespace beginning/ending a block is stripped.
|
||||||
|
|
||||||
|
|
@ -332,6 +341,12 @@ class BatchCodeProcessor(object):
|
||||||
|
|
||||||
if parseline.startswith("#HEADER"):
|
if parseline.startswith("#HEADER"):
|
||||||
return ("header", "", "")
|
return ("header", "", "")
|
||||||
|
if parseline.startswith("#INSERT"):
|
||||||
|
filename = line.lstrip("#INSERT").strip()
|
||||||
|
if filename:
|
||||||
|
return ('insert', "", filename)
|
||||||
|
else:
|
||||||
|
return ('comment', "", "{r#INSERT <None>{n")
|
||||||
elif parseline.startswith("#CODE"):
|
elif parseline.startswith("#CODE"):
|
||||||
# parse code command
|
# parse code command
|
||||||
line = line.lstrip("#CODE").strip()
|
line = line.lstrip("#CODE").strip()
|
||||||
|
|
@ -368,7 +383,16 @@ class BatchCodeProcessor(object):
|
||||||
# print "::", in_header, in_code, mode, line.strip()
|
# print "::", in_header, in_code, mode, line.strip()
|
||||||
# except:
|
# except:
|
||||||
# print "::", in_header, in_code, mode, line
|
# print "::", in_header, in_code, mode, line
|
||||||
if mode == 'header':
|
if mode == 'insert':
|
||||||
|
# recursive load of inserted code files - note that we
|
||||||
|
# are not checking for cyclic imports!
|
||||||
|
in_header = False
|
||||||
|
in_code = False
|
||||||
|
inserted_codes = self.parse_file(line) or [{'objs':"", 'info':line, 'code':""}]
|
||||||
|
for codedict in inserted_codes:
|
||||||
|
codedict["inserted"] = True
|
||||||
|
codes.extend(inserted_codes)
|
||||||
|
elif mode == 'header':
|
||||||
in_header = True
|
in_header = True
|
||||||
in_code = False
|
in_code = False
|
||||||
elif mode == 'codeheader':
|
elif mode == 'codeheader':
|
||||||
|
|
@ -376,9 +400,7 @@ class BatchCodeProcessor(object):
|
||||||
in_code = True
|
in_code = True
|
||||||
# the line is a list of object variable names
|
# the line is a list of object variable names
|
||||||
# (or an empty list) at this point.
|
# (or an empty list) at this point.
|
||||||
codedict = {'objs':line,
|
codedict = {'objs':line, 'info':info, 'code':""}
|
||||||
'info':info,
|
|
||||||
'code':""}
|
|
||||||
codes.append(codedict)
|
codes.append(codedict)
|
||||||
elif mode == 'comment' and in_header:
|
elif mode == 'comment' and in_header:
|
||||||
continue
|
continue
|
||||||
|
|
@ -394,13 +416,21 @@ class BatchCodeProcessor(object):
|
||||||
|
|
||||||
# last, we merge the headers with all codes.
|
# last, we merge the headers with all codes.
|
||||||
for codedict in codes:
|
for codedict in codes:
|
||||||
objs = ", ".join(codedict["objs"])
|
#print "codedict:", codedict
|
||||||
if objs:
|
if codedict and "inserted" in codedict:
|
||||||
objs = "[%s]" % objs
|
# we don't need to merge code+header in this case
|
||||||
codedict["code"] = "#CODE %s %s \n%s\n\n%s" % (codedict['info'],
|
# since that was already added in the recursion. We
|
||||||
objs,
|
# just check for errors.
|
||||||
header.strip(),
|
if not codedict['code']:
|
||||||
codedict["code"].strip())
|
codedict['code'] = "{r#INSERT ERROR: %s{n" % codedict['info']
|
||||||
|
else:
|
||||||
|
objs = ", ".join(codedict["objs"])
|
||||||
|
if objs:
|
||||||
|
objs = "[%s]" % objs
|
||||||
|
codedict["code"] = "#CODE %s %s \n%s\n\n%s" % (codedict['info'],
|
||||||
|
objs,
|
||||||
|
header.strip(),
|
||||||
|
codedict["code"].strip())
|
||||||
return codes
|
return codes
|
||||||
|
|
||||||
def code_exec(self, codedict, extra_environ=None, debug=False):
|
def code_exec(self, codedict, extra_environ=None, debug=False):
|
||||||
|
|
@ -409,7 +439,6 @@ class BatchCodeProcessor(object):
|
||||||
|
|
||||||
extra_environ - dict with environment variables
|
extra_environ - dict with environment variables
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# define the execution environment
|
# define the execution environment
|
||||||
environ = "setup_environ(settings_module)"
|
environ = "setup_environ(settings_module)"
|
||||||
environdict = {"setup_environ":setup_environ,
|
environdict = {"setup_environ":setup_environ,
|
||||||
|
|
@ -419,7 +448,7 @@ class BatchCodeProcessor(object):
|
||||||
environdict[key] = value
|
environdict[key] = value
|
||||||
|
|
||||||
# merge all into one block
|
# merge all into one block
|
||||||
code = "%s\n%s" % (environ, codedict['code'])
|
code = "%s # auto-added by Evennia\n%s" % (environ, codedict['code'])
|
||||||
if debug:
|
if debug:
|
||||||
# try to delete marked objects
|
# try to delete marked objects
|
||||||
for obj in codedict['objs']:
|
for obj in codedict['objs']:
|
||||||
|
|
@ -428,11 +457,27 @@ class BatchCodeProcessor(object):
|
||||||
# execute the block
|
# execute the block
|
||||||
try:
|
try:
|
||||||
exec(code, environdict)
|
exec(code, environdict)
|
||||||
except Exception, e:
|
except Exception:
|
||||||
errlist = format_exc().split('\n')
|
etype, value, tb = sys.exc_info()
|
||||||
if len(errlist) > 4:
|
|
||||||
errlist = errlist[4:]
|
fname = tb_filename(tb)
|
||||||
err = "\n".join(" %s" % line for line in errlist if line)
|
for tb in tb_iter(tb):
|
||||||
|
if fname != tb_filename(tb):
|
||||||
|
break
|
||||||
|
lineno = tb.tb_lineno - 1
|
||||||
|
err = ""
|
||||||
|
for iline, line in enumerate(code.split("\n")):
|
||||||
|
if iline == lineno:
|
||||||
|
err += "\n{w%02i{n: %s" % (iline + 1, line)
|
||||||
|
elif lineno - 5 < iline < lineno + 5:
|
||||||
|
err += "\n%02i: %s" % (iline + 1, line)
|
||||||
|
|
||||||
|
err += "\n".join(traceback.format_exception(etype, value, tb))
|
||||||
|
#errlist = format_exc().split('\n')
|
||||||
|
#if len(errlist) > 4:
|
||||||
|
# errlist = errlist[4:]
|
||||||
|
#err = "\n".join(" %s" % line for line in errlist if line)
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
# try to delete objects again.
|
# try to delete objects again.
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue