mirror of https://github.com/AxioDL/metaforce.git
Add proper file-based error reporting
This commit is contained in:
parent
e17d5c0b83
commit
577af720d3
|
@ -3,9 +3,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <hecl/hecl.hpp>
|
||||
#include <hecl/Database.hpp>
|
||||
|
@ -103,7 +106,7 @@ size_t BlenderConnection::_readLine(char* buf, size_t bufSz)
|
|||
*buf = '\0';
|
||||
if (readBytes >= 4)
|
||||
if (!memcmp(buf, "EXCEPTION", std::min(readBytes, size_t(9))))
|
||||
BlenderLog.report(logvisor::Fatal, "Blender exception");
|
||||
_blenderDied();
|
||||
return readBytes;
|
||||
}
|
||||
++readBytes;
|
||||
|
@ -114,7 +117,7 @@ size_t BlenderConnection::_readLine(char* buf, size_t bufSz)
|
|||
*buf = '\0';
|
||||
if (readBytes >= 4)
|
||||
if (!memcmp(buf, "EXCEPTION", std::min(readBytes, size_t(9))))
|
||||
BlenderLog.report(logvisor::Fatal, "Blender exception");
|
||||
_blenderDied();
|
||||
return readBytes;
|
||||
}
|
||||
}
|
||||
|
@ -131,7 +134,7 @@ size_t BlenderConnection::_writeLine(const char* buf)
|
|||
goto err;
|
||||
return (size_t)ret;
|
||||
err:
|
||||
BlenderLog.report(logvisor::Fatal, strerror(errno));
|
||||
_blenderDied();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -142,10 +145,10 @@ size_t BlenderConnection::_readBuf(void* buf, size_t len)
|
|||
goto err;
|
||||
if (len >= 4)
|
||||
if (!memcmp((char*)buf, "EXCEPTION", std::min(len, size_t(9))))
|
||||
BlenderLog.report(logvisor::Fatal, "Blender exception");
|
||||
_blenderDied();
|
||||
return ret;
|
||||
err:
|
||||
BlenderLog.report(logvisor::Fatal, strerror(errno));
|
||||
_blenderDied();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -156,7 +159,7 @@ size_t BlenderConnection::_writeBuf(const void* buf, size_t len)
|
|||
goto err;
|
||||
return ret;
|
||||
err:
|
||||
BlenderLog.report(logvisor::Fatal, strerror(errno));
|
||||
_blenderDied();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -166,9 +169,30 @@ void BlenderConnection::_closePipe()
|
|||
close(m_writepipe[1]);
|
||||
}
|
||||
|
||||
void BlenderConnection::_blenderDied()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
FILE* errFp = hecl::Fopen(m_errPath.c_str(), _S("r"));
|
||||
if (errFp)
|
||||
{
|
||||
fseek(errFp, 0, SEEK_END);
|
||||
int64_t len = hecl::FTell(errFp);
|
||||
if (len)
|
||||
{
|
||||
fseek(errFp, 0, SEEK_SET);
|
||||
std::unique_ptr<char[]> buf(new char[len+1]);
|
||||
memset(buf.get(), 0, len+1);
|
||||
fread(buf.get(), 1, len, errFp);
|
||||
BlenderLog.report(logvisor::Fatal, "\n%s", buf.get());
|
||||
}
|
||||
}
|
||||
BlenderLog.report(logvisor::Fatal, "Blender Exception");
|
||||
}
|
||||
|
||||
BlenderConnection::BlenderConnection(int verbosityLevel)
|
||||
{
|
||||
BlenderLog.report(logvisor::Info, "Establishing BlenderConnection...");
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* Put hecl_blendershell.py in temp dir */
|
||||
#ifdef _WIN32
|
||||
|
@ -320,6 +344,10 @@ BlenderConnection::BlenderConnection(int verbosityLevel)
|
|||
m_blenderProc = pid;
|
||||
#endif
|
||||
|
||||
/* Stash error path an unlink existing file */
|
||||
m_errPath = hecl::SystemString(TMPDIR) + hecl::Format(_S("/hecl_%016llX.derp"), (unsigned long long)m_blenderProc);
|
||||
hecl::Unlink(m_errPath.c_str());
|
||||
|
||||
/* Handle first response */
|
||||
char lineBuf[256];
|
||||
_readLine(lineBuf, sizeof(lineBuf));
|
||||
|
@ -398,7 +426,7 @@ BlenderConnection::PyOutStream::StreamBuf::overflow(int_type ch)
|
|||
{
|
||||
if (m_deleteOnError)
|
||||
m_parent.m_parent->deleteBlend();
|
||||
BlenderLog.report(logvisor::Fatal, "error sending '%s' to blender", m_lineBuf.c_str());
|
||||
m_parent.m_parent->_blenderDied();
|
||||
}
|
||||
m_lineBuf.clear();
|
||||
return ch;
|
||||
|
|
|
@ -61,11 +61,13 @@ private:
|
|||
bool m_loadedRigged = false;
|
||||
ProjectPath m_loadedBlend;
|
||||
std::string m_startupBlend;
|
||||
hecl::SystemString m_errPath;
|
||||
size_t _readLine(char* buf, size_t bufSz);
|
||||
size_t _writeLine(const char* buf);
|
||||
size_t _readBuf(void* buf, size_t len);
|
||||
size_t _writeBuf(const void* buf, size_t len);
|
||||
void _closePipe();
|
||||
void _blenderDied();
|
||||
public:
|
||||
BlenderConnection(int verbosityLevel=1);
|
||||
~BlenderConnection();
|
||||
|
|
|
@ -10,10 +10,19 @@ args = sys.argv[sys.argv.index('--')+1:]
|
|||
readfd = int(args[0])
|
||||
writefd = int(args[1])
|
||||
verbosity_level = int(args[2])
|
||||
err_path = ""
|
||||
if sys.platform == "win32":
|
||||
import msvcrt
|
||||
readfd = msvcrt.open_osfhandle(readfd, os.O_RDONLY | os.O_BINARY)
|
||||
writefd = msvcrt.open_osfhandle(writefd, os.O_WRONLY | os.O_BINARY)
|
||||
err_path = "/Temp"
|
||||
else:
|
||||
err_path = "/tmp"
|
||||
|
||||
if 'TMPDIR' in os.environ:
|
||||
err_path = os.environ['TMPDIR']
|
||||
|
||||
err_path += "/hecl_%016X.derp" % os.getpid()
|
||||
|
||||
def readpipeline():
|
||||
retval = bytearray()
|
||||
|
@ -230,125 +239,133 @@ def dataout_loop():
|
|||
writepipebuf(struct.pack('f', c))
|
||||
|
||||
|
||||
# Command loop
|
||||
while True:
|
||||
cmdargs = read_cmdargs()
|
||||
print(cmdargs)
|
||||
# Main exception handling
|
||||
try:
|
||||
# Command loop
|
||||
while True:
|
||||
cmdargs = read_cmdargs()
|
||||
print(cmdargs)
|
||||
|
||||
if cmdargs[0] == 'QUIT':
|
||||
quitblender()
|
||||
if cmdargs[0] == 'QUIT':
|
||||
quitblender()
|
||||
|
||||
elif cmdargs[0] == 'OPEN':
|
||||
if 'FINISHED' in bpy.ops.wm.open_mainfile(filepath=cmdargs[1]):
|
||||
if bpy.ops.object.mode_set.poll():
|
||||
bpy.ops.object.mode_set(mode = 'OBJECT')
|
||||
writepipeline(b'FINISHED')
|
||||
else:
|
||||
writepipeline(b'CANCELLED')
|
||||
|
||||
elif cmdargs[0] == 'CREATE':
|
||||
if len(cmdargs) >= 4:
|
||||
bpy.ops.wm.open_mainfile(filepath=cmdargs[3])
|
||||
else:
|
||||
bpy.ops.wm.read_homefile()
|
||||
bpy.context.user_preferences.filepaths.save_version = 0
|
||||
if 'FINISHED' in bpy.ops.wm.save_as_mainfile(filepath=cmdargs[1]):
|
||||
bpy.ops.file.hecl_patching_load()
|
||||
bpy.context.scene.hecl_type = cmdargs[2]
|
||||
writepipeline(b'FINISHED')
|
||||
else:
|
||||
writepipeline(b'CANCELLED')
|
||||
|
||||
elif cmdargs[0] == 'GETTYPE':
|
||||
writepipeline(bpy.context.scene.hecl_type.encode())
|
||||
|
||||
elif cmdargs[0] == 'GETMESHRIGGED':
|
||||
meshName = bpy.context.scene.hecl_mesh_obj
|
||||
if meshName not in bpy.data.objects:
|
||||
writepipeline(b'FALSE')
|
||||
else:
|
||||
if len(bpy.data.objects[meshName].vertex_groups):
|
||||
writepipeline(b'TRUE')
|
||||
elif cmdargs[0] == 'OPEN':
|
||||
if 'FINISHED' in bpy.ops.wm.open_mainfile(filepath=cmdargs[1]):
|
||||
if bpy.ops.object.mode_set.poll():
|
||||
bpy.ops.object.mode_set(mode = 'OBJECT')
|
||||
writepipeline(b'FINISHED')
|
||||
else:
|
||||
writepipeline(b'CANCELLED')
|
||||
|
||||
elif cmdargs[0] == 'CREATE':
|
||||
if len(cmdargs) >= 4:
|
||||
bpy.ops.wm.open_mainfile(filepath=cmdargs[3])
|
||||
else:
|
||||
bpy.ops.wm.read_homefile()
|
||||
bpy.context.user_preferences.filepaths.save_version = 0
|
||||
if 'FINISHED' in bpy.ops.wm.save_as_mainfile(filepath=cmdargs[1]):
|
||||
bpy.ops.file.hecl_patching_load()
|
||||
bpy.context.scene.hecl_type = cmdargs[2]
|
||||
writepipeline(b'FINISHED')
|
||||
else:
|
||||
writepipeline(b'CANCELLED')
|
||||
|
||||
elif cmdargs[0] == 'GETTYPE':
|
||||
writepipeline(bpy.context.scene.hecl_type.encode())
|
||||
|
||||
elif cmdargs[0] == 'GETMESHRIGGED':
|
||||
meshName = bpy.context.scene.hecl_mesh_obj
|
||||
if meshName not in bpy.data.objects:
|
||||
writepipeline(b'FALSE')
|
||||
else:
|
||||
if len(bpy.data.objects[meshName].vertex_groups):
|
||||
writepipeline(b'TRUE')
|
||||
else:
|
||||
writepipeline(b'FALSE')
|
||||
|
||||
elif cmdargs[0] == 'SAVE':
|
||||
bpy.context.user_preferences.filepaths.save_version = 0
|
||||
if 'FINISHED' in bpy.ops.wm.save_mainfile(check_existing=False, compress=True):
|
||||
writepipeline(b'FINISHED')
|
||||
else:
|
||||
writepipeline(b'CANCELLED')
|
||||
elif cmdargs[0] == 'SAVE':
|
||||
bpy.context.user_preferences.filepaths.save_version = 0
|
||||
if 'FINISHED' in bpy.ops.wm.save_mainfile(check_existing=False, compress=True):
|
||||
writepipeline(b'FINISHED')
|
||||
else:
|
||||
writepipeline(b'CANCELLED')
|
||||
|
||||
elif cmdargs[0] == 'PYBEGIN':
|
||||
writepipeline(b'READY')
|
||||
globals = {'hecl':hecl}
|
||||
compbuf = str()
|
||||
bracket_count = 0
|
||||
while True:
|
||||
try:
|
||||
line = readpipeline()
|
||||
elif cmdargs[0] == 'PYBEGIN':
|
||||
writepipeline(b'READY')
|
||||
globals = {'hecl':hecl}
|
||||
compbuf = str()
|
||||
bracket_count = 0
|
||||
while True:
|
||||
try:
|
||||
line = readpipeline()
|
||||
|
||||
# ANIM check
|
||||
if line == b'PYANIM':
|
||||
# Ensure remaining block gets executed
|
||||
# ANIM check
|
||||
if line == b'PYANIM':
|
||||
# Ensure remaining block gets executed
|
||||
if len(compbuf):
|
||||
exec_compbuf(compbuf, globals)
|
||||
compbuf = str()
|
||||
animin_loop(globals)
|
||||
continue
|
||||
|
||||
# End check
|
||||
elif line == b'PYEND':
|
||||
# Ensure remaining block gets executed
|
||||
if len(compbuf):
|
||||
exec_compbuf(compbuf, globals)
|
||||
compbuf = str()
|
||||
writepipeline(b'DONE')
|
||||
break
|
||||
|
||||
# Syntax filter
|
||||
linestr = line.decode().rstrip()
|
||||
if not len(linestr) or linestr.lstrip()[0] == '#':
|
||||
writepipeline(b'OK')
|
||||
continue
|
||||
leading_spaces = len(linestr) - len(linestr.lstrip())
|
||||
|
||||
# Block lines always get appended right away
|
||||
if linestr.endswith(':') or leading_spaces or bracket_count:
|
||||
if len(compbuf):
|
||||
compbuf += '\n'
|
||||
compbuf += linestr
|
||||
bracket_count += count_brackets(linestr)
|
||||
writepipeline(b'OK')
|
||||
continue
|
||||
|
||||
# Complete non-block statement in compbuf
|
||||
if len(compbuf):
|
||||
exec_compbuf(compbuf, globals)
|
||||
compbuf = str()
|
||||
animin_loop(globals)
|
||||
continue
|
||||
|
||||
# End check
|
||||
elif line == b'PYEND':
|
||||
# Ensure remaining block gets executed
|
||||
if len(compbuf):
|
||||
exec_compbuf(compbuf, globals)
|
||||
compbuf = str()
|
||||
writepipeline(b'DONE')
|
||||
break
|
||||
|
||||
# Syntax filter
|
||||
linestr = line.decode().rstrip()
|
||||
if not len(linestr) or linestr.lstrip()[0] == '#':
|
||||
writepipeline(b'OK')
|
||||
continue
|
||||
leading_spaces = len(linestr) - len(linestr.lstrip())
|
||||
|
||||
# Block lines always get appended right away
|
||||
if linestr.endswith(':') or leading_spaces or bracket_count:
|
||||
if len(compbuf):
|
||||
compbuf += '\n'
|
||||
compbuf += linestr
|
||||
# Establish new compbuf
|
||||
compbuf = linestr
|
||||
bracket_count += count_brackets(linestr)
|
||||
writepipeline(b'OK')
|
||||
continue
|
||||
|
||||
# Complete non-block statement in compbuf
|
||||
if len(compbuf):
|
||||
exec_compbuf(compbuf, globals)
|
||||
except Exception as e:
|
||||
writepipeline(b'EXCEPTION')
|
||||
raise
|
||||
break
|
||||
writepipeline(b'OK')
|
||||
|
||||
# Establish new compbuf
|
||||
compbuf = linestr
|
||||
bracket_count += count_brackets(linestr)
|
||||
elif cmdargs[0] == 'PYEND':
|
||||
writepipeline(b'ERROR')
|
||||
|
||||
elif cmdargs[0] == 'DATABEGIN':
|
||||
try:
|
||||
dataout_loop()
|
||||
except Exception as e:
|
||||
writepipeline(b'EXCEPTION')
|
||||
raise
|
||||
break
|
||||
writepipeline(b'OK')
|
||||
|
||||
elif cmdargs[0] == 'PYEND':
|
||||
writepipeline(b'ERROR')
|
||||
elif cmdargs[0] == 'DATAEND':
|
||||
writepipeline(b'ERROR')
|
||||
|
||||
elif cmdargs[0] == 'DATABEGIN':
|
||||
try:
|
||||
dataout_loop()
|
||||
except Exception as e:
|
||||
writepipeline(b'EXCEPTION')
|
||||
raise
|
||||
|
||||
elif cmdargs[0] == 'DATAEND':
|
||||
writepipeline(b'ERROR')
|
||||
|
||||
else:
|
||||
hecl.command(cmdargs, writepipeline, writepipebuf)
|
||||
else:
|
||||
hecl.command(cmdargs, writepipeline, writepipebuf)
|
||||
|
||||
except Exception:
|
||||
import traceback
|
||||
fout = open(err_path, 'w')
|
||||
traceback.print_exc(file=fout)
|
||||
fout.close()
|
||||
raise
|
||||
|
|
Loading…
Reference in New Issue