BatchApplicationManager.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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. : BatchApplicationManager(argc, argv, parent, {})
  33. {
  34. }
  35. BatchApplicationManager::BatchApplicationManager(int* argc, char*** argv, AZ::ComponentApplicationSettings componentAppSettings)
  36. : BatchApplicationManager(argc, argv, nullptr, AZStd::move(componentAppSettings))
  37. {
  38. }
  39. BatchApplicationManager::BatchApplicationManager(int* argc, char*** argv, QObject* parent, AZ::ComponentApplicationSettings componentAppSettings)
  40. : ApplicationManagerBase(argc, argv, parent, AZStd::move(componentAppSettings))
  41. {
  42. AssetProcessor::MessageInfoBus::Handler::BusConnect();
  43. }
  44. BatchApplicationManager::~BatchApplicationManager()
  45. {
  46. AssetProcessor::MessageInfoBus::Handler::BusDisconnect();
  47. }
  48. void BatchApplicationManager::Destroy()
  49. {
  50. #if defined(AZ_PLATFORM_WINDOWS)
  51. SetConsoleCtrlHandler((PHANDLER_ROUTINE)BatchApplicationManagerPrivate::CtrlHandlerRoutine, FALSE);
  52. BatchApplicationManagerPrivate::g_appManager = nullptr;
  53. #endif //#if defined(AZ_PLATFORM_WINDOWS)
  54. ApplicationManagerBase::Destroy();
  55. }
  56. bool BatchApplicationManager::Activate()
  57. {
  58. #if defined(AZ_PLATFORM_WINDOWS)
  59. BatchApplicationManagerPrivate::g_appManager = this;
  60. SetConsoleCtrlHandler((PHANDLER_ROUTINE)BatchApplicationManagerPrivate::CtrlHandlerRoutine, TRUE);
  61. #endif //defined(AZ_PLATFORM_WINDOWS)
  62. return ApplicationManagerBase::Activate();
  63. }
  64. void BatchApplicationManager::OnErrorMessage([[maybe_unused]] const char* error)
  65. {
  66. AZ_Error("AssetProcessor", false, "%s", error);
  67. }
  68. void BatchApplicationManager::Reflect()
  69. {
  70. ApplicationManagerBase::Reflect();
  71. }
  72. const char* BatchApplicationManager::GetLogBaseName()
  73. {
  74. return "AP_Batch";
  75. }
  76. ApplicationManager::RegistryCheckInstructions BatchApplicationManager::PopupRegistryProblemsMessage(QString warningText)
  77. {
  78. return RegistryCheckInstructions::Exit;
  79. }
  80. void BatchApplicationManager::InitSourceControl()
  81. {
  82. bool enableSourceControl = false;
  83. const AzFramework::CommandLine* commandLine = nullptr;
  84. AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetCommandLine);
  85. if (commandLine->HasSwitch("enablescm"))
  86. {
  87. enableSourceControl = true;
  88. }
  89. if (enableSourceControl)
  90. {
  91. AzToolsFramework::SourceControlConnectionRequestBus::Broadcast(&AzToolsFramework::SourceControlConnectionRequestBus::Events::EnableSourceControl, true);
  92. }
  93. else
  94. {
  95. Q_EMIT SourceControlReady();
  96. }
  97. }
  98. void BatchApplicationManager::InitUuidManager()
  99. {
  100. m_uuidManager = AZStd::make_unique<AssetProcessor::UuidManager>();
  101. m_assetProcessorManager->SetMetaCreationDelay(0);
  102. // 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.
  103. }
  104. void BatchApplicationManager::MakeActivationConnections()
  105. {
  106. QObject::connect(m_rcController, &AssetProcessor::RCController::FileCompiled,
  107. m_assetProcessorManager, [this](AssetProcessor::JobEntry entry, AssetBuilderSDK::ProcessJobResponse /*response*/)
  108. {
  109. m_processedAssetCount++;
  110. // If a file fails and later succeeds, don't count it as a failure.
  111. // This avoids marking the entire run as a failure (returning non-zero) when everything compiled successfully *eventually*
  112. m_failedAssets.erase(entry.GetAbsoluteSourcePath().toUtf8().constData());
  113. AssetProcessor::JobDiagnosticInfo info{};
  114. AssetProcessor::JobDiagnosticRequestBus::BroadcastResult(info, &AssetProcessor::JobDiagnosticRequestBus::Events::GetDiagnosticInfo, entry.m_jobRunKey);
  115. m_warningCount += info.m_warningCount;
  116. m_errorCount += info.m_errorCount;
  117. });
  118. QObject::connect(m_rcController, &AssetProcessor::RCController::FileFailed,
  119. m_assetProcessorManager, [this](AssetProcessor::JobEntry entry)
  120. {
  121. m_failedAssets.emplace(entry.GetAbsoluteSourcePath().toUtf8().constData());
  122. AssetProcessor::JobDiagnosticInfo info{};
  123. AssetProcessor::JobDiagnosticRequestBus::BroadcastResult(info, &AssetProcessor::JobDiagnosticRequestBus::Events::GetDiagnosticInfo, entry.m_jobRunKey);
  124. m_warningCount += info.m_warningCount;
  125. m_errorCount += info.m_errorCount;
  126. using AssetJobLogRequest = AzToolsFramework::AssetSystem::AssetJobLogRequest;
  127. using AssetJobLogResponse = AzToolsFramework::AssetSystem::AssetJobLogResponse;
  128. 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
  129. {
  130. AssetJobLogRequest request;
  131. AssetJobLogResponse response;
  132. request.m_jobRunKey = entry.m_jobRunKey;
  133. QMetaObject::invokeMethod(GetAssetProcessorManager(), "ProcessGetAssetJobLogRequest", Qt::DirectConnection, Q_ARG(const AssetJobLogRequest&, request), Q_ARG(AssetJobLogResponse&, response));
  134. if (response.m_isSuccess)
  135. {
  136. // write the log to console!
  137. AzToolsFramework::Logging::LogLine::ParseLog(response.m_jobLog.c_str(), response.m_jobLog.size(),
  138. [](AzToolsFramework::Logging::LogLine& target)
  139. {
  140. // 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
  141. AZStd::string logString = target.ToString();
  142. AZ_TracePrintf(AssetProcessor::ConsoleChannel, "JOB LOG: %s", logString.c_str());
  143. });
  144. }
  145. }
  146. else if (m_failedAssets.size() == s_MaximumFailuresToReport)
  147. {
  148. // notify the user that we're done here, and will not be notifying any more.
  149. AZ_Printf(AssetProcessor::ConsoleChannel, "%s\n", QCoreApplication::translate("Batch Mode", "Too Many Compile Errors - not printing out full logs for remaining errors").toUtf8().constData());
  150. }
  151. });
  152. m_connectionsToRemoveOnShutdown << QObject::connect(m_assetScanner, &AssetProcessor::AssetScanner::AssetScanningStatusChanged, this,
  153. [this](AssetProcessor::AssetScanningStatus status)
  154. {
  155. if ((status == AssetProcessor::AssetScanningStatus::Completed) || (status == AssetProcessor::AssetScanningStatus::Stopped))
  156. {
  157. AZ_Printf(AssetProcessor::ConsoleChannel, QCoreApplication::translate("Batch Mode", "Analyzing scanned files for changes...\n").toUtf8().constData());
  158. CheckForIdle();
  159. }
  160. });
  161. }
  162. void BatchApplicationManager::TryScanProductDependencies()
  163. {
  164. if (!m_dependencyScanPattern.isEmpty())
  165. {
  166. m_assetProcessorManager->ScanForMissingProductDependencies(m_dependencyScanPattern, m_fileDependencyScanPattern, m_dependencyAddtionalScanFolders, m_dependencyScanMaxIteration);
  167. m_dependencyScanPattern.clear();
  168. }
  169. }
  170. void BatchApplicationManager::TryHandleFileRelocation()
  171. {
  172. HandleFileRelocation();
  173. }
  174. bool BatchApplicationManager::InitApplicationServer()
  175. {
  176. m_applicationServer = new BatchApplicationServer();
  177. return true;
  178. }