2021-05-12 15:46:19 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "DerivedDataBuildOutput.h"
|
|
|
|
|
|
|
|
|
|
#include "Algo/BinarySearch.h"
|
2021-11-24 13:25:25 -05:00
|
|
|
#include "Algo/Find.h"
|
2021-05-12 15:46:19 -04:00
|
|
|
#include "Containers/StringView.h"
|
|
|
|
|
#include "Containers/UnrealString.h"
|
|
|
|
|
#include "DerivedDataBuildKey.h"
|
|
|
|
|
#include "DerivedDataBuildPrivate.h"
|
|
|
|
|
#include "DerivedDataCacheRecord.h"
|
2022-01-06 11:05:57 -05:00
|
|
|
#include "DerivedDataValue.h"
|
2021-05-12 15:46:19 -04:00
|
|
|
#include "Misc/StringBuilder.h"
|
|
|
|
|
#include "Serialization/CompactBinary.h"
|
|
|
|
|
#include "Serialization/CompactBinaryWriter.h"
|
|
|
|
|
|
|
|
|
|
namespace UE::DerivedData::Private
|
|
|
|
|
{
|
|
|
|
|
|
2021-11-24 13:25:25 -05:00
|
|
|
static FUtf8StringView LexToString(EBuildOutputMessageLevel Level)
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
|
|
|
|
switch (Level)
|
|
|
|
|
{
|
2021-11-24 13:25:25 -05:00
|
|
|
case EBuildOutputMessageLevel::Error: return "Error"_U8SV;
|
|
|
|
|
case EBuildOutputMessageLevel::Warning: return "Warning"_U8SV;
|
|
|
|
|
case EBuildOutputMessageLevel::Display: return "Display"_U8SV;
|
|
|
|
|
default: return "Unknown"_U8SV;
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-24 13:25:25 -05:00
|
|
|
static bool TryLexFromString(EBuildOutputMessageLevel& OutLevel, FUtf8StringView String)
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2021-11-24 13:25:25 -05:00
|
|
|
if (String.Equals("Error"_U8SV, ESearchCase::CaseSensitive))
|
|
|
|
|
{
|
|
|
|
|
OutLevel = EBuildOutputMessageLevel::Error;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-08-02 12:15:42 -04:00
|
|
|
if (String.Equals("Warning"_U8SV, ESearchCase::CaseSensitive))
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2021-11-24 13:25:25 -05:00
|
|
|
OutLevel = EBuildOutputMessageLevel::Warning;
|
|
|
|
|
return true;
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
2021-11-24 13:25:25 -05:00
|
|
|
if (String.Equals("Display"_U8SV, ESearchCase::CaseSensitive))
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2021-11-24 13:25:25 -05:00
|
|
|
OutLevel = EBuildOutputMessageLevel::Display;
|
|
|
|
|
return true;
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
2021-11-24 13:25:25 -05:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FUtf8StringView LexToString(EBuildOutputLogLevel Level)
|
|
|
|
|
{
|
|
|
|
|
switch (Level)
|
|
|
|
|
{
|
|
|
|
|
case EBuildOutputLogLevel::Error: return "Error"_U8SV;
|
|
|
|
|
case EBuildOutputLogLevel::Warning: return "Warning"_U8SV;
|
|
|
|
|
default: return "Unknown"_U8SV;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool TryLexFromString(EBuildOutputLogLevel& OutLevel, FUtf8StringView String)
|
|
|
|
|
{
|
|
|
|
|
if (String.Equals("Error"_U8SV, ESearchCase::CaseSensitive))
|
|
|
|
|
{
|
|
|
|
|
OutLevel = EBuildOutputLogLevel::Error;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (String.Equals("Warning"_U8SV, ESearchCase::CaseSensitive))
|
|
|
|
|
{
|
|
|
|
|
OutLevel = EBuildOutputLogLevel::Warning;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
class FBuildOutputBuilderInternal final : public IBuildOutputBuilderInternal
|
|
|
|
|
{
|
|
|
|
|
public:
|
2021-05-20 21:54:47 -04:00
|
|
|
explicit FBuildOutputBuilderInternal(FStringView InName, FStringView InFunction)
|
|
|
|
|
: Name(InName)
|
|
|
|
|
, Function(InFunction)
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2021-05-20 21:54:47 -04:00
|
|
|
checkf(!Name.IsEmpty(), TEXT("A build output requires a non-empty name."));
|
2021-05-31 12:24:20 -04:00
|
|
|
AssertValidBuildFunctionName(Function, Name);
|
2021-11-24 13:25:25 -05:00
|
|
|
MessageWriter.BeginArray();
|
|
|
|
|
LogWriter.BeginArray();
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~FBuildOutputBuilderInternal() final = default;
|
|
|
|
|
|
2021-11-24 13:25:25 -05:00
|
|
|
void SetMeta(FCbObject&& InMeta) final { Meta = MoveTemp(InMeta); Meta.MakeOwned(); }
|
2022-01-06 11:05:57 -05:00
|
|
|
void AddValue(const FValueId& Id, const FValue& Value) final;
|
2021-11-24 13:25:25 -05:00
|
|
|
void AddMessage(const FBuildOutputMessage& Message) final;
|
|
|
|
|
void AddLog(const FBuildOutputLog& Log) final;
|
2021-05-12 17:57:54 -04:00
|
|
|
bool HasError() const final { return bHasError; }
|
2021-05-12 15:46:19 -04:00
|
|
|
FBuildOutput Build() final;
|
|
|
|
|
|
|
|
|
|
FString Name;
|
|
|
|
|
FString Function;
|
|
|
|
|
FCbObject Meta;
|
2022-01-06 11:05:57 -05:00
|
|
|
TArray<FValueWithId> Values;
|
2021-11-24 13:25:25 -05:00
|
|
|
FCbWriter MessageWriter;
|
|
|
|
|
FCbWriter LogWriter;
|
|
|
|
|
bool bHasMessages = false;
|
|
|
|
|
bool bHasLogs = false;
|
|
|
|
|
bool bHasError = false;
|
2021-05-12 15:46:19 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class FBuildOutputInternal final : public IBuildOutputInternal
|
|
|
|
|
{
|
|
|
|
|
public:
|
2022-01-06 11:05:57 -05:00
|
|
|
FBuildOutputInternal(FString&& Name, FString&& Function, FCbObject&& Meta, FCbObject&& Output, TArray<FValueWithId>&& Values);
|
2021-11-24 13:25:25 -05:00
|
|
|
FBuildOutputInternal(FStringView Name, FStringView Function, const FCbObject& Output, bool& bOutIsValid);
|
|
|
|
|
FBuildOutputInternal(FStringView Name, FStringView Function, const FCacheRecord& Output, bool& bOutIsValid);
|
2021-05-12 15:46:19 -04:00
|
|
|
|
|
|
|
|
~FBuildOutputInternal() final = default;
|
|
|
|
|
|
|
|
|
|
FStringView GetName() const final { return Name; }
|
|
|
|
|
FStringView GetFunction() const final { return Function; }
|
|
|
|
|
|
|
|
|
|
const FCbObject& GetMeta() const final { return Meta; }
|
|
|
|
|
|
2022-01-06 11:05:57 -05:00
|
|
|
const FValueWithId& GetValue(const FValueId& Id) const final;
|
|
|
|
|
TConstArrayView<FValueWithId> GetValues() const final { return Values; }
|
2021-11-24 13:25:25 -05:00
|
|
|
TConstArrayView<FBuildOutputMessage> GetMessages() const final { return Messages; }
|
|
|
|
|
TConstArrayView<FBuildOutputLog> GetLogs() const final { return Logs; }
|
|
|
|
|
bool HasLogs() const final { return !Logs.IsEmpty(); }
|
2021-05-12 17:57:54 -04:00
|
|
|
bool HasError() const final;
|
2021-05-12 15:46:19 -04:00
|
|
|
|
2021-11-24 13:25:25 -05:00
|
|
|
bool TryLoad();
|
|
|
|
|
|
2021-05-14 14:47:11 -04:00
|
|
|
void Save(FCbWriter& Writer) const final;
|
|
|
|
|
void Save(FCacheRecordBuilder& RecordBuilder) const final;
|
|
|
|
|
|
2021-05-12 15:46:19 -04:00
|
|
|
inline void AddRef() const final
|
|
|
|
|
{
|
|
|
|
|
ReferenceCount.fetch_add(1, std::memory_order_relaxed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void Release() const final
|
|
|
|
|
{
|
|
|
|
|
if (ReferenceCount.fetch_sub(1, std::memory_order_acq_rel) == 1)
|
|
|
|
|
{
|
|
|
|
|
delete this;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
FString Name;
|
|
|
|
|
FString Function;
|
2021-05-20 21:54:47 -04:00
|
|
|
FCbObject Meta;
|
2021-11-24 13:25:25 -05:00
|
|
|
FCbObject Output;
|
2022-01-06 11:05:57 -05:00
|
|
|
TArray<FValueWithId> Values;
|
2021-11-24 13:25:25 -05:00
|
|
|
TArray<FBuildOutputMessage> Messages;
|
|
|
|
|
TArray<FBuildOutputLog> Logs;
|
2021-05-20 21:54:47 -04:00
|
|
|
mutable std::atomic<uint32> ReferenceCount{0};
|
2021-05-12 15:46:19 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2021-11-24 13:25:25 -05:00
|
|
|
FBuildOutputInternal::FBuildOutputInternal(
|
|
|
|
|
FString&& InName,
|
|
|
|
|
FString&& InFunction,
|
|
|
|
|
FCbObject&& InMeta,
|
|
|
|
|
FCbObject&& InOutput,
|
2022-01-06 11:05:57 -05:00
|
|
|
TArray<FValueWithId>&& InValues)
|
2021-11-24 13:25:25 -05:00
|
|
|
: Name(MoveTemp(InName))
|
|
|
|
|
, Function(MoveTemp(InFunction))
|
|
|
|
|
, Meta(MoveTemp(InMeta))
|
|
|
|
|
, Output(MoveTemp(InOutput))
|
2022-01-06 11:05:57 -05:00
|
|
|
, Values(MoveTemp(InValues))
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2021-11-24 13:25:25 -05:00
|
|
|
Meta.MakeOwned();
|
|
|
|
|
Output.MakeOwned();
|
|
|
|
|
TryLoad();
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
|
2021-05-14 14:47:11 -04:00
|
|
|
FBuildOutputInternal::FBuildOutputInternal(FStringView InName, FStringView InFunction, const FCbObject& InOutput, bool& bOutIsValid)
|
2021-05-14 15:08:12 -04:00
|
|
|
: Name(InName)
|
|
|
|
|
, Function(InFunction)
|
2021-11-24 13:25:25 -05:00
|
|
|
, Output(InOutput)
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2021-05-20 21:54:47 -04:00
|
|
|
checkf(!Name.IsEmpty(), TEXT("A build output requires a non-empty name."));
|
2021-05-31 12:24:20 -04:00
|
|
|
AssertValidBuildFunctionName(Function, Name);
|
2021-11-24 13:25:25 -05:00
|
|
|
Output.MakeOwned();
|
|
|
|
|
FCbField MetaField = InOutput["Meta"_ASV];
|
|
|
|
|
bOutIsValid = TryLoad() && (!MetaField || MetaField.IsObject());
|
|
|
|
|
Meta = MoveTemp(MetaField).AsObject();
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
|
2021-05-14 14:47:11 -04:00
|
|
|
FBuildOutputInternal::FBuildOutputInternal(FStringView InName, FStringView InFunction, const FCacheRecord& InOutput, bool& bOutIsValid)
|
|
|
|
|
: Name(InName)
|
|
|
|
|
, Function(InFunction)
|
|
|
|
|
, Meta(InOutput.GetMeta())
|
2021-12-13 15:24:25 -05:00
|
|
|
, Output(InOutput.GetValue().GetData().Decompress())
|
2022-01-06 11:05:57 -05:00
|
|
|
, Values(InOutput.GetAttachments())
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2021-05-20 21:54:47 -04:00
|
|
|
checkf(!Name.IsEmpty(), TEXT("A build output requires a non-empty name."));
|
2021-05-31 12:24:20 -04:00
|
|
|
AssertValidBuildFunctionName(Function, Name);
|
2021-11-24 13:25:25 -05:00
|
|
|
bOutIsValid = TryLoad();
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
|
2022-01-06 11:05:57 -05:00
|
|
|
const FValueWithId& FBuildOutputInternal::GetValue(const FValueId& Id) const
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2022-01-06 11:05:57 -05:00
|
|
|
const int32 Index = Algo::BinarySearchBy(Values, Id, &FValueWithId::GetId);
|
|
|
|
|
return Values.IsValidIndex(Index) ? Values[Index] : FValueWithId::Null;
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
|
2021-05-12 17:57:54 -04:00
|
|
|
bool FBuildOutputInternal::HasError() const
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2021-11-24 13:25:25 -05:00
|
|
|
return Algo::FindBy(Messages, EBuildOutputMessageLevel::Error, &FBuildOutputMessage::Level) ||
|
|
|
|
|
Algo::FindBy(Logs, EBuildOutputLogLevel::Error, &FBuildOutputLog::Level);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FBuildOutputInternal::TryLoad()
|
|
|
|
|
{
|
|
|
|
|
const FCbObjectView OutputView = Output;
|
|
|
|
|
|
2022-01-06 11:05:57 -05:00
|
|
|
if (Values.IsEmpty())
|
2021-05-12 17:57:54 -04:00
|
|
|
{
|
2022-01-06 11:05:57 -05:00
|
|
|
for (FCbFieldView Value : OutputView["Payloads"_ASV])
|
2021-05-12 17:57:54 -04:00
|
|
|
{
|
2022-01-06 11:05:57 -05:00
|
|
|
const FValueId Id = Value["Id"_ASV].AsObjectId();
|
|
|
|
|
const FIoHash& RawHash = Value["RawHash"_ASV].AsAttachment();
|
|
|
|
|
const uint64 RawSize = Value["RawSize"_ASV].AsUInt64(MAX_uint64);
|
2021-11-24 13:25:25 -05:00
|
|
|
if (Id.IsNull() || RawHash.IsZero() || RawSize == MAX_uint64)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-01-06 11:05:57 -05:00
|
|
|
Values.Emplace(Id, RawHash, RawSize);
|
2021-05-12 17:57:54 -04:00
|
|
|
}
|
|
|
|
|
}
|
2021-11-24 13:25:25 -05:00
|
|
|
|
|
|
|
|
if (FCbFieldView MessagesField = OutputView["Messages"_ASV])
|
|
|
|
|
{
|
|
|
|
|
if (!MessagesField.IsArray())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
Messages.Reserve(MessagesField.AsArrayView().Num());
|
|
|
|
|
for (FCbFieldView MessageField : MessagesField)
|
|
|
|
|
{
|
|
|
|
|
const FUtf8StringView LevelName = MessageField["Level"_ASV].AsString();
|
|
|
|
|
const FUtf8StringView Message = MessageField["Message"_ASV].AsString();
|
|
|
|
|
EBuildOutputMessageLevel Level;
|
|
|
|
|
if (LevelName.IsEmpty() || Message.IsEmpty() || !TryLexFromString(Level, LevelName))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
Messages.Add({Message, Level});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FCbFieldView LogsField = OutputView["Logs"_ASV])
|
|
|
|
|
{
|
|
|
|
|
if (!LogsField.IsArray())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
Logs.Reserve(LogsField.AsArrayView().Num());
|
|
|
|
|
for (FCbFieldView LogField : LogsField)
|
|
|
|
|
{
|
|
|
|
|
const FUtf8StringView LevelName = LogField["Level"_ASV].AsString();
|
|
|
|
|
const FUtf8StringView Category = LogField["Category"_ASV].AsString();
|
|
|
|
|
const FUtf8StringView Message = LogField["Message"_ASV].AsString();
|
|
|
|
|
EBuildOutputLogLevel Level;
|
|
|
|
|
if (LevelName.IsEmpty() || Category.IsEmpty() || Message.IsEmpty() || !TryLexFromString(Level, LevelName))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
Logs.Add({Category, Message, Level});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FBuildOutputInternal::Save(FCbWriter& Writer) const
|
|
|
|
|
{
|
|
|
|
|
Writer.BeginObject();
|
2022-01-06 11:05:57 -05:00
|
|
|
if (!Values.IsEmpty())
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
|
|
|
|
Writer.BeginArray("Payloads"_ASV);
|
2022-01-06 11:05:57 -05:00
|
|
|
for (const FValueWithId& Value : Values)
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
|
|
|
|
Writer.BeginObject();
|
2022-01-06 11:05:57 -05:00
|
|
|
Writer.AddObjectId("Id"_ASV, Value.GetId());
|
|
|
|
|
Writer.AddBinaryAttachment("RawHash"_ASV, Value.GetRawHash());
|
|
|
|
|
Writer.AddInteger("RawSize"_ASV, Value.GetRawSize());
|
2021-05-12 15:46:19 -04:00
|
|
|
Writer.EndObject();
|
|
|
|
|
}
|
|
|
|
|
Writer.EndArray();
|
|
|
|
|
}
|
2021-11-24 13:25:25 -05:00
|
|
|
if (FCbField MessagesField = Output["Messages"_ASV])
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2021-11-24 13:25:25 -05:00
|
|
|
Writer.AddField("Messages"_ASV, MessagesField);
|
|
|
|
|
}
|
|
|
|
|
if (FCbField LogsField = Output["Logs"_ASV])
|
|
|
|
|
{
|
|
|
|
|
Writer.AddField("Logs"_ASV, LogsField);
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
if (Meta)
|
|
|
|
|
{
|
|
|
|
|
Writer.AddObject("Meta"_ASV, Meta);
|
|
|
|
|
}
|
|
|
|
|
Writer.EndObject();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FBuildOutputInternal::Save(FCacheRecordBuilder& RecordBuilder) const
|
|
|
|
|
{
|
|
|
|
|
RecordBuilder.SetMeta(FCbObject(Meta));
|
2021-11-24 13:25:25 -05:00
|
|
|
if (!Messages.IsEmpty() || !Logs.IsEmpty())
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2021-11-24 13:25:25 -05:00
|
|
|
TCbWriter<1024> Writer;
|
|
|
|
|
if (FCbField MessagesField = Output["Messages"_ASV])
|
|
|
|
|
{
|
|
|
|
|
Writer.AddField("Messages"_ASV, MessagesField);
|
|
|
|
|
}
|
|
|
|
|
if (FCbField LogsField = Output["Logs"_ASV])
|
|
|
|
|
{
|
|
|
|
|
Writer.AddField("Logs"_ASV, LogsField);
|
|
|
|
|
}
|
|
|
|
|
RecordBuilder.SetValue(Writer.Save().GetBuffer());
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
2022-01-06 11:05:57 -05:00
|
|
|
for (const FValueWithId& Value : Values)
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2022-01-06 11:05:57 -05:00
|
|
|
RecordBuilder.AddAttachment(Value);
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2022-01-06 11:05:57 -05:00
|
|
|
void FBuildOutputBuilderInternal::AddValue(const FValueId& Id, const FValue& Value)
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2022-01-06 11:05:57 -05:00
|
|
|
checkf(Id.IsValid(), TEXT("Null value added in output for build of '%s' by %s."), *Name, *Function);
|
|
|
|
|
const int32 Index = Algo::LowerBoundBy(Values, Id, &FValueWithId::GetId);
|
|
|
|
|
checkf(!(Values.IsValidIndex(Index) && Values[Index].GetId() == Id),
|
|
|
|
|
TEXT("Duplicate ID %s used by value for build of '%s' by %s."), *WriteToString<32>(Id), *Name, *Function);
|
|
|
|
|
Values.Insert(FValueWithId(Id, Value), Index);
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
|
2021-11-24 13:25:25 -05:00
|
|
|
void FBuildOutputBuilderInternal::AddMessage(const FBuildOutputMessage& Message)
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2021-11-24 13:25:25 -05:00
|
|
|
bHasError |= Message.Level == EBuildOutputMessageLevel::Error;
|
|
|
|
|
bHasMessages = true;
|
|
|
|
|
MessageWriter.BeginObject();
|
|
|
|
|
MessageWriter.AddString("Level"_ASV, LexToString(Message.Level));
|
|
|
|
|
MessageWriter.AddString("Message"_ASV, Message.Message);
|
|
|
|
|
MessageWriter.EndObject();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FBuildOutputBuilderInternal::AddLog(const FBuildOutputLog& Log)
|
|
|
|
|
{
|
|
|
|
|
bHasError |= Log.Level == EBuildOutputLogLevel::Error;
|
|
|
|
|
bHasLogs = true;
|
|
|
|
|
LogWriter.BeginObject();
|
|
|
|
|
LogWriter.AddString("Level"_ASV, LexToString(Log.Level));
|
|
|
|
|
LogWriter.AddString("Category"_ASV, Log.Category);
|
|
|
|
|
LogWriter.AddString("Message"_ASV, Log.Message);
|
|
|
|
|
LogWriter.EndObject();
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FBuildOutput FBuildOutputBuilderInternal::Build()
|
|
|
|
|
{
|
2021-11-24 13:25:25 -05:00
|
|
|
if (bHasError)
|
2021-05-12 15:46:19 -04:00
|
|
|
{
|
2022-01-06 11:05:57 -05:00
|
|
|
Values.Empty();
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
2021-11-24 13:25:25 -05:00
|
|
|
MessageWriter.EndArray();
|
|
|
|
|
LogWriter.EndArray();
|
|
|
|
|
FCbObject Output;
|
|
|
|
|
if (bHasMessages || bHasLogs)
|
|
|
|
|
{
|
|
|
|
|
TCbWriter<1024> Writer;
|
|
|
|
|
Writer.BeginObject();
|
|
|
|
|
if (bHasMessages)
|
|
|
|
|
{
|
|
|
|
|
Writer.AddArray("Messages"_ASV, MessageWriter.Save().AsArray());
|
|
|
|
|
MessageWriter.Reset();
|
|
|
|
|
}
|
|
|
|
|
if (bHasLogs)
|
|
|
|
|
{
|
|
|
|
|
Writer.AddArray("Logs"_ASV, LogWriter.Save().AsArray());
|
|
|
|
|
LogWriter.Reset();
|
|
|
|
|
}
|
|
|
|
|
Writer.EndObject();
|
|
|
|
|
Output = Writer.Save().AsObject();
|
|
|
|
|
}
|
2022-01-06 11:05:57 -05:00
|
|
|
return CreateBuildOutput(new FBuildOutputInternal(MoveTemp(Name), MoveTemp(Function), MoveTemp(Meta), MoveTemp(Output), MoveTemp(Values)));
|
2021-05-12 15:46:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
FBuildOutput CreateBuildOutput(IBuildOutputInternal* Output)
|
|
|
|
|
{
|
|
|
|
|
return FBuildOutput(Output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FBuildOutputBuilder CreateBuildOutputBuilder(IBuildOutputBuilderInternal* OutputBuilder)
|
|
|
|
|
{
|
|
|
|
|
return FBuildOutputBuilder(OutputBuilder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FBuildOutputBuilder CreateBuildOutput(FStringView Name, FStringView Function)
|
|
|
|
|
{
|
|
|
|
|
return CreateBuildOutputBuilder(new FBuildOutputBuilderInternal(Name, Function));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // UE::DerivedData::Private
|
2021-08-06 11:58:24 -04:00
|
|
|
|
|
|
|
|
namespace UE::DerivedData
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
FOptionalBuildOutput FBuildOutput::Load(FStringView Name, FStringView Function, const FCbObject& Output)
|
|
|
|
|
{
|
|
|
|
|
bool bIsValid = false;
|
|
|
|
|
FOptionalBuildOutput Out = Private::CreateBuildOutput(
|
|
|
|
|
new Private::FBuildOutputInternal(Name, Function, Output, bIsValid));
|
|
|
|
|
if (!bIsValid)
|
|
|
|
|
{
|
|
|
|
|
Out.Reset();
|
|
|
|
|
}
|
|
|
|
|
return Out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FOptionalBuildOutput FBuildOutput::Load(FStringView Name, FStringView Function, const FCacheRecord& Output)
|
|
|
|
|
{
|
|
|
|
|
bool bIsValid = false;
|
|
|
|
|
FOptionalBuildOutput Out = Private::CreateBuildOutput(
|
|
|
|
|
new Private::FBuildOutputInternal(Name, Function, Output, bIsValid));
|
|
|
|
|
if (!bIsValid)
|
|
|
|
|
{
|
|
|
|
|
Out.Reset();
|
|
|
|
|
}
|
|
|
|
|
return Out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // UE::DerivedData
|