#jira UE-120464 Add Custom Config directory feature, which allows specifying an override directory to support shipping multiple types of builds per platform

Setting CustomConfig=Foo in a Target.cs file will cause it to overlay config files from Project/Config/Custom/Foo on top of the defaults, allowing easy override of things like OSS settings to support multiple stores
In development, -CustomConfig=foo can be specified in both C++ and C# to enable the same functionality, which can be used to select between multiple different stage/deploy configurations in a build script
#rb josh.adams, ben.marsh

#ROBOMERGE-SOURCE: CL 17017130 in //UE5/Main/...
#ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v839-17012307)

[CL 17017144 by ben zeigler in ue5-release-engine-test branch]
This commit is contained in:
ben zeigler
2021-08-02 12:22:46 -04:00
parent fdd30297da
commit e9bd4ff609
8 changed files with 193 additions and 38 deletions
@@ -136,6 +136,11 @@ public class DeploymentContext //: ProjectParams
/// </summary>
public List<StageTarget> StageTargets;
/// <summary>
/// Extra subdirectory to load config files out of, for making multiple types of builds with the same platform
/// </summary>
public string CustomConfig;
/// <summary>
/// This is the root directory that contains the engine: d:\a\UE4\
/// </summary>
@@ -443,8 +448,30 @@ public class DeploymentContext //: ProjectParams
ProjectArgForCommandLines = CommandUtils.MakePathSafeToUseWithCommandLine(RawProjectPath.FullName);
CookSourceRuntimeRootDir = RuntimeRootDir = LocalRoot;
RuntimeProjectRootDir = ProjectRoot;
if (Stage)
// Parse the custom config dir out of the receipts
foreach (StageTarget Target in StageTargets)
{
var Results = Target.Receipt.AdditionalProperties.Where(x => x.Name == "CustomConfig");
foreach (var Property in Results)
{
string FoundCustomConfig = Property.Value;
if (String.IsNullOrEmpty(FoundCustomConfig))
{
continue;
}
else if (String.IsNullOrEmpty(CustomConfig))
{
CustomConfig = FoundCustomConfig;
}
else if (CustomConfig != FoundCustomConfig)
{
throw new AutomationException("Cannot deploy targts with conflicting CustomConfig values! {0} does not match {1}", FoundCustomConfig, CustomConfig);
}
}
}
if (Stage)
{
CommandUtils.CreateDirectory(StageDirectory.FullName);
@@ -470,7 +497,7 @@ public class DeploymentContext //: ProjectParams
RestrictedFolderNames.Remove(StageTargetPlatform.IniPlatformType.ToString());
// Read the game config files
ConfigHierarchy GameConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, ProjectRoot, InTargetPlatform.PlatformType);
ConfigHierarchy GameConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, ProjectRoot, InTargetPlatform.PlatformType, CustomConfig);
// Read the list of directories to remap when staging
List<string> RemapDirectoriesList;
@@ -524,12 +551,11 @@ public class DeploymentContext //: ProjectParams
ReadConfigFileList(GameConfig, "Staging", "BlacklistConfigFiles", BlacklistConfigFiles);
// Grab the game ini data
ConfigHierarchy GameIni = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, ProjectRoot, InTargetPlatform.PlatformType);
String IniPath = "/Script/UnrealEd.ProjectPackagingSettings";
String PackagingIniPath = "/Script/UnrealEd.ProjectPackagingSettings";
// Read the config blacklists
GameIni.GetArray(IniPath, "IniKeyBlacklist", out IniKeyBlacklist);
GameIni.GetArray(IniPath, "IniSectionBlacklist", out IniSectionBlacklist);
GameConfig.GetArray(PackagingIniPath, "IniKeyBlacklist", out IniKeyBlacklist);
GameConfig.GetArray(PackagingIniPath, "IniSectionBlacklist", out IniSectionBlacklist);
// TODO: Drive these lists from a config file
IniSuffixWhitelist = new List<string>
@@ -576,7 +602,7 @@ public class DeploymentContext //: ProjectParams
else
{
bool bSetting = false;
if (GameIni.GetBool(IniPath, "bGenerateChunks", out bSetting))
if (GameConfig.GetBool(PackagingIniPath, "bGenerateChunks", out bSetting))
{
PlatformUsesChunkManifests = bSetting;
}
@@ -638,7 +638,7 @@ namespace AutomationScripts
LogInformation("Creating Staging Manifest...");
ConfigHierarchy PlatformGameConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, DirectoryReference.FromFile(Params.RawProjectPath), SC.StageTargetPlatform.IniPlatformType);
ConfigHierarchy PlatformGameConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, DirectoryReference.FromFile(Params.RawProjectPath), SC.StageTargetPlatform.IniPlatformType, SC.CustomConfig);
if (Params.HasIterateSharedCookedBuild)
{
@@ -1129,7 +1129,7 @@ namespace AutomationScripts
}
// check if the game will be verifying ssl connections - if not, we can skip staging files that won't be needed
bool bStageSSLCertificates = false;
ConfigHierarchy PlatformEngineConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.FromFile(Params.RawProjectPath), SC.StageTargetPlatform.IniPlatformType);
ConfigHierarchy PlatformEngineConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.FromFile(Params.RawProjectPath), SC.StageTargetPlatform.IniPlatformType, SC.CustomConfig);
if (PlatformEngineConfig != null)
{
PlatformEngineConfig.GetBool("/Script/Engine.NetworkSettings", "n.VerifyPeer", out bStageSSLCertificates);
@@ -1397,6 +1397,7 @@ namespace AutomationScripts
/// <param name="SC">The staging context</param>
/// <param name="ConfigDir">Directory containing the config files</param>
/// <param name="ConfigFile">The config file to check</param>
/// <param name="PlatformExtenionName">Name of platform to scan outside the main directory</param>
/// <returns>True if the file should be staged, false otherwise</returns>
static Nullable<bool> ShouldStageConfigFile(DeploymentContext SC, DirectoryReference ConfigDir, FileReference ConfigFile, string PlatformExtensionName)
{
@@ -1410,8 +1411,35 @@ namespace AutomationScripts
return false;
}
const string CustomPrefix = "custom/";
string NormalizedPath = ConfigFile.MakeRelativeTo(ConfigDir).ToLowerInvariant().Replace('\\', '/');
if (NormalizedPath.StartsWith(CustomPrefix))
{
// Strip custom prefix, then check if it matches our specified custom config
NormalizedPath = NormalizedPath.Substring(CustomPrefix.Length);
if (!String.IsNullOrEmpty(SC.CustomConfig))
{
string PrefixToStrip = SC.CustomConfig.ToLowerInvariant() + "/";
if (NormalizedPath.StartsWith(PrefixToStrip))
{
// Strip custom config path off the front
NormalizedPath = NormalizedPath.Substring(PrefixToStrip.Length);
}
else
{
// If custom config is specified, we want to ignore others automatically
return false;
}
}
else
{
// Ignore all custom config directories
return false;
}
}
int DirectoryIdx = NormalizedPath.IndexOf('/');
if (DirectoryIdx == -1)
{
@@ -1821,7 +1849,7 @@ namespace AutomationScripts
ConfigHierarchy PakRulesConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.PakFileRules, DirectoryReference.FromFile(Params.RawProjectPath), SC.StageTargetPlatform.IniPlatformType);
ConfigHierarchy PakRulesConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.PakFileRules, DirectoryReference.FromFile(Params.RawProjectPath), SC.StageTargetPlatform.IniPlatformType, SC.CustomConfig);
bool bChunkedBuild = SC.PlatformUsesChunkManifests && DoesChunkPakManifestExist(Params, SC);
@@ -2287,7 +2315,7 @@ namespace AutomationScripts
// read some compression settings from the project (once, shared across all pak commands)
ConfigHierarchy PlatformGameConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, DirectoryReference.FromFile(Params.RawProjectPath), SC.StageTargetPlatform.IniPlatformType);
ConfigHierarchy PlatformGameConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, DirectoryReference.FromFile(Params.RawProjectPath), SC.StageTargetPlatform.IniPlatformType, SC.CustomConfig);
// in standard runs, ProjectPackagingSettings/bCompressed is read by the program invoking this script
// and used to pass "-compressed" on the command line
@@ -2771,7 +2799,7 @@ namespace AutomationScripts
AdditionalArgs += " -platform=" + ConfigHierarchy.GetIniPlatformName(SC.StageTargetPlatform.IniPlatformType);
Dictionary<string, string> UnrealPakResponseFile = PakParams.UnrealPakResponseFile;
if (ShouldCreateIoStoreContainerFiles(Params, SC.StageTargetPlatform))
if (ShouldCreateIoStoreContainerFiles(Params, SC.StageTargetPlatform, SC.CustomConfig))
{
bool bAllowBulkDataInIoStore = true;
if (!PlatformEngineConfig.GetBool("Core.System", "AllowBulkDataInIoStore", out bAllowBulkDataInIoStore))
@@ -2950,7 +2978,7 @@ namespace AutomationScripts
InternalUtils.SafeCreateDirectory(Path.GetDirectoryName(ReleaseVersionPath));
InternalUtils.SafeCopyFile(OutputLocation.FullName, ReleaseVersionPath);
if (ShouldCreateIoStoreContainerFiles(Params, SC.StageTargetPlatform))
if (ShouldCreateIoStoreContainerFiles(Params, SC.StageTargetPlatform, SC.CustomConfig))
{
InternalUtils.SafeCopyFile(Path.ChangeExtension(OutputLocation.FullName, ".utoc"), Path.ChangeExtension(ReleaseVersionPath, ".utoc"));
InternalUtils.SafeCopyFile(Path.ChangeExtension(OutputLocation.FullName, ".ucas"), Path.ChangeExtension(ReleaseVersionPath, ".ucas"));
@@ -3060,7 +3088,7 @@ namespace AutomationScripts
{
HashSet<string> IncludedExtensions = new HashSet<string>();
IncludedExtensions.Add(OutputFilenameExtension);
if (ShouldCreateIoStoreContainerFiles(Params, SC.StageTargetPlatform))
if (ShouldCreateIoStoreContainerFiles(Params, SC.StageTargetPlatform, SC.CustomConfig))
{
IncludedExtensions.Add(".ucas");
IncludedExtensions.Add(".utoc");
@@ -3355,7 +3383,7 @@ namespace AutomationScripts
LogInformation("Creating pak using streaming install manifests.");
DumpManifest(SC, CombinePaths(CmdEnv.LogFolder, "PrePak" + (SC.DedicatedServer ? "_Server" : "") + "_" + SC.CookPlatform));
ConfigHierarchy PlatformGameConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, DirectoryReference.FromFile(Params.RawProjectPath), SC.StageTargetPlatform.IniPlatformType);
ConfigHierarchy PlatformGameConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, DirectoryReference.FromFile(Params.RawProjectPath), SC.StageTargetPlatform.IniPlatformType, SC.CustomConfig);
bool bShouldGenerateEarlyDownloaderPakFile = false, bForceOneChunkPerFile = false;
string EarlyDownloaderPakFilePrefix = string.Empty;
@@ -3684,7 +3712,7 @@ namespace AutomationScripts
return TmpPackagingPath;
}
private static bool ShouldCreateIoStoreContainerFiles(ProjectParams Params, Platform StageTargetPlatform)
private static bool ShouldCreateIoStoreContainerFiles(ProjectParams Params, Platform StageTargetPlatform, String CustomConfig)
{
if (Params.CookOnTheFly)
{
@@ -3703,7 +3731,7 @@ namespace AutomationScripts
if (Params.Stage && !Params.SkipStage)
{
ConfigHierarchy PlatformGameConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, DirectoryReference.FromFile(Params.RawProjectPath), StageTargetPlatform.IniPlatformType);
ConfigHierarchy PlatformGameConfig = ConfigCache.ReadHierarchy(ConfigHierarchyType.Game, DirectoryReference.FromFile(Params.RawProjectPath), StageTargetPlatform.IniPlatformType, CustomConfig);
bool bUseIoStore = false;
PlatformGameConfig.GetBool("/Script/UnrealEd.ProjectPackagingSettings", "bUseIoStore", out bUseIoStore);
return bUseIoStore;