BuilderManager.inl 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. #pragma once
  9. #include <AzCore/StringFunc/StringFunc.h>
  10. namespace AssetProcessor
  11. {
  12. //! Sends the job over to the builder and blocks until the response is received or the builder crashes/times out
  13. template<typename TNetRequest, typename TNetResponse, typename TRequest, typename TResponse>
  14. BuilderRunJobOutcome Builder::RunJob(const TRequest& request, TResponse& response, AZ::u32 processTimeoutLimitInSeconds, const AZStd::string& task, const AZStd::string& modulePath, AssetBuilderSDK::JobCancelListener* jobCancelListener /*= nullptr*/, AZStd::string tempFolderPath /*= AZStd::string()*/) const
  15. {
  16. TNetRequest netRequest;
  17. TNetResponse netResponse;
  18. netRequest.m_request = request;
  19. struct BuildTracker final
  20. {
  21. BuildTracker(const Builder& builder, const AZStd::string& sourceFile, const AZStd::string& task)
  22. : m_builder(builder)
  23. , m_sourceFile(sourceFile)
  24. , m_task(task)
  25. {
  26. AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Request started builder [%s] task (%s) %s \n",
  27. m_builder.UuidString().c_str(), m_task.c_str(), m_sourceFile.c_str());
  28. }
  29. ~BuildTracker()
  30. {
  31. AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Request stopped builder [%s] task (%s) %s \n",
  32. m_builder.UuidString().c_str(), m_task.c_str(), m_sourceFile.c_str());
  33. }
  34. const Builder& m_builder;
  35. const AZStd::string& m_sourceFile;
  36. const AZStd::string& m_task;
  37. };
  38. BuildTracker tracker(*this, request.m_sourceFile, task);
  39. [[maybe_unused]] AZ::u32 type;
  40. QByteArray data;
  41. AZStd::binary_semaphore wait;
  42. unsigned int serial;
  43. AssetProcessor::ConnectionBus::EventResult(serial, m_connectionId, &AssetProcessor::ConnectionBusTraits::SendRequest, netRequest, [&](AZ::u32 msgType, QByteArray msgData)
  44. {
  45. type = msgType;
  46. data = msgData;
  47. wait.release();
  48. });
  49. BuilderRunJobOutcome result = WaitForBuilderResponse(jobCancelListener, processTimeoutLimitInSeconds, &wait);
  50. if (result != BuilderRunJobOutcome::Ok)
  51. {
  52. // Clear out the response handler so it doesn't get triggered after the variables go out of scope (also to clean up the memory)
  53. AssetProcessor::ConnectionBus::Event(m_connectionId, &AssetProcessor::ConnectionBusTraits::RemoveResponseHandler, serial);
  54. return result;
  55. }
  56. AZ_Assert(type == netRequest.GetMessageType(), "Response type does not match");
  57. if (!AZ::Utils::LoadObjectFromBufferInPlace(data.data(), data.length(), netResponse))
  58. {
  59. AZ_Error("Builder", false, "Failed to deserialize processJobs response");
  60. return BuilderRunJobOutcome::FailedToDecodeResponse;
  61. }
  62. if (!netResponse.m_response.Succeeded() || s_createRequestFileForSuccessfulJob)
  63. {
  64. // we write the request out to disk for failure or debugging
  65. BuilderPurpose purpose = azrtti_typeid<TRequest>() == azrtti_typeid<AssetBuilderSDK::CreateJobsRequest>()
  66. ? BuilderPurpose::CreateJobs
  67. : BuilderPurpose::ProcessJob;
  68. if (!DebugWriteRequestFile(tempFolderPath.c_str(), request, task, modulePath, purpose))
  69. {
  70. return BuilderRunJobOutcome::FailedToWriteDebugRequest;
  71. }
  72. }
  73. response = AZStd::move(netResponse.m_response);
  74. return result;
  75. }
  76. template<typename TRequest>
  77. bool Builder::DebugWriteRequestFile(QString tempFolderPath, const TRequest& request, const AZStd::string& task, const AZStd::string& modulePath, BuilderPurpose purpose) const
  78. {
  79. if (tempFolderPath.isEmpty())
  80. {
  81. if (!AssetUtilities::CreateTempWorkspace(tempFolderPath))
  82. {
  83. AZ_Error("Builder", false, "Failed to create temporary workspace to execute builder task");
  84. return false;
  85. }
  86. }
  87. const QDir tempFolder = QDir(tempFolderPath);
  88. const AZStd::string jobRequestFile = tempFolder.filePath("request.xml").toStdString().c_str();
  89. const AZStd::string jobResponseFile = tempFolder.filePath("response.xml").toStdString().c_str();
  90. if (!AZ::Utils::SaveObjectToFile(jobRequestFile, AZ::DataStream::ST_XML, &request))
  91. {
  92. AZ_Error("Builder", false, "Failed to save request to file: %s", jobRequestFile.c_str());
  93. return false;
  94. }
  95. auto params = BuildParams(task.c_str(), modulePath.c_str(), "", jobRequestFile, jobResponseFile, purpose);
  96. AZStd::string paramString;
  97. AZ::StringFunc::Join(paramString, params.begin(), params.end(), " ");
  98. AZ_TracePrintf(AssetProcessor::DebugChannel, "Job request written to %s\n", jobRequestFile.c_str());
  99. AZ_TracePrintf(AssetProcessor::DebugChannel, "To re-run this request manually, run AssetBuilder with the following parameters:\n");
  100. AZ_TracePrintf(AssetProcessor::DebugChannel, "%s\n", paramString.c_str());
  101. return true;
  102. }
  103. } // namespace AssetProcessor