Files
UnrealEngineUWP/Engine/Source/Programs/UnrealVirtualizationTool/Private/UnrealVirtualizationToolApp.cpp

880 lines
26 KiB
C++
Raw Normal View History

// Copyright Epic Games, Inc. All Rights Reserved.
#include "UnrealVirtualizationToolApp.h"
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
#include "Commands/CommandBase.h"
#include "Commands/RehydrateCommand.h"
UnrealVirtualizationTool can now be given the path of a package or the path of a directory of packages to virtualize in addition to previous functionality. NOTE that all existing functionality should continue to work but using -Mode=Changelist or -Mode=Packagelist will result in a warning prompting the future use of the new versions for those commands. #rb Per.Larsson #jira UE-170657, UE-160396 #rnx #preflight 637c9232fa348e8480bdc7e2 - When the rehydration functionality was added it started to look like more functionality would be added to the tool than originally thought so I started to add the new functionality via a command system. This change now moves the older legacy functionality to the coommand system as well. - Added a new FVirtualizeCommand which can accept package paths, directory paths, packagelist files or changelists as the input. -- Unlike the legacy commands, virtualizing via changelist does not require the client spec to be provided on the commandline, although doing so will avoid several perforce commands and speed up the call. It is expected that people calling the tool on the commandline will probably opt to not supply a clientspec and let the tool workout which workspace a changelist is under, where as calls from other tools (such as P4VUtils) can provide it if already known to speed things up. -- FVirtualizeLegacyChangeListCommand replicates the functionality of the old -Mode=Changelist command. -- FVirtualizeLegacyPackageListCommand replicates the functionality of the old -Mode=Packagelist command. -- The new command will only try to submit the results if a changelist was provided as the input and even then it will not do so by default. The tool now requires people to opt into submitting the changelist via the command line option -submit. NOTE: Other versions of the command maybe allow submission in the future but the virtualization process needs to be improved so that it can check out package files before this really makes sense. - The rehydration command no longer requires a clientspec on the command line, it wasn't using the value anyway. - Moved the source control code from the app code files to CommandBase. If we add more commands in the future we might want to factor this out to its own base class so commands can opt into source control functionality. - In the future we should probably move the package -> project sorting code (FUnrealVirtualizationToolApp::TrySortFilesByProject) into the command base code as well. [CL 23233456 by paul chipchase in ue5-main branch]
2022-11-22 07:23:08 -05:00
#include "Commands/VirtualizeCommand.h"
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
#include "GenericPlatform/GenericPlatformOutputDevices.h"
#include "HAL/FeedbackContextAnsi.h"
#include "HAL/FileManager.h"
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
#include "HAL/PlatformProcess.h"
#include "Interfaces/IPluginManager.h"
#include "Logging/StructuredLog.h"
#include "Misc/CommandLine.h"
#include "Misc/ConfigCacheIni.h"
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
#include "Misc/FileHelper.h"
#include "Misc/PackageName.h"
#include "Misc/Parse.h"
#include "Misc/Paths.h"
#include "Misc/PathViews.h"
UnrealVirtualizationTool can now be given the path of a package or the path of a directory of packages to virtualize in addition to previous functionality. NOTE that all existing functionality should continue to work but using -Mode=Changelist or -Mode=Packagelist will result in a warning prompting the future use of the new versions for those commands. #rb Per.Larsson #jira UE-170657, UE-160396 #rnx #preflight 637c9232fa348e8480bdc7e2 - When the rehydration functionality was added it started to look like more functionality would be added to the tool than originally thought so I started to add the new functionality via a command system. This change now moves the older legacy functionality to the coommand system as well. - Added a new FVirtualizeCommand which can accept package paths, directory paths, packagelist files or changelists as the input. -- Unlike the legacy commands, virtualizing via changelist does not require the client spec to be provided on the commandline, although doing so will avoid several perforce commands and speed up the call. It is expected that people calling the tool on the commandline will probably opt to not supply a clientspec and let the tool workout which workspace a changelist is under, where as calls from other tools (such as P4VUtils) can provide it if already known to speed things up. -- FVirtualizeLegacyChangeListCommand replicates the functionality of the old -Mode=Changelist command. -- FVirtualizeLegacyPackageListCommand replicates the functionality of the old -Mode=Packagelist command. -- The new command will only try to submit the results if a changelist was provided as the input and even then it will not do so by default. The tool now requires people to opt into submitting the changelist via the command line option -submit. NOTE: Other versions of the command maybe allow submission in the future but the virtualization process needs to be improved so that it can check out package files before this really makes sense. - The rehydration command no longer requires a clientspec on the command line, it wasn't using the value anyway. - Moved the source control code from the app code files to CommandBase. If we add more commands in the future we might want to factor this out to its own base class so commands can opt into source control functionality. - In the future we should probably move the package -> project sorting code (FUnrealVirtualizationToolApp::TrySortFilesByProject) into the command base code as well. [CL 23233456 by paul chipchase in ue5-main branch]
2022-11-22 07:23:08 -05:00
#include "Modules/ModuleManager.h"
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
#include "ProcessUtilities.h"
#include "UnrealVirtualizationTool.h"
#include "Virtualization/VirtualizationSystem.h"
namespace
{
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
/** Utility to get EMode from a string */
void LexFromString(UE::Virtualization::EMode& OutValue, const FStringView& InString)
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
{
if (InString == TEXT("Changelist"))
{
OutValue = UE::Virtualization::EMode::Changelist;
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
}
else if (InString == TEXT("PackageList"))
{
OutValue = UE::Virtualization::EMode::PackageList;
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
}
UnrealVirtualizationTool can now be given the path of a package or the path of a directory of packages to virtualize in addition to previous functionality. NOTE that all existing functionality should continue to work but using -Mode=Changelist or -Mode=Packagelist will result in a warning prompting the future use of the new versions for those commands. #rb Per.Larsson #jira UE-170657, UE-160396 #rnx #preflight 637c9232fa348e8480bdc7e2 - When the rehydration functionality was added it started to look like more functionality would be added to the tool than originally thought so I started to add the new functionality via a command system. This change now moves the older legacy functionality to the coommand system as well. - Added a new FVirtualizeCommand which can accept package paths, directory paths, packagelist files or changelists as the input. -- Unlike the legacy commands, virtualizing via changelist does not require the client spec to be provided on the commandline, although doing so will avoid several perforce commands and speed up the call. It is expected that people calling the tool on the commandline will probably opt to not supply a clientspec and let the tool workout which workspace a changelist is under, where as calls from other tools (such as P4VUtils) can provide it if already known to speed things up. -- FVirtualizeLegacyChangeListCommand replicates the functionality of the old -Mode=Changelist command. -- FVirtualizeLegacyPackageListCommand replicates the functionality of the old -Mode=Packagelist command. -- The new command will only try to submit the results if a changelist was provided as the input and even then it will not do so by default. The tool now requires people to opt into submitting the changelist via the command line option -submit. NOTE: Other versions of the command maybe allow submission in the future but the virtualization process needs to be improved so that it can check out package files before this really makes sense. - The rehydration command no longer requires a clientspec on the command line, it wasn't using the value anyway. - Moved the source control code from the app code files to CommandBase. If we add more commands in the future we might want to factor this out to its own base class so commands can opt into source control functionality. - In the future we should probably move the package -> project sorting code (FUnrealVirtualizationToolApp::TrySortFilesByProject) into the command base code as well. [CL 23233456 by paul chipchase in ue5-main branch]
2022-11-22 07:23:08 -05:00
else if (InString == TEXT("Virtualize"))
{
OutValue = UE::Virtualization::EMode::Virtualize;
}
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
else if (InString == TEXT("Rehydrate"))
{
OutValue = UE::Virtualization::EMode::Rehydrate;
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
}
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
else
{
OutValue = UE::Virtualization::EMode::Unknown;
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
}
}
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
/**
* Utility to convert EMode to a string. NOTE that legacy modes will return the
* name of the newer mode that replaces it and not the legacy mode.
*/
const TCHAR* LexToString(UE::Virtualization::EMode Mode)
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
{
using namespace UE::Virtualization;
switch (Mode)
{
case EMode::Unknown:
return TEXT("Unknown");
case EMode::Changelist: // Legacy Mode
case EMode::PackageList: // Legacy Mode
case EMode::Virtualize:
return TEXT("Virtualize");
case EMode::Rehydrate:
return TEXT("Rehydrate");
default:
checkNoEntry();
return TEXT("");
}
}
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
/** Utility for creating a new command */
template<typename CommandType>
TUniquePtr<UE::Virtualization::FCommand> CreateCommand(const FString& ModeName, const TCHAR* CmdLine)
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
{
UE_LOG(LogVirtualizationTool, Display, TEXT("Attempting to initialize command '%s'..."), *ModeName);
TUniquePtr<UE::Virtualization::FCommand> Command = MakeUnique<CommandType>(ModeName);
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
if (Command->Initialize(CmdLine))
{
return Command;
}
else
{
return TUniquePtr<UE::Virtualization::FCommand>();
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
}
}
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
/** Utility to create a file path for the child process input/output file */
void CreateChildProcessFilePath(FStringView Id, FStringView Extension, FStringBuilderBase& OutPath)
{
FPathViews::ToAbsolutePath(FPaths::EngineSavedDir(), OutPath);
OutPath << TEXT("UnrealVirtualizationTool/") << Id << TEXT(".") << Extension;
}
/** Utility to create a file path for the child process input/output file from a FGuid */
void CreateChildProcessFilePath(const FGuid& Id, FStringView Extension, FStringBuilderBase& OutPath)
{
CreateChildProcessFilePath(WriteToString<40>(Id), Extension, OutPath);
}
/**
* This class can be used to prevent log messages from other systems being logged with the Display verbosity.
* In practical terms this means as long as the class is alive, only LogVirtualizationTool messages will
* be logged to the display meaning the user will have less information to deal with.
*/
class FOverrideOutputDevice final : public FFeedbackContextAnsi
{
public:
FOverrideOutputDevice()
{
OriginalLog = GWarn;
GWarn = this;
}
virtual ~FOverrideOutputDevice()
{
GWarn = OriginalLog;
}
virtual void Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category) override
{
Serialize(V, Verbosity, Category, -1.0);
}
virtual void Serialize(const TCHAR* V, ELogVerbosity::Type Verbosity, const FName& Category, double Time) override
{
#if !NO_LOGGING
if (Verbosity == ELogVerbosity::Display && Category != LogVirtualizationTool.GetCategoryName())
#endif
{
Verbosity = ELogVerbosity::Log;
}
FFeedbackContextAnsi::Serialize(V, Verbosity, Category, Time);
}
virtual void SerializeRecord(const UE::FLogRecord& Record) override
{
#if !NO_LOGGING
if (Record.GetVerbosity() == ELogVerbosity::Display && Record.GetCategory() != LogVirtualizationTool.GetCategoryName())
{
UE::FLogRecord LocalRecord = Record;
LocalRecord.SetVerbosity(ELogVerbosity::Log);
return FFeedbackContextAnsi::SerializeRecord(LocalRecord);
}
#endif
FFeedbackContextAnsi::SerializeRecord(Record);
}
private:
FFeedbackContext* OriginalLog;
};
} // namespace
namespace UE::Virtualization
{
FUnrealVirtualizationToolApp::FUnrealVirtualizationToolApp()
{
}
FUnrealVirtualizationToolApp::~FUnrealVirtualizationToolApp()
{
}
EInitResult FUnrealVirtualizationToolApp::Initialize()
{
TRACE_CPUPROFILER_EVENT_SCOPE(Initialize);
UE_LOG(LogVirtualizationTool, Display, TEXT("Initializing..."));
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
// Display the log path to the user so that they can more easily find it
// Note that ::GetAbsoluteLogFilename does not always return an absolute filename
FString LogFilePath = FGenericPlatformOutputDevices::GetAbsoluteLogFilename();
LogFilePath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*LogFilePath);
UE_LOG(LogVirtualizationTool, Display, TEXT("Logging process to '%s'"), *LogFilePath);
if (!TryLoadModules())
{
return EInitResult::Error;
}
if (!TryInitEnginePlugins())
{
return EInitResult::Error;
}
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
EInitResult CmdLineResult = TryParseCmdLine();
if (CmdLineResult != EInitResult::Success)
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
{
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
return CmdLineResult;
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
}
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
if (!IsChildProcess())
{
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
TArray<FString> Packages = CurrentCommand->GetPackages();
UE_LOG(LogVirtualizationTool, Display, TEXT("\tFound '%d' package file(s)"), Packages.Num());
if (!TrySortFilesByProject(Packages))
{
return EInitResult::Error;
}
}
UE_LOG(LogVirtualizationTool, Display, TEXT("Initialization complete!"));
return EInitResult::Success;
}
bool FUnrealVirtualizationToolApp::Run()
{
TRACE_CPUPROFILER_EVENT_SCOPE(Run);
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
TArray<TUniquePtr<FCommandOutput>> OutputArray;
if (!ProcessProjects(OutputArray))
{
UnrealVirtualizationTool can now be given the path of a package or the path of a directory of packages to virtualize in addition to previous functionality. NOTE that all existing functionality should continue to work but using -Mode=Changelist or -Mode=Packagelist will result in a warning prompting the future use of the new versions for those commands. #rb Per.Larsson #jira UE-170657, UE-160396 #rnx #preflight 637c9232fa348e8480bdc7e2 - When the rehydration functionality was added it started to look like more functionality would be added to the tool than originally thought so I started to add the new functionality via a command system. This change now moves the older legacy functionality to the coommand system as well. - Added a new FVirtualizeCommand which can accept package paths, directory paths, packagelist files or changelists as the input. -- Unlike the legacy commands, virtualizing via changelist does not require the client spec to be provided on the commandline, although doing so will avoid several perforce commands and speed up the call. It is expected that people calling the tool on the commandline will probably opt to not supply a clientspec and let the tool workout which workspace a changelist is under, where as calls from other tools (such as P4VUtils) can provide it if already known to speed things up. -- FVirtualizeLegacyChangeListCommand replicates the functionality of the old -Mode=Changelist command. -- FVirtualizeLegacyPackageListCommand replicates the functionality of the old -Mode=Packagelist command. -- The new command will only try to submit the results if a changelist was provided as the input and even then it will not do so by default. The tool now requires people to opt into submitting the changelist via the command line option -submit. NOTE: Other versions of the command maybe allow submission in the future but the virtualization process needs to be improved so that it can check out package files before this really makes sense. - The rehydration command no longer requires a clientspec on the command line, it wasn't using the value anyway. - Moved the source control code from the app code files to CommandBase. If we add more commands in the future we might want to factor this out to its own base class so commands can opt into source control functionality. - In the future we should probably move the package -> project sorting code (FUnrealVirtualizationToolApp::TrySortFilesByProject) into the command base code as well. [CL 23233456 by paul chipchase in ue5-main branch]
2022-11-22 07:23:08 -05:00
UE_LOG(LogVirtualizationTool, Error, TEXT("Command '%s' failed!"), *CurrentCommand->GetName());
return false;
}
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
if (!IsChildProcess())
{
if (!CurrentCommand->ProcessOutput(OutputArray))
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Command '%s' failed!"), *CurrentCommand->GetName());
return false;
}
}
else
{
if (!TryWriteChildProcessOutputFile(ChildProcessId, OutputArray))
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Command '%s' failed!"), *CurrentCommand->GetName());
return false;
}
}
UE_LOG(LogVirtualizationTool, Display, TEXT("Command '%s' succeeded!"), *CurrentCommand->GetName());
return true;
}
bool FUnrealVirtualizationToolApp::ProcessProjects(TArray<TUniquePtr<FCommandOutput>>& OutputArray)
{
TRACE_CPUPROFILER_EVENT_SCOPE(ProcessProjects);
UE_LOG(LogVirtualizationTool, Display, TEXT("Running the '%s' command..."), *CurrentCommand->GetName());
OutputArray.Reserve(Projects.Num());
for (const FProject& Project : Projects)
{
UE_LOG(LogVirtualizationTool, Display, TEXT("Processing project: %s"), *Project.GetProjectFilePath());
const FString ProjectPath = FPaths::ConvertRelativePathToFull(FPaths::GetProjectFilePath());
if (IsChildProcess() || ProjectPath == Project.GetProjectFilePath())
{
if (IsChildProcess() && ProjectPath != Project.GetProjectFilePath())
{
// If we are a child process then the correct project path should have been provided and so
// this check is mostly a paranoid check to make sure things are working as we expect.
UE_LOG(LogVirtualizationTool, Error, TEXT("The child process was create with project path '%s' but expected '%s'"), *ProjectPath, *Project.GetProjectFilePath());
return false;
}
check(ProjectPath == Project.GetProjectFilePath());
TUniquePtr<FCommandOutput> Output;
if (!CurrentCommand->ProcessProject(Project, Output))
{
return false;
}
if (Output != nullptr)
{
OutputArray.Emplace(MoveTemp(Output));
}
}
else
{
if (!LaunchChildProcess(*CurrentCommand, Project, GlobalCmdlineOptions, OutputArray))
{
return false;
}
}
}
return true;
}
void FUnrealVirtualizationToolApp::PrintCmdLineHelp() const
{
UE_LOG(LogVirtualizationTool, Display, TEXT("Usage:"));
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
UE_LOG(LogVirtualizationTool, Display, TEXT("Commands:"));
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
// TODO: If the commands were registered in some way we could automate this
UnrealVirtualizationTool can now be given the path of a package or the path of a directory of packages to virtualize in addition to previous functionality. NOTE that all existing functionality should continue to work but using -Mode=Changelist or -Mode=Packagelist will result in a warning prompting the future use of the new versions for those commands. #rb Per.Larsson #jira UE-170657, UE-160396 #rnx #preflight 637c9232fa348e8480bdc7e2 - When the rehydration functionality was added it started to look like more functionality would be added to the tool than originally thought so I started to add the new functionality via a command system. This change now moves the older legacy functionality to the coommand system as well. - Added a new FVirtualizeCommand which can accept package paths, directory paths, packagelist files or changelists as the input. -- Unlike the legacy commands, virtualizing via changelist does not require the client spec to be provided on the commandline, although doing so will avoid several perforce commands and speed up the call. It is expected that people calling the tool on the commandline will probably opt to not supply a clientspec and let the tool workout which workspace a changelist is under, where as calls from other tools (such as P4VUtils) can provide it if already known to speed things up. -- FVirtualizeLegacyChangeListCommand replicates the functionality of the old -Mode=Changelist command. -- FVirtualizeLegacyPackageListCommand replicates the functionality of the old -Mode=Packagelist command. -- The new command will only try to submit the results if a changelist was provided as the input and even then it will not do so by default. The tool now requires people to opt into submitting the changelist via the command line option -submit. NOTE: Other versions of the command maybe allow submission in the future but the virtualization process needs to be improved so that it can check out package files before this really makes sense. - The rehydration command no longer requires a clientspec on the command line, it wasn't using the value anyway. - Moved the source control code from the app code files to CommandBase. If we add more commands in the future we might want to factor this out to its own base class so commands can opt into source control functionality. - In the future we should probably move the package -> project sorting code (FUnrealVirtualizationToolApp::TrySortFilesByProject) into the command base code as well. [CL 23233456 by paul chipchase in ue5-main branch]
2022-11-22 07:23:08 -05:00
FVirtualizeCommand::PrintCmdLineHelp();
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
FRehydrateCommand::PrintCmdLineHelp();
UnrealVirtualizationTool can now be given the path of a package or the path of a directory of packages to virtualize in addition to previous functionality. NOTE that all existing functionality should continue to work but using -Mode=Changelist or -Mode=Packagelist will result in a warning prompting the future use of the new versions for those commands. #rb Per.Larsson #jira UE-170657, UE-160396 #rnx #preflight 637c9232fa348e8480bdc7e2 - When the rehydration functionality was added it started to look like more functionality would be added to the tool than originally thought so I started to add the new functionality via a command system. This change now moves the older legacy functionality to the coommand system as well. - Added a new FVirtualizeCommand which can accept package paths, directory paths, packagelist files or changelists as the input. -- Unlike the legacy commands, virtualizing via changelist does not require the client spec to be provided on the commandline, although doing so will avoid several perforce commands and speed up the call. It is expected that people calling the tool on the commandline will probably opt to not supply a clientspec and let the tool workout which workspace a changelist is under, where as calls from other tools (such as P4VUtils) can provide it if already known to speed things up. -- FVirtualizeLegacyChangeListCommand replicates the functionality of the old -Mode=Changelist command. -- FVirtualizeLegacyPackageListCommand replicates the functionality of the old -Mode=Packagelist command. -- The new command will only try to submit the results if a changelist was provided as the input and even then it will not do so by default. The tool now requires people to opt into submitting the changelist via the command line option -submit. NOTE: Other versions of the command maybe allow submission in the future but the virtualization process needs to be improved so that it can check out package files before this really makes sense. - The rehydration command no longer requires a clientspec on the command line, it wasn't using the value anyway. - Moved the source control code from the app code files to CommandBase. If we add more commands in the future we might want to factor this out to its own base class so commands can opt into source control functionality. - In the future we should probably move the package -> project sorting code (FUnrealVirtualizationToolApp::TrySortFilesByProject) into the command base code as well. [CL 23233456 by paul chipchase in ue5-main branch]
2022-11-22 07:23:08 -05:00
UE_LOG(LogVirtualizationTool, Display, TEXT("Legacy Commands:"));
UE_LOG(LogVirtualizationTool, Display, TEXT("-Mode=Changelist -ClientSpecName=<name> [optional] -Changelist=<number> -nosubmit [optional]"));
UE_LOG(LogVirtualizationTool, Display, TEXT("-Mode=PackageList -Path=<string>"));
UE_LOG(LogVirtualizationTool, Display, TEXT(""));
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
UE_LOG(LogVirtualizationTool, Display, TEXT("Global Options:"));
UE_LOG(LogVirtualizationTool, Display, TEXT("\t-MinimalLogging (demote log messages with 'display' verbosity to 'log' verbosity except those using the LogVirtualizationTool category)"));
}
bool FUnrealVirtualizationToolApp::TryLoadModules()
{
if (FModuleManager::Get().LoadModule(TEXT("Virtualization"), ELoadModuleFlags::LogFailures) == nullptr)
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Failed to load the 'Virtualization' module"));
}
return true;
}
bool FUnrealVirtualizationToolApp::TryInitEnginePlugins()
{
TRACE_CPUPROFILER_EVENT_SCOPE(TryInitEnginePlugins);
UE_LOG(LogVirtualizationTool, Log, TEXT("Loading Engine Plugins"));
auto LoadPlugin = [](const FString& PlugInName) -> bool
{
IPluginManager& PluginMgr = IPluginManager::Get();
PluginMgr.MountNewlyCreatedPlugin(PlugInName);
TSharedPtr<IPlugin> Plugin = PluginMgr.FindPlugin(PlugInName);
if (Plugin == nullptr || !Plugin->IsEnabled())
{
UE_LOG(LogVirtualizationTool, Error, TEXT("The plugin '%s' is disabled."), *PlugInName);
return false;
}
return true;
};
if (!LoadPlugin(TEXT("PerforceSourceControl")))
{
return false;
}
return true;
}
EInitResult FUnrealVirtualizationToolApp::TryParseCmdLine()
{
TRACE_CPUPROFILER_EVENT_SCOPE(TryParseCmdLine);
UE_LOG(LogVirtualizationTool, Log, TEXT("Parsing the commandline"));
const TCHAR* CmdLine = FCommandLine::Get();
if (CmdLine == nullptr || CmdLine[0] == TEXT('\0'))
{
UE_LOG(LogVirtualizationTool, Error, TEXT("No commandline parameters found!"));
PrintCmdLineHelp();
return EInitResult::Error;
}
if (FParse::Param(CmdLine, TEXT("Help")) || FParse::Param(CmdLine, TEXT("?")))
{
UE_LOG(LogVirtualizationTool, Display, TEXT("Commandline help requested"));
PrintCmdLineHelp();
return EInitResult::EarlyOut;
}
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
EInitResult GlobalOptionResult = TryParseGlobalOptions(CmdLine);
if(GlobalOptionResult != EInitResult::Success)
{
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
return GlobalOptionResult;
}
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
// Check to see if we are a child process with an input file
FString ChildProcessInput;
if (FParse::Value(CmdLine, TEXT("-ChildProcess="), ChildProcessInput))
{
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
if (TryReadChildProcessInputFile(ChildProcessInput))
{
return EInitResult::Success;
}
else
{
return EInitResult::Error;
}
}
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
// Now parse the mode specific command line options
FString ModeAsString;
if (!FParse::Value(CmdLine, TEXT("-Mode="), ModeAsString))
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Failed to find cmdline switch 'Mode', this is a required parameter!"));
PrintCmdLineHelp();
return EInitResult::Error;
}
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
return CreateCommandFromString(ModeAsString, CmdLine);
}
EInitResult FUnrealVirtualizationToolApp::TryParseGlobalOptions(const TCHAR* CmdLine)
{
GlobalCmdlineOptions.Reset();
if (FParse::Param(CmdLine, TEXT("MinimalLogging")))
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
{
OutputDeviceOverride = MakeUnique<FOverrideOutputDevice>();
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
AddGlobalOption(TEXT("-MinimalLogging"));
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
}
else
{
OutputDeviceOverride.Reset();
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
}
return EInitResult::Success;
}
EInitResult FUnrealVirtualizationToolApp::CreateCommandFromString(const FString& CommandName, const TCHAR* Cmdline)
{
check(Mode == EMode::Unknown && !CurrentCommand.IsValid());
LexFromString(Mode, CommandName);
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
switch (Mode)
{
case EMode::Changelist:
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
CurrentCommand = CreateCommand<FVirtualizeLegacyChangeListCommand>(LexToString(Mode), Cmdline);
UnrealVirtualizationTool can now be given the path of a package or the path of a directory of packages to virtualize in addition to previous functionality. NOTE that all existing functionality should continue to work but using -Mode=Changelist or -Mode=Packagelist will result in a warning prompting the future use of the new versions for those commands. #rb Per.Larsson #jira UE-170657, UE-160396 #rnx #preflight 637c9232fa348e8480bdc7e2 - When the rehydration functionality was added it started to look like more functionality would be added to the tool than originally thought so I started to add the new functionality via a command system. This change now moves the older legacy functionality to the coommand system as well. - Added a new FVirtualizeCommand which can accept package paths, directory paths, packagelist files or changelists as the input. -- Unlike the legacy commands, virtualizing via changelist does not require the client spec to be provided on the commandline, although doing so will avoid several perforce commands and speed up the call. It is expected that people calling the tool on the commandline will probably opt to not supply a clientspec and let the tool workout which workspace a changelist is under, where as calls from other tools (such as P4VUtils) can provide it if already known to speed things up. -- FVirtualizeLegacyChangeListCommand replicates the functionality of the old -Mode=Changelist command. -- FVirtualizeLegacyPackageListCommand replicates the functionality of the old -Mode=Packagelist command. -- The new command will only try to submit the results if a changelist was provided as the input and even then it will not do so by default. The tool now requires people to opt into submitting the changelist via the command line option -submit. NOTE: Other versions of the command maybe allow submission in the future but the virtualization process needs to be improved so that it can check out package files before this really makes sense. - The rehydration command no longer requires a clientspec on the command line, it wasn't using the value anyway. - Moved the source control code from the app code files to CommandBase. If we add more commands in the future we might want to factor this out to its own base class so commands can opt into source control functionality. - In the future we should probably move the package -> project sorting code (FUnrealVirtualizationToolApp::TrySortFilesByProject) into the command base code as well. [CL 23233456 by paul chipchase in ue5-main branch]
2022-11-22 07:23:08 -05:00
return CurrentCommand.IsValid() ? EInitResult::Success : EInitResult::Error;
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
break;
case EMode::PackageList:
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
CurrentCommand = CreateCommand<FVirtualizeLegacyPackageListCommand>(LexToString(Mode), Cmdline);
UnrealVirtualizationTool can now be given the path of a package or the path of a directory of packages to virtualize in addition to previous functionality. NOTE that all existing functionality should continue to work but using -Mode=Changelist or -Mode=Packagelist will result in a warning prompting the future use of the new versions for those commands. #rb Per.Larsson #jira UE-170657, UE-160396 #rnx #preflight 637c9232fa348e8480bdc7e2 - When the rehydration functionality was added it started to look like more functionality would be added to the tool than originally thought so I started to add the new functionality via a command system. This change now moves the older legacy functionality to the coommand system as well. - Added a new FVirtualizeCommand which can accept package paths, directory paths, packagelist files or changelists as the input. -- Unlike the legacy commands, virtualizing via changelist does not require the client spec to be provided on the commandline, although doing so will avoid several perforce commands and speed up the call. It is expected that people calling the tool on the commandline will probably opt to not supply a clientspec and let the tool workout which workspace a changelist is under, where as calls from other tools (such as P4VUtils) can provide it if already known to speed things up. -- FVirtualizeLegacyChangeListCommand replicates the functionality of the old -Mode=Changelist command. -- FVirtualizeLegacyPackageListCommand replicates the functionality of the old -Mode=Packagelist command. -- The new command will only try to submit the results if a changelist was provided as the input and even then it will not do so by default. The tool now requires people to opt into submitting the changelist via the command line option -submit. NOTE: Other versions of the command maybe allow submission in the future but the virtualization process needs to be improved so that it can check out package files before this really makes sense. - The rehydration command no longer requires a clientspec on the command line, it wasn't using the value anyway. - Moved the source control code from the app code files to CommandBase. If we add more commands in the future we might want to factor this out to its own base class so commands can opt into source control functionality. - In the future we should probably move the package -> project sorting code (FUnrealVirtualizationToolApp::TrySortFilesByProject) into the command base code as well. [CL 23233456 by paul chipchase in ue5-main branch]
2022-11-22 07:23:08 -05:00
return CurrentCommand.IsValid() ? EInitResult::Success : EInitResult::Error;
break;
case EMode::Virtualize:
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
CurrentCommand = CreateCommand<FVirtualizeCommand>(CommandName, Cmdline);
UnrealVirtualizationTool can now be given the path of a package or the path of a directory of packages to virtualize in addition to previous functionality. NOTE that all existing functionality should continue to work but using -Mode=Changelist or -Mode=Packagelist will result in a warning prompting the future use of the new versions for those commands. #rb Per.Larsson #jira UE-170657, UE-160396 #rnx #preflight 637c9232fa348e8480bdc7e2 - When the rehydration functionality was added it started to look like more functionality would be added to the tool than originally thought so I started to add the new functionality via a command system. This change now moves the older legacy functionality to the coommand system as well. - Added a new FVirtualizeCommand which can accept package paths, directory paths, packagelist files or changelists as the input. -- Unlike the legacy commands, virtualizing via changelist does not require the client spec to be provided on the commandline, although doing so will avoid several perforce commands and speed up the call. It is expected that people calling the tool on the commandline will probably opt to not supply a clientspec and let the tool workout which workspace a changelist is under, where as calls from other tools (such as P4VUtils) can provide it if already known to speed things up. -- FVirtualizeLegacyChangeListCommand replicates the functionality of the old -Mode=Changelist command. -- FVirtualizeLegacyPackageListCommand replicates the functionality of the old -Mode=Packagelist command. -- The new command will only try to submit the results if a changelist was provided as the input and even then it will not do so by default. The tool now requires people to opt into submitting the changelist via the command line option -submit. NOTE: Other versions of the command maybe allow submission in the future but the virtualization process needs to be improved so that it can check out package files before this really makes sense. - The rehydration command no longer requires a clientspec on the command line, it wasn't using the value anyway. - Moved the source control code from the app code files to CommandBase. If we add more commands in the future we might want to factor this out to its own base class so commands can opt into source control functionality. - In the future we should probably move the package -> project sorting code (FUnrealVirtualizationToolApp::TrySortFilesByProject) into the command base code as well. [CL 23233456 by paul chipchase in ue5-main branch]
2022-11-22 07:23:08 -05:00
return CurrentCommand.IsValid() ? EInitResult::Success : EInitResult::Error;
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
break;
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
case EMode::Rehydrate:
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
CurrentCommand = CreateCommand<FRehydrateCommand>(CommandName, Cmdline);
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
return CurrentCommand.IsValid() ? EInitResult::Success : EInitResult::Error;
break;
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
case EMode::Unknown:
default:
UE_LOG(LogVirtualizationTool, Error, TEXT("Unexpected value for the cmdline switch 'Mode', this is a required parameter!"));
PrintCmdLineHelp();
return EInitResult::Error;
break;
}
}
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
bool FUnrealVirtualizationToolApp::TrySortFilesByProject(const TArray<FString>& Packages)
{
TRACE_CPUPROFILER_EVENT_SCOPE(TrySortFilesByProject);
UE_LOG(LogVirtualizationTool, Display, TEXT("\tSorting files by project..."));
Extend the VA stand-alone tool to work on both changelists (the existing functionality) and lists of packages stored in a text file (the new functionality) #rb PJ.Kack #jira UE-143675 #rnx #preflight 624c6a1814634fba5c7e3d71 ### Rationale - The new mode being added allows us to write a list of package file paths to be virtualized to a file on disk and then the file to be passed to the tool so that it knows what to virtualize. This new mode will then be used by P4VUtils.dll which is how we will run the virtualization process via p4v custom tools. - We need this second mode because: -- A workspace could have multiple projects in it, which means a user could try to virtualize a changelist with packages from more than one project. -- Projects can be associated with different engine installations so the user could try to virtualize a changelist with packages using different engine installations, which in turn means that they need to be virtualized by different versions of the stand-alone tool. -- This means we cannot rely on passing the CL number to the tool, install P4VUtils.dll will need to sort the package paths by engine installation, then pass those paths to the correct version of the tool. -- The paths need to be written to a text file to be passed to the tool as the total length of path data can easily exceed the commandline max length limit if someone were to try and virtualize an entire project in one go for example. - Note that the new mode does NOT submit the package files since there might be multiple calls to different versions of the stand-alone tool. In theory if all the packages are under one engine install (which is almost certainly going to be 99.999% of all submits) we could allow the tool to do the submit but that means we need to maintain two different code paths for the same operation. - The existing mode (virtualize and submit a changelist) remains unchanged. It is not likely that an end user will ever use this mode, but it will make for a useful debugging tool in the future. ### Changes - When the tool first starts we now print the log path to the user so that they can more easily find it. This might be something that we want to remove after a while, but during the initial release of the tool it should make getting good debug info back from users with problems somewhat easier. - Some logging and error messages have had small updates made, to make the final output to the user more readable (based on the many many times this tool was run while testing). In some places additional logging has been added where I felt it was not clear to the user as to what was going on. - Connecting to source control has been moved from the changelist parsing code to it's own method ::TryConnectToSourceControl since all modes will require it. - The cmdline help output has been redone to support the multiple command line options we now have. - Although we could infer the mode to run based on the commandline options, we require the users to explicitly state the mode via -Mode=XXX. In general the tool will be invoked from a gui so adding extra commands doesn't really affect the usability of the system and it makes things a bit clearer. [CL 19665307 by paul chipchase in ue5-main branch]
2022-04-07 02:08:03 -04:00
for (const FString& PackagePath : Packages)
{
FString ProjectFilePath;
FString PluginFilePath;
if (TryFindProject(PackagePath, ProjectFilePath, PluginFilePath))
{
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
FProject& Project = FindOrAddProject(MoveTemp(ProjectFilePath));
if (PluginFilePath.IsEmpty())
{
Project.AddFile(PackagePath);
}
else
{
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
Project.AddPluginFile(PackagePath, MoveTemp(PluginFilePath));
}
}
}
UE_LOG(LogVirtualizationTool, Display, TEXT("\tThe package files are associated with '%d' projects(s)"), Projects.Num());
return true;
}
bool FUnrealVirtualizationToolApp::TryFindProject(const FString& PackagePath, FString& ProjectFilePath, FString& PluginFilePath) const
{
TRACE_CPUPROFILER_EVENT_SCOPE(TryFindProject);
// TODO: This could be heavily optimized by caching known project files
int32 ContentIndex = PackagePath.Find(TEXT("/content/"), ESearchCase::IgnoreCase, ESearchDir::FromEnd);
// Early out if there is not a single content directory in the path
if (ContentIndex == INDEX_NONE)
{
UE_LOG(LogVirtualizationTool, Warning, TEXT("'%s' is not under a content directory"), *PackagePath);
return false;
}
while (ContentIndex != INDEX_NONE)
{
// Assume that the project directory is the parent of the /content/ directory
FString ProjectDirectory = PackagePath.Left(ContentIndex);
FString PluginDirectory;
TArray<FString> ProjectFile;
TArray<FString> PluginFile;
IFileManager::Get().FindFiles(ProjectFile, *ProjectDirectory, TEXT(".uproject"));
if (ProjectFile.IsEmpty())
{
// If there was no project file, the package could be in a plugin, so lets check for that
PluginDirectory = ProjectDirectory;
IFileManager::Get().FindFiles(PluginFile, *PluginDirectory, TEXT(".uplugin"));
if (PluginFile.Num() == 1)
{
PluginFilePath = PluginDirectory / PluginFile[0];
// We have a valid plugin file, so we should be able to find a /plugins/ directory which will be just below the project directory
const int32 PluginIndex = PluginDirectory.Find(TEXT("/plugins/"), ESearchCase::IgnoreCase, ESearchDir::FromEnd);
if (PluginIndex != INDEX_NONE)
{
// We found the plugin root directory so the one above it should be the project directory
ProjectDirectory = PluginDirectory.Left(PluginIndex);
IFileManager::Get().FindFiles(ProjectFile, *ProjectDirectory, TEXT(".uproject"));
}
}
else if (PluginFile.Num() > 1)
{
UE_LOG(LogVirtualizationTool, Warning, TEXT("Found multiple .uplugin files for '%s' at '%s'"), *PackagePath, *PluginDirectory);
return false;
}
}
if (ProjectFile.Num() == 1)
{
ProjectFilePath = ProjectDirectory / ProjectFile[0];
return true;
}
else if (!ProjectFile.IsEmpty())
{
UE_LOG(LogVirtualizationTool, Warning, TEXT("Found multiple .uproject files for '%s' at '%s'"), *PackagePath, *ProjectDirectory);
return false;
}
// Could be more than one content directory in the path so lets keep looking
ContentIndex = PackagePath.Find(TEXT("/content/"), ESearchCase::IgnoreCase, ESearchDir::FromEnd, ContentIndex);
}
// We found one or more content directories but none of them contained a project file
UE_LOG(LogVirtualizationTool, Warning, TEXT("Failed to find project file for '%s'"), *PackagePath);
return false;
}
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
FProject& FUnrealVirtualizationToolApp::FindOrAddProject(FString&& ProjectFilePath)
{
FProject* Project = Projects.FindByPredicate([&ProjectFilePath](const FProject& Project)->bool
{
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
return Project.GetProjectFilePath() == ProjectFilePath;
});
if (Project != nullptr)
{
return *Project;
}
else
{
Add a rehydration command to the stand alone virtualization tool, making it easier to reverse the effects of asset virtualization. Unlike previous processes, this one does not require that we load the package and will just manipulate the data storaged in the package trailer. #rb Sebastian.Nordgren #rnx #jira UE-156436 #preflight 62c287f9a3568e30664eb94f ### VA Standalone Tool - We now plan to add much more functionality to the tool than just virtualizing and submitting changelists, so to make this easier I am moving the tool towards a design where it should be fairly easy to add new functionality. - Added FCommand, which is a base class for adding new functionality, simple derive from FCommand and hook it up at the appropriate locations. -- In the future it should be possible for new command types to automatically register themselves to be initiated from the command line. There should be no need to edit UnrealVirtualizationToolApp to add a new command but this will be done as an additional work item. -- At the moment FCommand comes with a number of utility methods to call that cover some common source control commands. -- The original functionality has not yet been moved to the command system and so the code is a little bit weird at the moment. Updating older code to the new system will be done as an additional work item. - FProject/FPlugin have been moved to their own code files. ### Rehydrate Command - The rehydrate command will take a number of packages, check them out of source control and then attempt to virtualize them. - At the moment the chekout logic is fairly basic, we just check out every package supplied, we don't check if the package is virtualized or not yet. This can be improved in additional work items. Ideally by the end of command the only packages that we have checked out should also be rehydrated. - At the moment the command can either take a path of a specific package, a path of a directory to find packages in, or a changelist containing packages that should be rehydrated. - A cleint spec (workspace) can optionally be provided, but if not supplied we will attempt to find a client spec for which to check out the packages. - Currently we will check out the packages to the default change list. ### Rehydrate process - Added the rehydration process in it's own code files in the virtualization module. Like the virtualization process this is exposed in a public header file and no via the Core interface which means it is very specific to our module/implementation. - The process expects that the caller will have checked out any required packages from source control. It will treat being unable to update a package file as an error. - Added PackageUtils.h/.cpp and moved some of the generic code from the virtualization process code there so that it can be shared by the rehydration process. ### Misc Moving away from the using things like FPackagePath as that requires that the correct mount points have been registered for a project and at the moment (with the flakiness of FConfig*) it seems that the best idea would be to prefer absolute file paths where possible. [CL 20982284 by paul chipchase in ue5-main branch]
2022-07-07 06:54:33 -04:00
int32 Index = Projects.Emplace(MoveTemp(ProjectFilePath));
return Projects[Index];
}
}
[UVT] Improve the robustness of the tool wrt ensuring that the correct project config settings are loaded. #rb Per.Larsson #jira UE-151641 #preflight 63ea068cde74ffbae5dc3a7f ### Problem - A lot of systems rely on the engine to know which project is being loaded on start up so that the correct config settings can be applied however so far the UVT has not required the user to provide the desired project. This is because in theory, the tool could be given a list of packages or a changelist to process that contain packages from more than one project and if that happens we need to handle it correctly. - The tool currently groups the provided packages by project, then runs the requested command on each project one at a time, initializing the VA system with that projects config files, then shutting it done once the project packages are processed. This allows us to pick up the correct settings for VA but other systems that we rely on, such as the DDC do not allow this sort of dynamic initialization and so may not have the correct settings. ### Solution - Before the projects packages are processed we check to see if the project applied to the process during initialization (if any) matches the project to be processed. If not we launch a new version of the tool with the correct project settings and have the child process perform the main processing. The output of each child process (or any projects we were able to run in process) are then provided to the command for a final "post projects" phase. - This means we can support multiple packages from multiple processes AND not require the user type out the project name when using the tool from the cmdline. - Although launching a child process only adds a few seconds of overhead (per project) any tool or process that make use of UVT should be updated to provide the project where possible. ### Changes ### FUnrealVirtualizationToolApp - As explained in the problem section, we now need to support launching a new instance of the tool as a child process. - We communicate with the child process by providing an input file via the cmdline, which is then parsed and used to recreate the original command and project settings. Once the command has run in the child process it will write its output to an output file which the calling process can then read back in. - So our new logic is to check the project that the tool was started with (in case the user provided a project path in the cmdline) against each project that we need to process. If the paths match then we can just process the project, if they do not match we launch a child process with the correct path and retrieve the output once done. -- If a child process detects an incorrect path we just error out to avoid endless recursive process launching. - Output from the child process is clearly logged to the user as coming from a child process to make debugging easier. ### FCommand - Added ToJson/FromJson methods to FCommand, which simulates the same interface as though it was using the json serialization macros, however we want more control over things so do the serialization manually via FCommand::Serialize -- Serialization is only used if the command is sent to a child process (if the current project is wrong), in which case the command should serialize out all info that it derived during setup that it will need to process correctly. Usually this consists of the options that were parsed from the command line. Then when the child process is run we will recreate the command via the same serialize method. - Added a new class FProcessPipes, which acts as a wrapper around the pipes we can create by calling FPlatformProcess::CreatePipe which are returned as raw pointers. This ensures that the pipes are cleaned up once the FProcessPipes object goes out of scope. - The ::Run method has been split into two, ::ProcessProject and ::ProcessOutput -- ::ProcessProject is called once per project and allows the command to return output via the Output parameter. This can be call in process or via a child process if the project needs to be set. -- ::ProcessOutput is called once all projects have been processed and provides an array which is a collection of the output from each call to ::ProcessProject. This is always called in process. -- The output is passed around by the base type FCommandOutput. It is expected that commands derive their own type and as we do not mix command types, they should know how to cast the output back to the correct type when ::ProcessOutput is called. This is a bit messy but to go further risks over engineering given it is unlikely that more commands will be added to the tool. If we do expand the tool in the future then this can be revisited. ### FCommandOutput - A struct used to represent the output of a command. - If the command is run as a child process then this struct will be serialized out to disk (via json) then loaded back in by the calling process so that the output of each child process can be combined. - Commands are expected to derive their own output structure and deal with the json serialization. To make this easier we provide a JSON_SERIALIZE_PARENT macro to allow for serialization of inheritance chains. - This system does require that commands know which type of output to cast FCommandOutput to. At the moment we do not provide any type safety. - Add json serialization to FProject and it's child struct FPlugin. - FProject::GetProjectFilePath now returns as a reference to a FString rather than a FStringView. [CL 24257111 by paul chipchase in ue5-main branch]
2023-02-16 09:18:15 -05:00
bool FUnrealVirtualizationToolApp::IsChildProcess() const
{
return !ChildProcessId.IsEmpty();
}
void FUnrealVirtualizationToolApp::AddGlobalOption(FStringView Options)
{
if (!GlobalCmdlineOptions.IsEmpty())
{
GlobalCmdlineOptions.Append(TEXT(" "));
}
GlobalCmdlineOptions.Append(Options);
}
bool FUnrealVirtualizationToolApp::TryReadChildProcessOutputFile(const FGuid& ChildProcessId, const FCommand& Command, TArray<TUniquePtr<FCommandOutput>>& OutputArray)
{
TRACE_CPUPROFILER_EVENT_SCOPE(TryReadChildProcessOutputFile);
TStringBuilder<512> FilePath;
CreateChildProcessFilePath(ChildProcessId, TEXT("output"), FilePath);
FString JsonText;
if (!FFileHelper::LoadFileToString(JsonText, FilePath.ToString()))
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Could not open child process output file '%s'"), FilePath.ToString());
return false;
}
TSharedPtr<FJsonObject> JsonRootObject;
TSharedRef<TJsonReader<TCHAR>> Reader = TJsonReaderFactory<TCHAR>::Create(JsonText);
if (!FJsonSerializer::Deserialize(Reader, JsonRootObject) || !JsonRootObject.IsValid())
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Failed to parse child process output file '%s'"), FilePath.ToString());
return false;
}
const TArray<TSharedPtr<FJsonValue>>* OutputJsonArray = nullptr;
if (JsonRootObject->TryGetArrayField(TEXT("OutputArray"), OutputJsonArray))
{
check(OutputJsonArray != nullptr);
for (TSharedPtr<FJsonValue> OutputValue : *OutputJsonArray)
{
TUniquePtr<FCommandOutput> Output = Command.CreateOutputObject();
const TSharedPtr<FJsonObject>* OutputObject = nullptr;
if (!OutputValue->TryGetObject(OutputObject))
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Invalid syntax found in child process output file '%s'"), FilePath.ToString());
return false;
}
check(OutputObject != nullptr);
if (!Output->FromJson(*OutputObject))
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Failed to read FCommandOutput from the child process output file '%s'"), FilePath.ToString());
return false;
}
OutputArray.Emplace(MoveTemp(Output));
}
}
else
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Invalid syntax found in child process output file '%s'"), FilePath.ToString());
return false;
}
return true;
}
bool FUnrealVirtualizationToolApp::TryWriteChildProcessOutputFile(const FString& ChildProcessId, const TArray<TUniquePtr<FCommandOutput>>& OutputArray)
{
TRACE_CPUPROFILER_EVENT_SCOPE(TryWriteChildProcessOutputFile);
FString JsonTcharText;
TSharedRef<TJsonWriter<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>> Writer = TJsonWriterFactory<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>::Create(&JsonTcharText);
Writer->WriteObjectStart();
Writer->WriteArrayStart(TEXT("OutputArray"));
for (const TUniquePtr<FCommandOutput>& Output : OutputArray)
{
if (Output)
{
Writer->WriteObjectStart();
Output->ToJson(Writer, true);
Writer->WriteObjectEnd();
}
}
Writer->WriteArrayEnd();
Writer->WriteObjectEnd();
if (!Writer->Close())
{
UE_LOG(LogVirtualizationTool, Display, TEXT("Failed to create child process output file json document"));
return false;
}
TStringBuilder<512> FilePath;
CreateChildProcessFilePath(ChildProcessId, TEXT("output"), FilePath);
if (!FFileHelper::SaveStringToFile(JsonTcharText, FilePath.ToString()))
{
UE_LOG(LogVirtualizationTool, Display, TEXT("Failed to create child process output file '%s'"), FilePath.ToString());
return false;
}
return true;
}
bool FUnrealVirtualizationToolApp::TryReadChildProcessInputFile(const FString& InputPath)
{
UE_LOG(LogVirtualizationTool, Display, TEXT("Parsing child process input file..."));
FString JsonText;
if (!FFileHelper::LoadFileToString(JsonText, *InputPath))
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Could not open child process input file '%s'"), *InputPath);
return false;
}
TSharedPtr<FJsonObject> JsonRootObject;
TSharedRef<TJsonReader<TCHAR>> Reader = TJsonReaderFactory<TCHAR>::Create(JsonText);
if (!FJsonSerializer::Deserialize(Reader, JsonRootObject) || !JsonRootObject.IsValid())
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Failed to parse child process input file '%s'"), *InputPath);
return false;
}
if (TSharedPtr<FJsonValue> JsonValue = JsonRootObject->TryGetField(TEXT("CommandName")))
{
const FString CommandName = JsonValue->AsString();
if (CreateCommandFromString(CommandName, TEXT("")) != EInitResult::Success)
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Failed to create command '%s'"), *CommandName);
return false;
}
}
else
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Failed to find 'CommandName' in child process input file '%s'"), *InputPath);
return false;
}
if (TSharedPtr<FJsonObject> JsonObject = JsonRootObject->GetObjectField(TEXT("ProjectData")))
{
FProject Project;
if (Project.FromJson(JsonObject))
{
Projects.Emplace(MoveTemp(Project));
}
else
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Failed to serialize project data from child process input file '%s'"), *InputPath);
return false;
}
}
else
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Failed to find 'ProjectData' in child process input file '%s'"), *InputPath);
return false;
}
if (TSharedPtr<FJsonObject> JsonObject = JsonRootObject->GetObjectField(TEXT("CommandData")))
{
CurrentCommand->FromJson(JsonObject);
}
else
{
UE_LOG(LogVirtualizationTool, Error, TEXT("Failed to find 'ProjectData' in child process input file '%s'"), *InputPath);
return false;
}
ChildProcessId = FPathViews::GetBaseFilename(InputPath);
return true;
}
bool FUnrealVirtualizationToolApp::TryWriteChildProcessInputFile(const FGuid& ChildProcessId, const FCommand& Command, const FProject& Project, FStringBuilderBase& OutPath)
{
TRACE_CPUPROFILER_EVENT_SCOPE(TryWriteChildProcessInputFile);
FString JsonTcharText;
TSharedRef<TJsonWriter<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>> Writer = TJsonWriterFactory<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>::Create(&JsonTcharText);
Writer->WriteObjectStart();
Writer->WriteValue(TEXT("CommandName"), Command.GetName());
Writer->WriteObjectStart(TEXT("ProjectData"));
Project.ToJson(Writer, true);
Writer->WriteObjectEnd();
Writer->WriteObjectStart(TEXT("CommandData"));
Command.ToJson(Writer);
Writer->WriteObjectEnd();
Writer->WriteObjectEnd();
if (!Writer->Close())
{
UE_LOG(LogVirtualizationTool, Display, TEXT("Failed to create child process input file json document"));
return false;
}
CreateChildProcessFilePath(ChildProcessId, TEXT("input"), OutPath);
if (!FFileHelper::SaveStringToFile(JsonTcharText, OutPath.ToString()))
{
UE_LOG(LogVirtualizationTool, Display, TEXT("Failed to save child process input file '%s'"), OutPath.ToString());
return false;
}
return true;
}
bool FUnrealVirtualizationToolApp::LaunchChildProcess(const FCommand& Command, const FProject& Project, FStringView GlobalOptions, TArray<TUniquePtr<FCommandOutput>>& OutputArray)
{
TRACE_CPUPROFILER_EVENT_SCOPE(LaunchChildProcess);
UE_LOG(LogVirtualizationTool, Display, TEXT("Launching and waiting on a new instance of the tool..."));
const FGuid ChildProcessId = FGuid::NewGuid();
TStringBuilder<512> InputFilePath;
if (!TryWriteChildProcessInputFile(ChildProcessId, Command, Project, InputFilePath))
{
// No need to log an error here, ::TryWriteChildProcessInputFile will take care of that
return false;
}
{
TRACE_CPUPROFILER_EVENT_SCOPE(RunChildProcess);
const FString CurrentExePath = FPlatformProcess::ExecutablePath();
FString Args = FString::Printf(TEXT("%s -ChildProcess=%s"), *Project.GetProjectFilePath(), InputFilePath.ToString());
if (!GlobalOptions.IsEmpty())
{
Args.Append(TEXT(" "));
Args.Append(GlobalOptions);
}
const bool bLaunchDetached = false;
const bool bLaunchHidden = true;
const bool bLaunchReallyHidden = true;
uint32 ProcessId = INDEX_NONE;
const int32 Priority = 0;
const TCHAR* WorkingDirectory = nullptr;
FProcessPipes Pipes;
FProcHandle Handle = FPlatformProcess::CreateProc(*CurrentExePath, *Args, bLaunchDetached, bLaunchHidden, bLaunchReallyHidden,
/*OutProcessID*/ nullptr, Priority, WorkingDirectory, Pipes.GetStdIn(), Pipes.GetStdOut());
{
TRACE_CPUPROFILER_EVENT_SCOPE(WaitOnChildProcess);
while (FPlatformProcess::IsProcRunning(Handle))
{
Pipes.ProcessStdOut();
FPlatformProcess::Sleep(0.033f);
}
}
int32 ReturnCode = INDEX_NONE;
if (!FPlatformProcess::GetProcReturnCode(Handle, &ReturnCode))
{
UE_LOG(LogVirtualizationTool, Display, TEXT("Failed to retrieve the return value of the child process"));
return false;
}
if (ReturnCode != 0)
{
UE_LOG(LogVirtualizationTool, Display, TEXT("Child process failed with error code: %d"), ReturnCode);
return false;
}
}
if (!TryReadChildProcessOutputFile(ChildProcessId, Command, OutputArray))
{
// No need to log an error here, ::TryReadChildProcessOutputFile will take care of that
return false;
}
return true;
}
} // namespace UE::Virtualization