ProductAsset.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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 <native/AssetManager/ProductAsset.h>
  9. #include <QDir>
  10. #include <AzToolsFramework/AssetDatabase/AssetDatabaseConnection.h>
  11. #include <AzToolsFramework/Metadata/MetadataManager.h>
  12. namespace AssetProcessor
  13. {
  14. ProductAsset::ProductAsset(AZ::IO::Path absolutePath)
  15. : m_absolutePath(AZStd::move(absolutePath))
  16. {
  17. }
  18. bool ProductAsset::IsValid() const
  19. {
  20. return ExistsOnDisk(false);
  21. }
  22. bool ProductAsset::ExistsOnDisk(bool printErrorMessage) const
  23. {
  24. bool exists = AZ::IO::SystemFile::Exists(m_absolutePath.c_str());
  25. if (!exists && printErrorMessage)
  26. {
  27. AZ_TracePrintf(
  28. AssetProcessor::ConsoleChannel, "Was expecting product asset to exist at `%s` but it was not found\n",
  29. m_absolutePath.c_str());
  30. }
  31. return exists;
  32. }
  33. bool ProductAsset::DeleteFile(bool sendNotification) const
  34. {
  35. if (!ExistsOnDisk(false))
  36. {
  37. AZ_TracePrintf(
  38. AssetProcessor::ConsoleChannel, "Was expecting to delete product file %s but it already appears to be gone.\n",
  39. m_absolutePath.c_str());
  40. return false;
  41. }
  42. if(sendNotification)
  43. {
  44. AssetProcessor::ProcessingJobInfoBus::Broadcast(
  45. &AssetProcessor::ProcessingJobInfoBus::Events::BeginCacheFileUpdate, m_absolutePath.AsPosix().c_str());
  46. }
  47. bool wasRemoved = AZ::IO::SystemFile::Delete(m_absolutePath.c_str());
  48. // Another process may be holding on to the file currently, so wait for a very brief period and then retry deleting
  49. // once in case we were just too quick to delete the file before.
  50. if (!wasRemoved)
  51. {
  52. constexpr int DeleteRetryDelay = 10;
  53. AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(DeleteRetryDelay));
  54. wasRemoved = AZ::IO::SystemFile::Delete(m_absolutePath.c_str());
  55. }
  56. // Try to delete the metadata file too if one exists
  57. auto metadataPath = AzToolsFramework::MetadataManager::ToMetadataPath(m_absolutePath).AsPosix();
  58. if(!AZ::IO::SystemFile::Delete(metadataPath.c_str()))
  59. {
  60. if (AZ::IO::SystemFile::Exists(metadataPath.c_str()))
  61. {
  62. AZ_Error(AssetProcessor::ConsoleChannel, false, "Failed to remove metadata file " AZ_STRING_FORMAT, AZ_STRING_ARG(metadataPath));
  63. wasRemoved = false;
  64. }
  65. }
  66. if(sendNotification)
  67. {
  68. AssetProcessor::ProcessingJobInfoBus::Broadcast(
  69. &AssetProcessor::ProcessingJobInfoBus::Events::EndCacheFileUpdate, m_absolutePath.AsPosix().c_str(), false);
  70. }
  71. if(!wasRemoved)
  72. {
  73. return false;
  74. }
  75. // Try to clean up empty folder
  76. if (QDir(m_absolutePath.AsPosix().c_str()).entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot).empty())
  77. {
  78. AZ::IO::SystemFile::DeleteDir(m_absolutePath.ParentPath().FixedMaxPathStringAsPosix().c_str());
  79. }
  80. AZ_TracePrintf(AssetProcessor::ConsoleChannel, "Deleted product file %s\n", m_absolutePath.c_str());
  81. return true;
  82. }
  83. AZ::u64 ProductAsset::ComputeHash() const
  84. {
  85. return AssetUtilities::GetFileHash(m_absolutePath.c_str());
  86. }
  87. ProductAssetWrapper::ProductAssetWrapper(
  88. const AssetBuilderSDK::JobProduct& jobProduct, const AssetUtilities::ProductPath& productPath)
  89. {
  90. AZ_Error("ProductAsset", AZ::IO::PathView(jobProduct.m_productFileName).IsRelative(), "Job Product m_productFileName (%s) must be relative",
  91. jobProduct.m_productFileName.c_str());
  92. if ((jobProduct.m_outputFlags & AssetBuilderSDK::ProductOutputFlags::ProductAsset) ==
  93. AssetBuilderSDK::ProductOutputFlags::ProductAsset)
  94. {
  95. m_cacheProduct = true;
  96. m_products.emplace_back(AZStd::make_unique<ProductAsset>(productPath.GetCachePath()));
  97. }
  98. if ((jobProduct.m_outputFlags & AssetBuilderSDK::ProductOutputFlags::IntermediateAsset) ==
  99. AssetBuilderSDK::ProductOutputFlags::IntermediateAsset)
  100. {
  101. m_intermediateProduct = true;
  102. m_products.emplace_back(AZStd::make_unique<ProductAsset>(productPath.GetIntermediatePath()));
  103. }
  104. }
  105. ProductAssetWrapper::ProductAssetWrapper(
  106. const AzToolsFramework::AssetDatabase::ProductDatabaseEntry& product,
  107. const AssetUtilities::ProductPath& productPath)
  108. {
  109. if((static_cast<AssetBuilderSDK::ProductOutputFlags>(product.m_flags.to_ullong()) & AssetBuilderSDK::ProductOutputFlags::ProductAsset) ==
  110. AssetBuilderSDK::ProductOutputFlags::ProductAsset)
  111. {
  112. m_cacheProduct = true;
  113. m_products.emplace_back(AZStd::make_unique<ProductAsset>(productPath.GetCachePath()));
  114. }
  115. if((static_cast<AssetBuilderSDK::ProductOutputFlags>(product.m_flags.to_ullong()) & AssetBuilderSDK::ProductOutputFlags::IntermediateAsset) ==
  116. AssetBuilderSDK::ProductOutputFlags::IntermediateAsset)
  117. {
  118. m_intermediateProduct = true;
  119. m_products.emplace_back(AZStd::make_unique<ProductAsset>(productPath.GetIntermediatePath()));
  120. }
  121. }
  122. bool ProductAssetWrapper::IsValid() const
  123. {
  124. return AZStd::all_of(
  125. m_products.begin(), m_products.end(),
  126. [](const AZStd::unique_ptr<ProductAsset>& productAsset)
  127. {
  128. return productAsset && productAsset->IsValid();
  129. });
  130. }
  131. bool ProductAssetWrapper::ExistOnDisk(bool printErrorMessage) const
  132. {
  133. return AZStd::all_of(
  134. m_products.begin(), m_products.end(),
  135. [printErrorMessage](const AZStd::unique_ptr<ProductAsset>& productAsset)
  136. {
  137. return productAsset->ExistsOnDisk(printErrorMessage);
  138. });
  139. }
  140. bool ProductAssetWrapper::HasCacheProduct() const
  141. {
  142. return m_cacheProduct;
  143. }
  144. bool ProductAssetWrapper::HasIntermediateProduct() const
  145. {
  146. return m_intermediateProduct;
  147. }
  148. bool ProductAssetWrapper::DeleteFiles(bool sendNotification) const
  149. {
  150. bool success = true;
  151. // Use a manual loop here since we want to be sure we attempt to delete every file even if one doesn't exist
  152. for(const auto& product : m_products)
  153. {
  154. success = product->DeleteFile(sendNotification) && success;
  155. }
  156. return success;
  157. }
  158. AZ::u64 ProductAssetWrapper::ComputeHash() const
  159. {
  160. for (const auto& product : m_products)
  161. {
  162. if (product)
  163. {
  164. // We just need one of the hashes, they should all be the same
  165. return product->ComputeHash();
  166. }
  167. }
  168. return 0;
  169. }
  170. }