3
0

BatchApplicationManager.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "BatchApplicationManager.h"
  9. #include <native/resourcecompiler/rccontroller.h>
  10. #include <native/AssetManager/assetScanner.h>
  11. #include <native/utilities/BatchApplicationServer.h>
  12. #include <AzToolsFramework/UI/Logging/LogLine.h>
  13. #include <QCoreApplication>
  14. // in batch mode, we are going to show the log files of up to N failures.
  15. // in order to not spam the logs, we limit this - its possible that something fundamental is broken and EVERY asset is failing
  16. // and we don't want to thus write gigabytes of logs out.
  17. const int s_MaximumFailuresToReport = 10;
  18. #if defined(AZ_PLATFORM_WINDOWS)
  19. namespace BatchApplicationManagerPrivate
  20. {
  21. BatchApplicationManager* g_appManager = nullptr;
  22. BOOL WINAPI CtrlHandlerRoutine(DWORD dwCtrlType)
  23. {
  24. (void)dwCtrlType;
  25. AZ_Printf("AssetProcessor", "Asset Processor Batch Processing Interrupted. Quitting.\n");
  26. QMetaObject::invokeMethod(g_appManager, "QuitRequested", Qt::QueuedConnection);
  27. return TRUE;
  28. }
  29. }
  30. #endif //#if defined(AZ_PLATFORM_WINDOWS)
  31. BatchApplicationManager::BatchApplicationManager(int* argc, char*** argv, QObject* parent)
  32. : ApplicationManagerBase(argc, argv, parent)
  33. {
  34. AssetProcessor::MessageInfoBus::Handler::BusConnect();
  35. }
  36. BatchApplicationManager::~BatchApplicationManager()
  37. {
  38. AssetProcessor::MessageInfoBus::Handler::BusDisconnect();
  39. }
  40. void BatchApplicationManager::Destroy()
  41. {
  42. #if defined(AZ_PLATFORM_WINDOWS)
  43. SetConsoleCtrlHandler((PHANDLER_ROUTINE)BatchApplicationManagerPrivate::CtrlHandlerRoutine, FALSE);
  44. BatchApplicationManagerPrivate::g_appManager = nullptr;
  45. #endif //#if defined(AZ_PLATFORM_WINDOWS)
  46. ApplicationManagerBase::Destroy();
  47. }
  48. bool BatchApplicationManager::Activate()
  49. {
  50. #if defined(AZ_PLATFORM_WINDOWS)
  51. BatchApplicationManagerPrivate::g_appManager = this;
  52. SetConsoleCtrlHandler((PHANDLER_ROUTINE)BatchApplicationManagerPrivate::CtrlHandlerRoutine, TRUE);
  53. #endif //defined(AZ_PLATFORM_WINDOWS)
  54. return ApplicationManagerBase::Activate();
  55. }
  56. void BatchApplicationManager::OnErrorMessage([[maybe_unused]] const char* error)
  57. {
  58. AZ_Error("AssetProcessor", false, "%s", error);
  59. }
  60. void BatchApplicationManager::Reflect()
  61. {
  62. ApplicationManagerBase::Reflect();
  63. }
  64. const char* BatchApplicationManager::GetLogBaseName()
  65. {
  66. return "AP_Batch";
  67. }
  68. ApplicationManager::RegistryCheckInstructions BatchApplicationManager::PopupRegistryProblemsMessage(QString warningText)
  69. {
  70. return RegistryCheckInstructions::Exit;
  71. }
  72. void BatchApplicationManager::InitSourceControl()
  73. {
  74. bool enableSourceControl = false;
  75. const AzFramework::CommandLine* commandLine = nullptr;
  76. AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine);
  77. if (commandLine->HasSwitch("enablescm"))
  78. {
  79. enableSourceControl = true;
  80. }
  81. if (enableSourceControl)
  82. {
  83. AzToolsFramework::SourceControlConnectionRequestBus::Broadcast(&AzToolsFramework::SourceControlConnectionRequestBus::Events::EnableSourceControl, true);
  84. }
  85. else
  86. {
  87. Q_EMIT SourceControlReady();
  88. }
  89. }
  90. void BatchApplicationManager::InitUuidManager()
  91. {
  92. m_uuidManager = AZStd::make_unique<AssetProcessor::UuidManager>();
  93. m_assetProcessorManager->SetMetaCreationDelay(0);
  94. // Note that batch does not set any enabled types and has 0 delay because batch mode is not expected to generate metadata files or handle moving/renaming while running.
  95. }
  96. void BatchApplicationManager::MakeActivationConnections()
  97. {
  98. QObject::connect(m_rcController, &AssetProcessor::RCController::FileCompiled,
  99. m_assetProcessorManager, [this](AssetProcessor::JobEntry entry, AssetBuilderSDK::ProcessJobResponse /*response*/)
  100. {
  101. m_processedAssetCount++;
  102. // If a file fails and later succeeds, don't count it as a failure.
  103. // This avoids marking the entire run as a failure (returning non-zero) when everything compiled successfully *eventually*
  104. m_failedAssets.erase(entry.GetAbsoluteSourcePath().toUtf8().constData());
  105. AssetProcessor::JobDiagnosticInfo info{};
  106. AssetProcessor::JobDiagnosticRequestBus::BroadcastResult(info, &AssetProcessor::JobDiagnosticRequestBus::Events::GetDiagnosticInfo, entry.m_jobRunKey);
  107. m_warningCount += info.m_warningCount;
  108. m_errorCount += info.m_errorCount;
  109. });
  110. QObject::connect(m_rcController, &AssetProcessor::RCController::FileFailed,
  111. m_assetProcessorManager, [this](AssetProcessor::JobEntry entry)
  112. {
  113. m_failedAssets.emplace(entry.GetAbsoluteSourcePath().toUtf8().constData());
  114. AssetProcessor::JobDiagnosticInfo info{};
  115. AssetProcessor::JobDiagnosticRequestBus::BroadcastResult(info, &AssetProcessor::JobDiagnosticRequestBus::Events::GetDiagnosticInfo, entry.m_jobRunKey);
  116. m_warningCount += info.m_warningCount;
  117. m_errorCount += info.m_errorCount;
  118. using AssetJobLogRequest = AzToolsFramework::AssetSystem::AssetJobLogRequest;
  119. using AssetJobLogResponse = AzToolsFramework::AssetSystem::AssetJobLogResponse;
  120. if (m_failedAssets.size() < s_MaximumFailuresToReport) // if we're in the situation where many assets are failing we need to stop spamming after a few
  121. {
  122. AssetJobLogRequest request;
  123. AssetJobLogResponse response;
  124. request.m_jobRunKey = entry.m_jobRunKey;
  125. QMetaObject::invokeMethod(GetAssetProcessorManager(), "ProcessGetAssetJobLogRequest", Qt::DirectConnection, Q_ARG(const AssetJobLogRequest&, request), Q_ARG(AssetJobLogResponse&, response));
  126. if (response.m_isSuccess)
  127. {
  128. // write the log to console!
  129. AzToolsFramework::Logging::LogLine::ParseLog(response.m_jobLog.c_str(), response.m_jobLog.size(),
  130. [](AzToolsFramework::Logging::LogLine& target)
  131. {
  132. // We're going to output *everything* because when a non-obvious error occurs, even mundane info output can be helpful for diagnosing the cause of the error
  133. AZStd::string logString = target.ToString();
  134. AZ_TracePrintf(AssetProcessor::ConsoleChannel, "JOB LOG: %s", logString.c_str());
  135. });
  136. }
  137. }
  138. else if (m_failedAssets.size() == s_MaximumFailuresToReport)
  139. {
  140. // notify the user that we're done here, and will not be notifying any more.
  141. AZ_Printf(AssetProcessor::ConsoleChannel, "%s\n", QCoreApplication::translate("Batch Mode", "Too Many Compile Errors - not printing out full logs for remaining errors").toUtf8().constData());
  142. }
  143. });
  144. m_connectionsToRemoveOnShutdown << QObject::connect(m_assetScanner, &AssetProcessor::AssetScanner::AssetScanningStatusChanged, this,
  145. [this](AssetProcessor::AssetScanningStatus status)
  146. {
  147. if ((status == AssetProcessor::AssetScanningStatus::Completed) || (status == AssetProcessor::AssetScanningStatus::Stopped))
  148. {
  149. AZ_Printf(AssetProcessor::ConsoleChannel, QCoreApplication::translate("Batch Mode", "Analyzing scanned files for changes...\n").toUtf8().constData());
  150. CheckForIdle();
  151. }
  152. });
  153. }
  154. void BatchApplicationManager::TryScanProductDependencies()
  155. {
  156. if (!m_dependencyScanPattern.isEmpty())
  157. {
  158. m_assetProcessorManager->ScanForMissingProductDependencies(m_dependencyScanPattern, m_fileDependencyScanPattern, m_dependencyAddtionalScanFolders, m_dependencyScanMaxIteration);
  159. m_dependencyScanPattern.clear();
  160. }
  161. }
  162. void BatchApplicationManager::TryHandleFileRelocation()
  163. {
  164. HandleFileRelocation();
  165. }
  166. bool BatchApplicationManager::InitApplicationServer()
  167. {
  168. m_applicationServer = new BatchApplicationServer();
  169. return true;
  170. }