Make prefab patch application use a best effort mechanism
Signed-off-by: srikappa <srikappa@amazon.com>
This commit is contained in:
@@ -110,7 +110,15 @@ namespace AZ
|
|||||||
|
|
||||||
if (result.GetProcessing() == Processing::Halted)
|
if (result.GetProcessing() == Processing::Halted)
|
||||||
{
|
{
|
||||||
return result;
|
ResultCode reportedResult = settings.m_reporting(R"(One of the patches couldn't be applied correctly.)", result, element);
|
||||||
|
if (reportedResult.GetOutcome() == Outcomes::PartialSkip)
|
||||||
|
{
|
||||||
|
result = reportedResult;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AzCore/Math/Vector3.h>
|
#include <AzCore/Math/Vector3.h>
|
||||||
|
#include <AzCore/Serialization/Json/JsonSerializationSettings.h>
|
||||||
#include <AzCore/std/string/string_view.h>
|
#include <AzCore/std/string/string_view.h>
|
||||||
#include <Tests/Serialization/Json/JsonSerializationTests.h>
|
#include <Tests/Serialization/Json/JsonSerializationTests.h>
|
||||||
|
|
||||||
@@ -43,7 +44,9 @@ namespace JsonSerializationTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CheckApplyPatchOutcome(const char* target, const char* patch,
|
void CheckApplyPatchOutcome(const char* target, const char* patch,
|
||||||
AZ::JsonSerializationResult::Outcomes outcome, AZ::JsonSerializationResult::Processing processing)
|
AZ::JsonSerializationResult::Outcomes outcome,
|
||||||
|
AZ::JsonSerializationResult::Processing processing,
|
||||||
|
const AZ::JsonApplyPatchSettings& settings = AZ::JsonApplyPatchSettings{})
|
||||||
{
|
{
|
||||||
m_jsonDocument->Parse(target);
|
m_jsonDocument->Parse(target);
|
||||||
ASSERT_FALSE(m_jsonDocument->HasParseError());
|
ASSERT_FALSE(m_jsonDocument->HasParseError());
|
||||||
@@ -53,12 +56,27 @@ namespace JsonSerializationTests
|
|||||||
ASSERT_FALSE(patchDocument.HasParseError());
|
ASSERT_FALSE(patchDocument.HasParseError());
|
||||||
|
|
||||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(*m_jsonDocument,
|
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(*m_jsonDocument,
|
||||||
m_jsonDocument->GetAllocator(), patchDocument, AZ::JsonMergeApproach::JsonPatch);
|
m_jsonDocument->GetAllocator(), patchDocument, AZ::JsonMergeApproach::JsonPatch, settings);
|
||||||
EXPECT_EQ(result.GetTask(), AZ::JsonSerializationResult::Tasks::Merge);
|
EXPECT_EQ(result.GetTask(), AZ::JsonSerializationResult::Tasks::Merge);
|
||||||
EXPECT_EQ(result.GetOutcome(), outcome);
|
EXPECT_EQ(result.GetOutcome(), outcome);
|
||||||
EXPECT_EQ(result.GetProcessing(), processing);
|
EXPECT_EQ(result.GetProcessing(), processing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckApplyPatchOutcome(
|
||||||
|
const char* target,
|
||||||
|
const char* patch,
|
||||||
|
const char* expectedPatchedResult,
|
||||||
|
AZ::JsonSerializationResult::Outcomes outcome,
|
||||||
|
AZ::JsonSerializationResult::Processing processing,
|
||||||
|
const AZ::JsonApplyPatchSettings& settings = AZ::JsonApplyPatchSettings{})
|
||||||
|
{
|
||||||
|
CheckApplyPatchOutcome(target, patch, outcome, processing, settings);
|
||||||
|
rapidjson::Document expectedPatchedDocument;
|
||||||
|
expectedPatchedDocument.Parse(expectedPatchedResult);
|
||||||
|
ASSERT_FALSE(expectedPatchedDocument.HasParseError());
|
||||||
|
EXPECT_EQ(AZ::JsonSerialization::Compare(expectedPatchedDocument, *m_jsonDocument), AZ::JsonSerializerCompareResult::Equal);
|
||||||
|
}
|
||||||
|
|
||||||
void CheckCreatePatch_Core(const char* source, AZStd::string_view patch, const char* target,
|
void CheckCreatePatch_Core(const char* source, AZStd::string_view patch, const char* target,
|
||||||
AZ::JsonMergeApproach approach)
|
AZ::JsonMergeApproach approach)
|
||||||
{
|
{
|
||||||
@@ -262,6 +280,36 @@ namespace JsonSerializationTests
|
|||||||
Outcomes::TypeMismatch, Processing::Halted);
|
Outcomes::TypeMismatch, Processing::Halted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(JsonPatchingSerializationTests, ApplyPatch_UseJsonPatchWithCustomReportingCallback_ReportPartialSkip)
|
||||||
|
{
|
||||||
|
using namespace AZ::JsonSerializationResult;
|
||||||
|
auto issueReportingCallback = [](AZStd::string_view, AZ::JsonSerializationResult::ResultCode result,
|
||||||
|
AZStd::string_view) -> AZ::JsonSerializationResult::ResultCode
|
||||||
|
{
|
||||||
|
using namespace AZ::JsonSerializationResult;
|
||||||
|
if (result.GetProcessing() == Processing::Halted)
|
||||||
|
{
|
||||||
|
return ResultCode(result.GetTask(), Outcomes::PartialSkip);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
AZ::JsonApplyPatchSettings applyPatchSettings;
|
||||||
|
applyPatchSettings.m_reporting = AZStd::move(issueReportingCallback);
|
||||||
|
CheckApplyPatchOutcome(
|
||||||
|
R"({})",
|
||||||
|
R"([
|
||||||
|
{ "op": "add", "path": "/nonexistent_key/new_member", "value": "someValue" },
|
||||||
|
{ "op": "add", "path": "/test", "value": "someValue" }
|
||||||
|
])",
|
||||||
|
R"(
|
||||||
|
{ "test": "someValue" }
|
||||||
|
)",
|
||||||
|
Outcomes::PartialSkip,
|
||||||
|
Processing::Completed,
|
||||||
|
AZStd::move(applyPatchSettings));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(JsonPatchingSerializationTests, ApplyPatch_UseJsonPatchAddUnnamedMember_ReportsSuccess)
|
TEST_F(JsonPatchingSerializationTests, ApplyPatch_UseJsonPatchAddUnnamedMember_ReportsSuccess)
|
||||||
{
|
{
|
||||||
CheckApplyPatch(
|
CheckApplyPatch(
|
||||||
|
|||||||
+11
-8
@@ -172,20 +172,23 @@ namespace AzToolsFramework
|
|||||||
PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
|
PrefabDom& templateDomReference = m_prefabSystemComponentInterface->FindTemplateDom(templateId);
|
||||||
|
|
||||||
//apply patch to template
|
//apply patch to template
|
||||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(templateDomReference,
|
AZ::JsonSerializationResult::ResultCode result =
|
||||||
templateDomReference.GetAllocator(), providedPatch, AZ::JsonMergeApproach::JsonPatch);
|
PrefabDomUtils::ApplyPatches(templateDomReference, templateDomReference.GetAllocator(), providedPatch);
|
||||||
|
|
||||||
//trigger propagation
|
//trigger propagation
|
||||||
if (result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success)
|
if (result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::Success)
|
||||||
{
|
{
|
||||||
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, true);
|
AZ_Error("Prefab", false, "Patch was not successfully applied.");
|
||||||
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId, instanceToExclude);
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AZ_Error("Prefab", false, "Patch was not successfully applied");
|
AZ_Error(
|
||||||
return false;
|
"Prefab", result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::PartialSkip,
|
||||||
|
"Some of the patches are not successfully applied.");
|
||||||
|
m_prefabSystemComponentInterface->SetTemplateDirtyFlag(templateId, true);
|
||||||
|
m_prefabSystemComponentInterface->PropagateTemplateChanges(templateId, instanceToExclude);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -176,12 +176,17 @@ namespace AzToolsFramework
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AZ::JsonSerializationResult::ResultCode applyPatchResult = AZ::JsonSerialization::ApplyPatch(
|
AZ::JsonSerializationResult::ResultCode applyPatchResult =
|
||||||
sourceTemplateDomCopy,
|
PrefabDomUtils::ApplyPatches(sourceTemplateDomCopy, targetTemplatePrefabDom.GetAllocator(), patchesReference->get());
|
||||||
targetTemplatePrefabDom.GetAllocator(),
|
|
||||||
patchesReference->get(),
|
|
||||||
AZ::JsonMergeApproach::JsonPatch);
|
|
||||||
linkedInstanceDom.CopyFrom(sourceTemplateDomCopy, targetTemplatePrefabDom.GetAllocator());
|
linkedInstanceDom.CopyFrom(sourceTemplateDomCopy, targetTemplatePrefabDom.GetAllocator());
|
||||||
|
|
||||||
|
PrefabDomValueReference sourceTemplateName =
|
||||||
|
PrefabDomUtils::FindPrefabDomValue(sourceTemplateDomCopy, PrefabDomUtils::SourceName);
|
||||||
|
AZ_Assert(sourceTemplateName && sourceTemplateName->get().IsString(), "A valid source template name couldn't be found");
|
||||||
|
PrefabDomValueReference targetTemplateName =
|
||||||
|
PrefabDomUtils::FindPrefabDomValue(targetTemplatePrefabDom, PrefabDomUtils::SourceName);
|
||||||
|
AZ_Assert(targetTemplateName && targetTemplateName->get().IsString(), "A valid target template name couldn't be found");
|
||||||
|
|
||||||
if (applyPatchResult.GetProcessing() != AZ::JsonSerializationResult::Processing::Completed)
|
if (applyPatchResult.GetProcessing() != AZ::JsonSerializationResult::Processing::Completed)
|
||||||
{
|
{
|
||||||
AZ_Error(
|
AZ_Error(
|
||||||
@@ -190,6 +195,14 @@ namespace AzToolsFramework
|
|||||||
m_sourceTemplateId, m_targetTemplateId);
|
m_sourceTemplateId, m_targetTemplateId);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (applyPatchResult.GetOutcome() == AZ::JsonSerializationResult::Outcomes::PartialSkip)
|
||||||
|
{
|
||||||
|
AZ_Error(
|
||||||
|
"Prefab", false,
|
||||||
|
"Link::UpdateTarget - Some of the patches couldn't be applied on the source template '%s' present under the "
|
||||||
|
"target Template '%s'.",
|
||||||
|
sourceTemplateName->get().GetString(), targetTemplateName->get().GetString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a guardrail to ensure the linked instance dom always has the LinkId value
|
// This is a guardrail to ensure the linked instance dom always has the LinkId value
|
||||||
|
|||||||
@@ -236,6 +236,26 @@ namespace AzToolsFramework
|
|||||||
return findInstancesResult->get();
|
return findInstancesResult->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AZ::JsonSerializationResult::ResultCode ApplyPatches(
|
||||||
|
PrefabDomValue& prefabDomToApplyPatchesOn, PrefabDom::AllocatorType& allocator, const PrefabDomValue& patches)
|
||||||
|
{
|
||||||
|
auto issueReportingCallback = [](AZStd::string_view, AZ::JsonSerializationResult::ResultCode result,
|
||||||
|
AZStd::string_view) -> AZ::JsonSerializationResult::ResultCode
|
||||||
|
{
|
||||||
|
using namespace AZ::JsonSerializationResult;
|
||||||
|
if (result.GetProcessing() == Processing::Halted)
|
||||||
|
{
|
||||||
|
return ResultCode(result.GetTask(), Outcomes::PartialSkip);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
AZ::JsonApplyPatchSettings applyPatchSettings;
|
||||||
|
applyPatchSettings.m_reporting = AZStd::move(issueReportingCallback);
|
||||||
|
return AZ::JsonSerialization::ApplyPatch(
|
||||||
|
prefabDomToApplyPatchesOn, allocator, patches, AZ::JsonMergeApproach::JsonPatch, applyPatchSettings);
|
||||||
|
}
|
||||||
|
|
||||||
void PrintPrefabDomValue(
|
void PrintPrefabDomValue(
|
||||||
[[maybe_unused]] const AZStd::string_view printMessage,
|
[[maybe_unused]] const AZStd::string_view printMessage,
|
||||||
[[maybe_unused]] const PrefabDomValue& prefabDomValue)
|
[[maybe_unused]] const PrefabDomValue& prefabDomValue)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AzCore/Serialization/Json/JsonSerializationResult.h>
|
||||||
#include <AzCore/std/optional.h>
|
#include <AzCore/std/optional.h>
|
||||||
#include <AzCore/Asset/AssetCommon.h>
|
#include <AzCore/Asset/AssetCommon.h>
|
||||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||||
@@ -122,6 +123,11 @@ namespace AzToolsFramework
|
|||||||
*/
|
*/
|
||||||
PrefabDomValueConstReference GetInstancesValue(const PrefabDomValue& prefabDom);
|
PrefabDomValueConstReference GetInstancesValue(const PrefabDomValue& prefabDom);
|
||||||
|
|
||||||
|
AZ::JsonSerializationResult::ResultCode ApplyPatches(
|
||||||
|
PrefabDomValue& prefabDomToApplyPatchesOn,
|
||||||
|
PrefabDom::AllocatorType& allocator,
|
||||||
|
const PrefabDomValue& patches);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints the contents of the given prefab DOM value to the debug output console in a readable format.
|
* Prints the contents of the given prefab DOM value to the debug output console in a readable format.
|
||||||
* @param printMessage The message that will be printed before printing the PrefabDomValue
|
* @param printMessage The message that will be printed before printing the PrefabDomValue
|
||||||
|
|||||||
@@ -261,8 +261,13 @@ namespace AzToolsFramework
|
|||||||
instanceDom.CopyFrom(instanceDomRef->get(), instanceDom.GetAllocator());
|
instanceDom.CopyFrom(instanceDomRef->get(), instanceDom.GetAllocator());
|
||||||
|
|
||||||
//apply the patch to the template within the target
|
//apply the patch to the template within the target
|
||||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(instanceDom,
|
AZ::JsonSerializationResult::ResultCode result = PrefabDomUtils::ApplyPatches(instanceDom, instanceDom.GetAllocator(), patch);
|
||||||
instanceDom.GetAllocator(), patch, AZ::JsonMergeApproach::JsonPatch);
|
|
||||||
|
AZ_Error(
|
||||||
|
"Prefab",
|
||||||
|
result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::PartialSkip &&
|
||||||
|
result.GetOutcome() != AZ::JsonSerializationResult::Outcomes::Success,
|
||||||
|
"Some of the patches are not successfully applied.");
|
||||||
|
|
||||||
//remove the link id placed into the instance
|
//remove the link id placed into the instance
|
||||||
auto linkIdIter = instanceDom.FindMember(PrefabDomUtils::LinkIdName);
|
auto linkIdIter = instanceDom.FindMember(PrefabDomUtils::LinkIdName);
|
||||||
|
|||||||
@@ -96,8 +96,8 @@ namespace UnitTest
|
|||||||
|
|
||||||
//apply the patch
|
//apply the patch
|
||||||
PrefabDom& templateDomReference = m_prefabSystemComponent->FindTemplateDom(nestedTemplateId);
|
PrefabDom& templateDomReference = m_prefabSystemComponent->FindTemplateDom(nestedTemplateId);
|
||||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::ApplyPatch(templateDomReference,
|
AZ::JsonSerializationResult::ResultCode result =
|
||||||
templateDomReference.GetAllocator(), patch, AZ::JsonMergeApproach::JsonPatch);
|
PrefabDomUtils::ApplyPatches(templateDomReference, templateDomReference.GetAllocator(), patch);
|
||||||
|
|
||||||
AZ_Error("Prefab", result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success,
|
AZ_Error("Prefab", result.GetOutcome() == AZ::JsonSerializationResult::Outcomes::Success,
|
||||||
"Patch was not successfully applied");
|
"Patch was not successfully applied");
|
||||||
|
|||||||
Reference in New Issue
Block a user