2022-12-09 03:39:15 -05:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
2023-01-13 04:29:19 -05:00
|
|
|
#include "GeneratePayloadManifestCommandlet.h"
|
2022-12-09 03:39:15 -05:00
|
|
|
|
2023-01-13 03:31:00 -05:00
|
|
|
#include "CommandletUtils.h"
|
2022-12-09 03:39:15 -05:00
|
|
|
#include "HAL/FileManager.h"
|
|
|
|
|
#include "Misc/PackageName.h"
|
|
|
|
|
#include "Misc/PackagePath.h"
|
|
|
|
|
#include "Misc/Paths.h"
|
|
|
|
|
#include "UObject/PackageTrailer.h"
|
|
|
|
|
|
2023-05-11 06:50:09 -04:00
|
|
|
class FSpreadSheet
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
bool OpenNewSheet()
|
|
|
|
|
{
|
|
|
|
|
Ar.Reset();
|
|
|
|
|
|
|
|
|
|
const TStringBuilder<512> CSVPath = GetFilePath(++NumSheets);
|
|
|
|
|
|
|
|
|
|
Ar = TUniquePtr<FArchive>(IFileManager::Get().CreateFileWriter(CSVPath.ToString()));
|
|
|
|
|
if (Ar.IsValid())
|
|
|
|
|
{
|
|
|
|
|
const ANSICHAR* Headings = "Path,PayloadId,SizeOnDisk,UncompressedSize,StorageType, FilterReason\n";
|
|
|
|
|
Ar->Serialize((void*)Headings, FPlatformString::Strlen(Headings));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualization, Error, TEXT("Failed to open '%s' for write"), CSVPath.ToString());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PrintRow(FAnsiStringView Row)
|
|
|
|
|
{
|
|
|
|
|
if (++NumRowsInSheet >= MaxNumRowsPerSheet || (Ar->Tell() + Row.Len()) >= MaxFileSize)
|
|
|
|
|
{
|
|
|
|
|
if (!OpenNewSheet())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NumRowsInSheet = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ar->Serialize((void*)Row.GetData(), Row.Len() * sizeof(FAnsiStringView::ElementType));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Flush()
|
|
|
|
|
{
|
|
|
|
|
Ar.Reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FString GetDebugInfo() const
|
|
|
|
|
{
|
|
|
|
|
TStringBuilder<1024> Output;
|
|
|
|
|
|
|
|
|
|
Output << TEXT("Manifest is comprised of ") << NumSheets << TEXT(" sheet(s) written to:");
|
|
|
|
|
|
|
|
|
|
for (int32 Index = 0; Index < NumSheets; ++Index)
|
|
|
|
|
{
|
|
|
|
|
Output << LINE_TERMINATOR << GetFilePath(Index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Output.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
static TStringBuilder<512> GetFilePath(int32 Index)
|
|
|
|
|
{
|
|
|
|
|
return WriteToString<512>(FPaths::ProjectSavedDir(), TEXT("PayloadManifest/sheet"), Index, TEXT(".csv"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// With any values above these we had trouble importing the finished cvs into various spread sheet programs
|
|
|
|
|
const int64 MaxNumRowsPerSheet = 250000;
|
|
|
|
|
const int64 MaxFileSize = 45 * 1024 * 1024;
|
|
|
|
|
|
|
|
|
|
int32 NumSheets = 0;
|
|
|
|
|
int32 NumRowsInSheet = 0;
|
|
|
|
|
|
|
|
|
|
TUniquePtr<FArchive> Ar;
|
|
|
|
|
};
|
|
|
|
|
|
2022-12-09 03:39:15 -05:00
|
|
|
UGeneratePayloadManifestCommandlet::UGeneratePayloadManifestCommandlet(const FObjectInitializer& ObjectInitializer)
|
|
|
|
|
: Super(ObjectInitializer)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32 UGeneratePayloadManifestCommandlet::Main(const FString& Params)
|
|
|
|
|
{
|
|
|
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(UGeneratePayloadManifestCommandlet);
|
|
|
|
|
|
2023-05-11 04:51:23 -04:00
|
|
|
if (!ParseCmdline(Params))
|
|
|
|
|
{
|
|
|
|
|
UE_LOG(LogVirtualization, Error, TEXT("Failed to parse the command line correctly"));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-01 03:47:24 -05:00
|
|
|
TArray<FString> PackageNames = UE::Virtualization::DiscoverPackages(Params, UE::Virtualization::EFindPackageFlags::ExcludeEngineContent);
|
2022-12-09 03:39:15 -05:00
|
|
|
|
|
|
|
|
UE_LOG(LogVirtualization, Display, TEXT("Found %d files to look in"), PackageNames.Num());
|
|
|
|
|
|
|
|
|
|
int32 PackageTrailerCount = 0;
|
2023-05-11 06:50:09 -04:00
|
|
|
int32 PayloadCount = 0;
|
2022-12-09 03:39:15 -05:00
|
|
|
|
2023-05-11 06:50:09 -04:00
|
|
|
FSpreadSheet Sheet;
|
|
|
|
|
if (!Sheet.OpenNewSheet())
|
2022-12-09 03:39:15 -05:00
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(ParsePackageTrailers);
|
|
|
|
|
|
|
|
|
|
UE_LOG(LogVirtualization, Display, TEXT("Parsing files..."));
|
|
|
|
|
|
|
|
|
|
uint32 FilesParsed = 0;
|
|
|
|
|
for (const FString& PackagePath : PackageNames)
|
|
|
|
|
{
|
|
|
|
|
if (FPackageName::IsPackageFilename(PackagePath))
|
|
|
|
|
{
|
|
|
|
|
UE::FPackageTrailer Trailer;
|
|
|
|
|
if (UE::FPackageTrailer::TryLoadFromFile(PackagePath, Trailer))
|
|
|
|
|
{
|
|
|
|
|
PackageTrailerCount++;
|
|
|
|
|
|
2023-05-11 06:50:09 -04:00
|
|
|
Trailer.ForEachPayload([&Sheet, &PackagePath, &PayloadCount, bLocalOnly = bLocalOnly](const FIoHash& Id, uint64 SizeOnDisk, uint64 RawSize, UE::EPayloadAccessMode Mode, UE::Virtualization::EPayloadFilterReason Filter)->void
|
2022-12-09 03:39:15 -05:00
|
|
|
{
|
2023-05-11 04:51:23 -04:00
|
|
|
if (bLocalOnly && Mode != UE::EPayloadAccessMode::Local)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-11 06:50:09 -04:00
|
|
|
PayloadCount++;
|
|
|
|
|
|
2022-12-09 03:39:15 -05:00
|
|
|
TAnsiStringBuilder<256> LineBuilder;
|
|
|
|
|
LineBuilder << PackagePath << "," << Id << "," << SizeOnDisk << "," << RawSize << "," << Mode << "," << *LexToString(Filter) <<"\n";
|
2023-05-11 06:50:09 -04:00
|
|
|
|
|
|
|
|
Sheet.PrintRow(LineBuilder);
|
2022-12-09 03:39:15 -05:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (++FilesParsed % 10000 == 0)
|
|
|
|
|
{
|
|
|
|
|
float PercentCompleted = ((float)FilesParsed / (float)PackageNames.Num()) * 100.0f;
|
|
|
|
|
UE_LOG(LogVirtualization, Display, TEXT("Parsed %d/%d (%.0f%%)"), FilesParsed, PackageNames.Num(), PercentCompleted);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-11 06:50:09 -04:00
|
|
|
Sheet.Flush();
|
2022-12-09 03:39:15 -05:00
|
|
|
|
2023-05-11 06:50:09 -04:00
|
|
|
UE_LOG(LogVirtualization, Display, TEXT("Found %d package trailers with %d payloads"), PackageTrailerCount, PayloadCount);
|
|
|
|
|
UE_LOG(LogVirtualization, Display, TEXT("%s"), *Sheet.GetDebugInfo());
|
2022-12-09 03:39:15 -05:00
|
|
|
|
|
|
|
|
return 0;
|
2023-05-11 04:51:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UGeneratePayloadManifestCommandlet::ParseCmdline(const FString& Params)
|
|
|
|
|
{
|
|
|
|
|
TArray<FString> Tokens;
|
|
|
|
|
TArray<FString> Switches;
|
|
|
|
|
|
|
|
|
|
ParseCommandLine(*Params, Tokens, Switches);
|
|
|
|
|
|
|
|
|
|
bLocalOnly = Switches.Contains(TEXT("LocalOnly"));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|