Fix asset server baking not working on *nix

This commit is contained in:
Ryan Huffman 2017-12-06 11:28:06 -08:00
parent bee666b522
commit f20aa2e680
4 changed files with 40 additions and 95 deletions

View file

@ -12,11 +12,9 @@
#include "BakeAssetTask.h"
#include <QtCore/QThread>
#include <QProcess>
#include <QCoreApplication>
#include <FBXBaker.h>
#include <PathUtils.h>
#include <JSBaker.h>
static const int OVEN_STATUS_CODE_SUCCESS { 0 };
static const int OVEN_STATUS_CODE_FAIL { 1 };
@ -48,7 +46,10 @@ void cleanupTempFiles(QString tempOutputDir, std::vector<QString> files) {
};
void BakeAssetTask::run() {
_isBaking.store(true);
if (_isBaking.exchange(true)) {
qWarning() << "Tried to start bake asset task while already baking";
return;
}
QString tempOutputDir = PathUtils::generateTemporaryDir();
_outputDir = tempOutputDir;
@ -61,25 +62,27 @@ void BakeAssetTask::run() {
"-t", extension,
};
qDebug().noquote() << "Path: " << path << args.join(' ');
QProcess* proc = new QProcess();
auto _ovenProcess = new QProcess(this);
connect(proc, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
this, [this, proc, tempOutputDir](int exitCode, QProcess::ExitStatus exitStatus) {
qDebug() << "Finished process: " << exitCode << exitStatus;
qDebug() << "stdout: " << proc->readAllStandardOutput();
connect(_ovenProcess, static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
this, [this, tempOutputDir](int exitCode, QProcess::ExitStatus exitStatus) {
qDebug() << "Baking process finished: " << exitCode << exitStatus;
auto files = _outputDir.entryInfoList(QDir::Files);
QVector<QString> outputFiles;
for (auto& file : files) {
qDebug() << "Output file: " << file.absoluteFilePath();
outputFiles.push_back(file.absoluteFilePath());
}
if (exitStatus == QProcess::CrashExit) {
_didFinish.store(true);
QString errors = "Fatal error occurred while baking";
emit bakeFailed(_assetHash, _assetPath, errors);
} else if (exitCode == OVEN_STATUS_CODE_SUCCESS) {
auto files = _outputDir.entryInfoList(QDir::Files);
QVector<QString> outputFiles;
for (auto& file : files) {
qDebug() << " Output file: " << file.absoluteFilePath();
outputFiles.push_back(file.absoluteFilePath());
}
if (exitCode == OVEN_STATUS_CODE_SUCCESS) {
_didFinish.store(true);
emit bakeComplete(_assetHash, _assetPath, tempOutputDir, outputFiles);
} else if (exitCode == OVEN_STATUS_CODE_ABORT) {
} else if (exitStatus == QProcess::NormalExit && exitCode == OVEN_STATUS_CODE_ABORT) {
_wasAborted.store(true);
emit bakeAborted(_assetHash, _assetPath);
} else {
@ -92,81 +95,22 @@ void BakeAssetTask::run() {
errors = errorFile.readAll();
errorFile.close();
} else {
errors = "Unknown error occurred";
errors = "Unknown error occurred while baking";
}
}
emit bakeFailed(_assetHash, _assetPath, errors);
}
});
connect(proc, &QProcess::errorOccurred, this, []() {
qDebug() << "Error occurred :(";
});
connect(proc, &QProcess::started, this, []() {
qDebug() << "Process started";
});
proc->start(path, args, QIODevice::ReadOnly);
proc->waitForStarted();
proc->waitForFinished();
return;
qRegisterMetaType<QVector<QString> >("QVector<QString>");
TextureBakerThreadGetter fn = []() -> QThread* { return QThread::currentThread(); };
if (_assetPath.endsWith(".fbx")) {
_baker = std::unique_ptr<FBXBaker> {
new FBXBaker(QUrl("file:///" + _filePath), fn, tempOutputDir)
};
} else if (_assetPath.endsWith(".js", Qt::CaseInsensitive)) {
_baker = std::unique_ptr<JSBaker>{
new JSBaker(QUrl("file:///" + _filePath), tempOutputDir)
};
} else {
_baker = std::unique_ptr<TextureBaker> {
new TextureBaker(QUrl("file:///" + _filePath), image::TextureUsage::CUBE_TEXTURE,
tempOutputDir)
};
}
QEventLoop loop;
connect(_baker.get(), &Baker::finished, &loop, &QEventLoop::quit);
connect(_baker.get(), &Baker::aborted, &loop, &QEventLoop::quit);
QMetaObject::invokeMethod(_baker.get(), "bake", Qt::QueuedConnection);
loop.exec();
if (_baker->wasAborted()) {
qDebug() << "Aborted baking: " << _assetHash << _assetPath;
_wasAborted.store(true);
cleanupTempFiles(tempOutputDir, _baker->getOutputFiles());
emit bakeAborted(_assetHash, _assetPath);
} else if (_baker->hasErrors()) {
qDebug() << "Failed to bake: " << _assetHash << _assetPath << _baker->getErrors();
auto errors = _baker->getErrors().join('\n'); // Join error list into a single string for convenience
_didFinish.store(true);
cleanupTempFiles(tempOutputDir, _baker->getOutputFiles());
emit bakeFailed(_assetHash, _assetPath, errors);
} else {
auto vectorOutputFiles = QVector<QString>::fromStdVector(_baker->getOutputFiles());
qDebug() << "Finished baking: " << _assetHash << _assetPath << vectorOutputFiles;
_didFinish.store(true);
emit bakeComplete(_assetHash, _assetPath, tempOutputDir, vectorOutputFiles);
}
qDebug() << "Starting oven for " << _assetPath;
_ovenProcess->start(path, args, QIODevice::ReadOnly);
_ovenProcess->waitForStarted();
_ovenProcess->waitForFinished();
}
void BakeAssetTask::abort() {
if (_baker) {
_baker->abort();
if (!_wasAborted.exchange(true)) {
_ovenProcess.terminate();
}
}

View file

@ -18,9 +18,9 @@
#include <QtCore/QObject>
#include <QtCore/QRunnable>
#include <QDir>
#include <QProcess>
#include <AssetUtils.h>
#include <Baker.h>
class BakeAssetTask : public QObject, public QRunnable {
Q_OBJECT
@ -46,7 +46,7 @@ private:
AssetPath _assetPath;
QString _filePath;
QDir _outputDir;
std::unique_ptr<Baker> _baker;
QProcess _ovenProcess { nullptr };
std::atomic<bool> _wasAborted { false };
std::atomic<bool> _didFinish { false };
};

View file

@ -67,7 +67,7 @@ QString PathUtils::generateTemporaryDir() {
for (auto i = 0; i < 64; ++i) {
auto now = std::chrono::system_clock::now().time_since_epoch().count();
auto dirName = TEMP_DIR_FORMAT.arg(appName).arg(qApp->applicationPid()).arg(now);
QDir tempDir = rootTempDir.filePath(appName + "-" + QString::number(now));
QDir tempDir = rootTempDir.filePath(dirName);
if (tempDir.mkpath(".")) {
return tempDir.absolutePath();
}
@ -83,32 +83,27 @@ int PathUtils::removeTemporaryDirs(QString appName) {
auto dirName = TEMP_DIR_FORMAT.arg(appName).arg("*").arg("*");
qDebug() << "Dirname format is: " << dirName;
auto pid = qApp->applicationPid();
QDir rootTempDir = QDir::tempPath();
qDebug() << "Temp dir is: " << rootTempDir;
auto dirs = rootTempDir.entryInfoList({ dirName }, QDir::Dirs);
int removed = 0;
for (auto& dir : dirs) {
auto dirName = dir.fileName();
auto absoluteDirPath = QDir(dir.absoluteFilePath());
qDebug() << " Deleting: " << dirName << absoluteDirPath;
QRegularExpression re { "^" + QRegularExpression::escape(appName) + "\\-(?<pid>\\d+)\\-(?<timestamp>\\d+)$" };
auto match = re.match(dirName);
if (match.hasMatch()) {
qDebug() << " Got match";
auto pid = match.capturedRef("pid").toLongLong();
auto timestamp = match.capturedRef("timestamp");
qDebug() << " Is " << pid << " running?" << processIsRunning(pid);
if (!processIsRunning(pid)) {
qDebug() << " Removing: " << absoluteDirPath;
qDebug() << " Removing old temporary directory: " << absoluteDirPath;
absoluteDirPath.removeRecursively();
removed++;
} else {
qDebug() << " Not removing (process is running): " << dir.absoluteDir();
}
} else {
qDebug() << " NO MATCH";
}
}

View file

@ -47,6 +47,7 @@ extern "C" FILE * __cdecl __iob_func(void) {
#if defined(Q_OS_LINUX) || defined(__APPLE__)
#include <signal.h>
#include <cerrno>
#endif
#include <QtCore/QDebug>
@ -1094,7 +1095,12 @@ bool processIsRunning(int64_t pid) {
}
return false;
#elif defined(Q_OS_LINUX) || defined(__APPLE__)
return kill(pid, 0) != ESRCH;
if (kill(pid, 0) == -1) {
return errno != ESRCH;
}
return true;
#else
static_assert(false);
#endif
}