ClementFix typo2c3dd157 years agoHistory
144 lines · 5.0 KB · C++
RawDownload
////  BakeAssetTask.cpp//  assignment-client/src/assets////  Created by Stephen Birarda on 9/18/17.//  Copyright 2017 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "BakeAssetTask.h" #include <mutex> #include <QtCore/QThread>#include <QCoreApplication> #include <PathUtils.h> static const int OVEN_STATUS_CODE_SUCCESS { 0 };static const int OVEN_STATUS_CODE_FAIL { 1 };static const int OVEN_STATUS_CODE_ABORT { 2 }; std::once_flag registerMetaTypesFlag; BakeAssetTask::BakeAssetTask(const AssetUtils::AssetHash& assetHash, const AssetUtils::AssetPath& assetPath, const QString& filePath) :    _assetHash(assetHash),    _assetPath(assetPath),    _filePath(filePath){     std::call_once(registerMetaTypesFlag, []() {        qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError");        qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus");    });} void BakeAssetTask::run() {    if (_isBaking.exchange(true)) {        qWarning() << "Tried to start bake asset task while already baking";        return;    }     // Make a new temporary directory for the Oven to work in    QString tempOutputDir = PathUtils::generateTemporaryDir();    QString tempOutputDirName = QDir(tempOutputDir).dirName();    if (tempOutputDir.isEmpty()) {        QString errors = "Could not create temporary working directory";        emit bakeFailed(_assetHash, _assetPath, errors);        PathUtils::deleteMyTemporaryDir(tempOutputDirName);        return;    }     // Copy file to bake the temporary dir and give a name the oven can work with    auto assetName = _assetPath.split("/").last();    auto tempAssetPath = tempOutputDir + "/" + assetName;    auto success = QFile::copy(_filePath, tempAssetPath);    if (!success) {        QString errors = "Couldn't copy file to bake to temporary directory";        emit bakeFailed(_assetHash, _assetPath, errors);        PathUtils::deleteMyTemporaryDir(tempOutputDirName);        return;    }     auto base = QFileInfo(QCoreApplication::applicationFilePath()).absoluteDir();    QString path = base.absolutePath() + "/oven";    QString extension = _assetPath.mid(_assetPath.lastIndexOf('.') + 1);    QStringList args {        "-i", tempAssetPath,        "-o", tempOutputDir,        "-t", extension,    };     _ovenProcess.reset(new QProcess());     QEventLoop loop;     connect(_ovenProcess.get(), static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),            this, [&loop, this, tempOutputDir, tempAssetPath, tempOutputDirName](int exitCode, QProcess::ExitStatus exitStatus) {        qDebug() << "Baking process finished: " << exitCode << exitStatus;         if (exitStatus == QProcess::CrashExit) {            PathUtils::deleteMyTemporaryDir(tempOutputDirName);            if (_wasAborted) {                emit bakeAborted(_assetHash, _assetPath);            } else {                QString errors = "Fatal error occurred while baking";                emit bakeFailed(_assetHash, _assetPath, errors);            }        } else if (exitCode == OVEN_STATUS_CODE_SUCCESS) {            emit bakeComplete(_assetHash, _assetPath, tempOutputDir);        } else if (exitStatus == QProcess::NormalExit && exitCode == OVEN_STATUS_CODE_ABORT) {            _wasAborted.store(true);            PathUtils::deleteMyTemporaryDir(tempOutputDirName);            emit bakeAborted(_assetHash, _assetPath);        } else {            QString errors;            if (exitCode == OVEN_STATUS_CODE_FAIL) {                QDir outputDir = tempOutputDir;                auto errorFilePath = outputDir.absoluteFilePath("errors.txt");                QFile errorFile { errorFilePath };                if (errorFile.open(QIODevice::ReadOnly)) {                    errors = errorFile.readAll();                    errorFile.close();                } else {                    errors = "Unknown error occurred while baking";                }            }            PathUtils::deleteMyTemporaryDir(tempOutputDirName);            emit bakeFailed(_assetHash, _assetPath, errors);        }         loop.quit();    });     qDebug() << "Starting oven for " << _assetPath;    _ovenProcess->start(path, args, QIODevice::ReadOnly);    qDebug() << "Running:" << path << args;    if (!_ovenProcess->waitForStarted()) {        PathUtils::deleteMyTemporaryDir(tempOutputDirName);         QString errors = "Oven process failed to start";        emit bakeFailed(_assetHash, _assetPath, errors);        return;    }     _isBaking = true;     loop.exec();} void BakeAssetTask::abort() {    if (QThread::currentThread() != thread()) {        QMetaObject::invokeMethod(this, "abort");        return;    }    qDebug() << "Aborting BakeAssetTask for" << _assetHash;    if (_ovenProcess->state() != QProcess::NotRunning) {        qDebug() << "Teminating oven process for" << _assetHash;        _wasAborted = true;        _ovenProcess->terminate();    }}