Files
UnrealEngineUWP/Engine/Source/Programs/AutomationTool/AutomationUtils/DeploymentContext.cs
Jack Porter 2082f7ec9b Copying //UE4/Dev-Mobile to //UE4/Dev-Main (Source: //UE4/Dev-Mobile @ 3056055)
#lockdown Nick.Penwarden
#rb None

==========================
MAJOR FEATURES + CHANGES
==========================

Change 3011102 on 2016/06/13 by Steve.Cano

	After taking a screenshot using glReadPixels, transfer the data to the target buffer from bottom row up to fix the "upside-down" render that OpenGL does. Confirmed with QA (owen.stupka_volt) that this does not appear to be happening on iOS (non-metal devices, inclusion of iOS in write-up was a mistake), verified on an ipod touch 5. Also confirmed that this does not happen on html5, and that Mobile HDR flag does not make a difference in function.

	#jira UE-26421
	#ue4
	#android

Change 3015801 on 2016/06/16 by Dmitriy.Dyomin

	Probbably fix for UE-30878, was not able to repro an actual crash(FFoliageInstanceBaseCache::AddInstanceBaseId). Added even more logging in case fix does not work.
	#jira  UE-30878

Change 3015903 on 2016/06/16 by Dmitriy.Dyomin

	Fixed: Levels window has Refresh/UI issues when World Composition is active
	#jira UE-26160

Change 3018352 on 2016/06/17 by Chris.Babcock

	Handle Android media prepare failure (URL without internet for example)
	#jira UE-32029
	#ue4
	#android

Change 3026387 on 2016/06/24 by Jack.Porter

	Remove FFuncTestManager warning about PIE when running on a standalone game binary

Change 3026398 on 2016/06/24 by Jack.Porter

	Prevent FSocketBSD::Recv returning false on SE_EWOULDBLOCK

Change 3027553 on 2016/06/25 by Niklas.Smedberg

	OpenGL: Made some block size calculation work for arbitrary block sizes (e.g. not pow-of-two).

Change 3027554 on 2016/06/25 by Niklas.Smedberg

	Metal: copyFromTexture now gets block-aligned size parameter (e.g. used for texture streaming)

Change 3028061 on 2016/06/26 by Jack.Porter

	Fixed a problem where newly discovered instances were not added to an existing session in the Session Browser.
	Fixed a problem where selecting an instance in a session with multiple instances didn't deselect the previously selected instance correctly.

Change 3029220 on 2016/06/27 by Steve.Cano

	Change Android Tilt values to use GetRotationMatrix/GetOrientation logic, same as java-side android would use, and adjust slightly to match as closely as possible to iOS values for tilt. There is drift and some differences in the "Y" value but the same sort of inconsistencies are also seen on iOS.

	#jira UE-6135
	#ue4
	#android

Change 3030420 on 2016/06/28 by Jack.Porter

	Fix crash with RenderOutputValidation when running with cooked content

Change 3030426 on 2016/06/28 by Jack.Porter

	Fix to CL 3026398 - make FSocketBSD(IPv6)::Recv(From) return false when recv returns 0.
	A return value of 0 indicates the connection was shutdown in an orderly manner.

Change 3030973 on 2016/06/28 by Steve.Cano

	Added a landscape downloader background along with the options to change it from within Android settings

	#ue4
	#android
	#jira UE-32318

Change 3031757 on 2016/06/28 by Chris.Babcock

	Remove unused methods from AndroidJNI header
	#ue4
	#android

Change 3032387 on 2016/06/29 by Allan.Bentham

	Rename android es31+aep -> glesdeferred.

Change 3032711 on 2016/06/29 by Allan.Bentham

	Rename GLSL_310_ES_EXT shader define:
	ES31_AEP_PROFILE -> ESDEFERRED_PROFILE
	bumped UE_SHADER_GLSL_310_ES_EXT_VER version number.

Change 3033698 on 2016/06/29 by Jack.Porter

	Merging //UE4/Dev-Main to Dev-Mobile (//UE4/Dev-Mobile)

Change 3034210 on 2016/06/30 by Steve.Cano

	Added a new AndroidRuntimeSettings variable that allows creation of installers for both Windows and Mac/Linux if set to true.

	#jira UE-32302

	#ue4
	#android

Change 3034530 on 2016/06/30 by Chris.Babcock

	Rename FManifestReader to FAndroidFileManifestReader in AndroidFile
	#jira UE-32679
	#ue4
	#android

Change 3034612 on 2016/06/30 by Steve.Cano

	Change Alpha from being set to a range of 0-255 to being in a range of 0-1 (which is the correct range of values)

	#jira UE-25325
	#ue4
	#android

Change 3034679 on 2016/06/30 by Chris.Babcock

	Fix tooltip (.command for mac, not .sh)
	#jira UE-32302
	#ue4
	#android

Change 3038881 on 2016/07/05 by Jack.Porter

	Package and launch on multiple Android devices simultaneously using the -Device=xxxxxxx+yyyyyyyy+zzzzzzzz format generated by a Project Launcher profile when you select multiple devices

	#jira UEMOB-115

Change 3039240 on 2016/07/06 by Jack.Porter

	TcpMessageTransport - connection-based message bus transport.

	#jira UEMOB-112
	#jira UEMOB-113

Change 3039252 on 2016/07/06 by Jack.Porter

	Enable messaging and session services and functional testing on Android when launched with -messaging
	Android device detection module support for adding port forwarding and connection announcement for TcpMessageTransport

	#jira UEMOB-112
	#jira UEMOB-113

Change 3039264 on 2016/07/06 by Jack.Porter

	Merging //UE4/Dev-Main to Dev-Mobile (//UE4/Dev-Mobile)

Change 3040041 on 2016/07/06 by Chris.Babcock

	Pass proper value to script generator functions
	#jira UE-32861
	#ue4
	#android

Change 3040890 on 2016/07/07 by Allan.Bentham

	Fix shadow crash
	#jira UE-32884

Change 3041458 on 2016/07/07 by Peter.Sauerbrei

	fix for IOS launch on failures

Change 3041542 on 2016/07/07 by Peter.Sauerbrei

	better fix for the multi-device deployment issue

Change 3041774 on 2016/07/07 by Steve.Cano

	Fixing crash that occurs when a games app id for Google Play is set before configuring the apk packaging. Also validating the value that is inserted and using it to override any values that have been hand-inserted into the GooglePlayAppID.xml

	#jira UE-16992
	#android
	#ue4

Change 3042222 on 2016/07/08 by Dmitriy.Dyomin

	Mobile packaging scenarious
	Added a wizard for creating launcher profiles (Android & IOS) for scenario: Minimal App + Downloadable content
	Added Archive step to launcher profiles to be able to store build product into specified directory
	Changes to a cooker to be able to pack DLC based with a different flavor to a release App
	Changes to DLC packaging to be able to build streaming data without chunking pak files
	#jira UEMOB-119

Change 3042244 on 2016/07/08 by Dmitriy.Dyomin

	Fixed crash in FTcpMessageTransportConnection::Stop

Change 3042270 on 2016/07/08 by Dmitriy.Dyomin

	GitHub #2320 : [ULevelStreamingKismet] Load Level Instance, Enables UE4 Users to create multiple transformed instances of a .umap without having to include in persistent level's list ? Rama
	contributed by: EverNewJoy
	#jira UE-29867

Change 3042449 on 2016/07/08 by Dmitriy.Dyomin

	Fixing Mac Editor build erros from CL# 3042222

Change 3042480 on 2016/07/08 by Allan.Bentham

	Add ES3.1 profile & compiler_glsl_es3_1 to shaders.

Change 3042481 on 2016/07/08 by Allan.Bentham

	hlslcc - ES3.1 changes.
	set ES3.1 version number to 310
	Do not use ES2 keywords for ES3.1.
	Generate Layout Locations for ES3.1
	bump version.

Change 3042483 on 2016/07/08 by Allan.Bentham

	Add mobile ES3.1 support.
	Recreates EGL and ES3.1 context during PlatformInitOpenGL if ES3.1 is required.

Change 3042485 on 2016/07/08 by Allan.Bentham

	Undo android XGE change.

Change 3042506 on 2016/07/08 by Dmitriy.Dyomin

	One more compile fix from CL# 3042222

Change 3044173 on 2016/07/10 by Dmitriy.Dyomin

	UAT: Added support for building target platforms with multiple cook flavors
	ex: -targetplatform=Android -cookflavor=ETC1+ETC2

Change 3044213 on 2016/07/11 by Dmitriy.Dyomin

	Fixed: Can't stream in a level whose name is a substring of another streaming level
	#jira UE-32999

Change 3044221 on 2016/07/11 by Jack.Porter

	Merging //UE4/Dev-Main to Dev-Mobile (//UE4/Dev-Mobile)

Change 3044815 on 2016/07/11 by Allan.Bentham

	Corrected NAME_GLSL_ES3_1_ANDROID format string.

Change 3046911 on 2016/07/12 by Chris.Babcock

	Add handling of OnTextChanged for virtual keyboard input on Android
	#jira UE-32348
	#ue4
	#android

Change 3046958 on 2016/07/12 by Chris.Babcock

	Rename some functions with Error in the name to prevent false coloring in the logs
	#jira UE-30541
	#ue4
	#android

Change 3047169 on 2016/07/12 by Chris.Babcock

	Return player ID and handle auth token for Google Play Games on Android (contributed by gameDNAstudio)
	#jira UE-30610
	#pr #2372
	#ue4
	#android

Change 3047406 on 2016/07/12 by Jack.Porter

	Add missing import to GameActivity.java

Change 3047442 on 2016/07/13 by Dmitriy.Dyomin

	Added: Mobile custom post-process
	Limitations: can fetch only from PostProcessInput0 (SceneColor) other scene textures are not supported. Does not support "Replacing the Tonemapper" blendable location.
	#jira UEMOB-147

Change 3047466 on 2016/07/13 by Dmitriy.Dyomin

	Disabled engine crash handler on Android, system crash handler works more reliably across different os versions/devices

Change 3047746 on 2016/07/13 by Jack.Porter

	Rename FBasePassFowardDynamicPointLightInfo

Change 3047778 on 2016/07/13 by Jack.Porter

	Missing file for rename FBasePassFowardDynamicPointLightInfo

Change 3047788 on 2016/07/13 by Allan.Bentham

	Fix incorrect TargetPlatformDescriptor string generation.

Change 3047790 on 2016/07/13 by Allan.Bentham

	Fixed half3x3 matrix use with ES3.1 glsl
	Fixed couple of interpolator precision mismatch.
	Fixed ES3.1 support detection issues

Change 3047816 on 2016/07/13 by Allan.Bentham

	Remove AndroidGL4 remnants.

Change 3048926 on 2016/07/13 by Chris.Babcock

	Added detection of Amazon Fire TV to disable requiring virtual joysticks
	#ue4
	#android

Change 3049335 on 2016/07/14 by Dmitriy.Dyomin

	Fixing UAT crash when packaging project for iOS

Change 3049390 on 2016/07/14 by Jack.Porter

	Disabled error for warning 4819 "The file contains a character that cannot be represented in the current code page (xxx). Save the file in Unicode format to prevent data loss"
	This is triggered by European characters and copyright symbols in source saved as latin-1 when compiling on non-US windows. Seen often in 3rd party headers, eg nvapi.

	#code_review: Ben.Marsh

Change 3049391 on 2016/07/14 by Jack.Porter

	Fixed incorrect comment order in CL 3049390

Change 3049545 on 2016/07/14 by Dmitriy.Dyomin

	Reworking some code from CL#3047442 to make static analizer happy

Change 3049626 on 2016/07/14 by Allan.Bentham

	Automatic CSM shader toggling
	#jira UE-27429

Change 3051574 on 2016/07/15 by Jack.Porter

	Support for lighting channels on Mobile
	- Multiple directional lights are supported in different channels but primitives are only affected by the directional light in the first channel they have set
	- CSM shadows from stationary or movable directional lights correctly follow their lighting channels
	- No channel limitations for dynamic point lights

	Notes:
	Removed mobile-specific directional light shadowing fields from View uniform buffer and mobile no longers uses SimpleDirectionalLight.
	Separate uniform buffers for mobile directional light are generated for each lighting channel.
	CSM culling information is now stored in FViewInfo and not per FVisibleLightViewInfo as the visibility bits are per view.

	#code_review Daniel.Wright
	#jira UEMOB-110

Change 3051699 on 2016/07/15 by Steve.Cano

	Preserve the original, pre-transformed input vertices for Slate shaders, which is required to properly do anti-aliasing (the ViewProjection-transformed values were causing the lines to not be drawn).

	#jira UE-20320
	#ue4
	#android

Change 3051744 on 2016/07/15 by Chris.Babcock

	Fix Android Vulkan include path checks (contributed by kodomastro)
	#jira UE-33311
	#PR #2602
	#ue4
	#android

Change 3052023 on 2016/07/15 by Chris.Babcock

	Fix shadowed variables

Change 3052110 on 2016/07/15 by Chris.Babcock

	Compile fixes for light channel support on mobile
	- missing template
	- accessor function for MobileDirectionalLights from scene

Change 3052242 on 2016/07/15 by Chris.Babcock

	Compile fixes for light channel support on mobile
	- removed dependency on C++14 feature

Change 3052730 on 2016/07/16 by Dmitriy.Dyomin

	Win32 build fix

Change 3053041 on 2016/07/17 by Jack.Porter

	Merging //UE4/Dev-Main to Dev-Mobile (//UE4/Dev-Mobile)

Change 3053054 on 2016/07/17 by Jack.Porter

	Changed use of old function ShouldUseDeferredRenderer() to new GetShadingPath()

Change 3053055 on 2016/07/17 by Jack.Porter

	Fixed local variable aliasing in unity build

Change 3053206 on 2016/07/18 by Jack.Porter

	Support ExecuteJavascript on iOS and Android
	Expose ExecuteJavascript to widget blueprint
	Fix ExecuteJavascript unicode string support on desktop platforms

	#jira UEMOB-152

Change 3053323 on 2016/07/18 by Dmitriy.Dyomin

	Added: Ability to set thread affinity for a device in Device Profiles (ex: +CVars=android.SetThreadAffinity=RT 0x02 GT 0x01)
	#jira UEMOB-107

Change 3053723 on 2016/07/18 by Jack.Porter

	Fix for UnrealTournamentProto.Automation.cs build errors

Change 3055090 on 2016/07/19 by Dmitriy.Dyomin

	Junk OnlineBlueprintSupport module binaries

[CL 3056789 by Jack Porter in Main branch]
2016-07-19 19:13:01 -04:00

802 lines
27 KiB
C#

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Reflection;
using AutomationTool;
using UnrealBuildTool;
public struct StageTarget
{
public TargetReceipt Receipt;
public bool RequireFilesExist;
}
public class DeploymentContext //: ProjectParams
{
/// <summary>
/// Full path to the .uproject file
/// </summary>
public FileReference RawProjectPath;
/// <summary>
/// true if we should stage crash reporter
/// </summary>
public bool bStageCrashReporter;
/// <summary>
/// CookPlatform, where to get the cooked data from and use for sandboxes
/// </summary>
public string CookPlatform;
/// <summary>
/// FinalCookPlatform, directory to stage and archive the final result to
/// </summary>
public string FinalCookPlatform;
/// <summary>
/// Source platform to get the cooked data from
/// </summary>
public Platform CookSourcePlatform;
/// <summary>
/// Target platform used for sandboxes and stage directory names
/// </summary>
public Platform StageTargetPlatform;
/// <summary>
/// Configurations to stage. Used to determine which ThirdParty configurations to copy.
/// </summary>
public List<UnrealTargetConfiguration> StageTargetConfigurations;
/// <summary>
/// Receipts for the build targets that should be staged.
/// </summary>
public List<StageTarget> StageTargets;
/// <summary>
/// this is the root directory that contains the engine: d:\a\UE4\
/// </summary>
public string LocalRoot;
/// <summary>
/// this is the directory that contains the "game": d:\a\UE4\ShooterGame
/// </summary>
public string ProjectRoot;
/// <summary>
/// raw name used for platform subdirectories Win32
/// </summary>
public string PlatformDir;
/// <summary>
/// this is the directory that contains the "game", staged: d:\stagedir\WindowsNoEditor\ShooterGame
/// </summary>
public string StageProjectRoot;
/// <summary>
/// Directory to put all of the files in: d:\stagedir\WindowsNoEditor
/// </summary>
public string StageDirectory;
/// <summary>
/// The relative staged project root, what would be tacked on to StageDirectory
/// </summary>
public string RelativeProjectRootForStage;
/// <summary>
/// The relative source project root, this will be the short project name for foreign projects, otherwise it is ProjectRoot minus the LocalRoot prefix
/// </summary>
public string SourceRelativeProjectRoot;
/// <summary>
/// The relative staged project root, used inside the pak file list (different slash convention than above)
/// </summary>
public string RelativeProjectRootForUnrealPak;
/// <summary>
/// This is what you use to test the engine which uproject you want. Many cases.
/// </summary>
public string ProjectArgForCommandLines;
/// <summary>
/// This is the root that the cook source platform would run from
/// </summary>
public string CookSourceRuntimeRootDir;
/// <summary>
/// This is the root that we are going to run from. Many cases.
/// </summary>
public string RuntimeRootDir;
/// <summary>
/// This is the project root that we are going to run from. Many cases.
/// </summary>
public string RuntimeProjectRootDir;
/// <summary>
/// This is the executable we are going to run and stage. Filled in by the platform abstraction.
/// </summary>
public string RuntimeExecutable = "";
/// <summary>
/// List of executables we are going to stage
/// </summary>
public List<string> StageExecutables;
/// <summary>
/// Probably going away, used to construct ProjectArgForCommandLines in the case that we are running staged
/// </summary>
public string UProjectCommandLineArgInternalRoot = "../../../";
/// <summary>
/// Probably going away, used to construct the pak file list
/// </summary>
public string PakFileInternalRoot = "../../../";
/// <summary>
/// Probably going away, and currently unused, this would be used to build the list of files for the UFS server
/// </summary>
public string UnrealFileServerInternalRoot = "../../../";
/// <summary>
/// After staging, this is a map from source file to relative file in the stage
/// These file are binaries, etc and can't go into a pak file
/// </summary>
public Dictionary<string, List<string>> NonUFSStagingFiles = new Dictionary<string, List<string>>();
/// <summary>
/// After staging, this is a map from source file to relative file in the stage
/// These file are debug, and can't go into a pak file
/// </summary>
public Dictionary<string, List<string>> NonUFSStagingFilesDebug = new Dictionary<string, List<string>>();
/// <summary>
/// After staging, this is a map from source file to relative file in the stage
/// These file are content, and can go into a pak file
/// </summary>
public Dictionary<string, string> UFSStagingFiles = new Dictionary<string, string>();
/// <summary>
/// List of files to be archived
/// </summary>
public Dictionary<string, string> ArchivedFiles = new Dictionary<string, string>();
/// <summary>
/// Directory to archive all of the files in: d:\archivedir\WindowsNoEditor
/// </summary>
public string ArchiveDirectory;
/// <summary>
/// Directory to project binaries
/// </summary>
public string ProjectBinariesFolder;
/// <summary>
/// Filename for the manifest of file changes for iterative deployment.
/// </summary>
static public readonly string UFSDeployDeltaFileName = "Manifest_DeltaUFSFiles.txt";
static public readonly string NonUFSDeployDeltaFileName = "Manifest_DeltaNonUFSFiles.txt";
/// <summary>
/// Filename for the manifest of files to delete during deployment.
/// </summary>
static public readonly string UFSDeployObsoleteFileName = "Manifest_ObsoleteUFSFiles.txt";
static public readonly string NonUFSDeployObsoleteFileName = "Manifest_ObsoleteNonUFSFiles.txt";
/// <summary>
/// The client connects to dedicated server to get data
/// </summary>
public bool DedicatedServer;
/// <summary>
/// The dedicated server and client use
/// </summary>
public bool bUseWebsocketNetDriver;
/// <summary>
/// True if this build is staged
/// </summary>
public bool Stage;
/// <summary>
/// True if this build is archived
/// </summary>
public bool Archive;
/// <summary>
/// True if this project has code
/// </summary>
public bool IsCodeBasedProject;
/// <summary>
/// Project name (name of the uproject file without extension or directory name where the project is localed)
/// </summary>
public string ShortProjectName;
/// <summary>
/// If true, multiple platforms are being merged together - some behavior needs to change (but not much)
/// </summary>
public bool bIsCombiningMultiplePlatforms = false;
public DeploymentContext(
FileReference RawProjectPathOrName,
string InLocalRoot,
string BaseStageDirectory,
string BaseArchiveDirectory,
Platform InSourcePlatform,
Platform InTargetPlatform,
List<UnrealTargetConfiguration> InTargetConfigurations,
IEnumerable<StageTarget> InStageTargets,
List<String> InStageExecutables,
bool InServer,
bool InCooked,
bool InStageCrashReporter,
bool InStage,
bool InCookOnTheFly,
bool InArchive,
bool InProgram,
bool IsClientInsteadOfNoEditor,
bool bInUseWebsocketNetDriver = false
)
{
bStageCrashReporter = InStageCrashReporter;
RawProjectPath = RawProjectPathOrName;
DedicatedServer = InServer;
LocalRoot = CommandUtils.CombinePaths(InLocalRoot);
CookSourcePlatform = InSourcePlatform;
StageTargetPlatform = InTargetPlatform;
StageTargetConfigurations = new List<UnrealTargetConfiguration>(InTargetConfigurations);
StageTargets = new List<StageTarget>(InStageTargets);
StageExecutables = InStageExecutables;
IsCodeBasedProject = ProjectUtils.IsCodeBasedUProjectFile(RawProjectPath);
ShortProjectName = ProjectUtils.GetShortProjectName(RawProjectPath);
Stage = InStage;
Archive = InArchive;
bUseWebsocketNetDriver = bInUseWebsocketNetDriver;
if (CookSourcePlatform != null && InCooked)
{
CookPlatform = CookSourcePlatform.GetCookPlatform(DedicatedServer, IsClientInsteadOfNoEditor);
}
else if (CookSourcePlatform != null && InProgram)
{
CookPlatform = CookSourcePlatform.GetCookPlatform(false, false);
}
else
{
CookPlatform = "";
}
if (StageTargetPlatform != null && InCooked)
{
FinalCookPlatform = StageTargetPlatform.GetCookPlatform(DedicatedServer, IsClientInsteadOfNoEditor);
}
else if (StageTargetPlatform != null && InProgram)
{
FinalCookPlatform = StageTargetPlatform.GetCookPlatform(false, false);
}
else
{
FinalCookPlatform = "";
}
PlatformDir = StageTargetPlatform.PlatformType.ToString();
StageDirectory = CommandUtils.CombinePaths(BaseStageDirectory, FinalCookPlatform);
ArchiveDirectory = CommandUtils.CombinePaths(BaseArchiveDirectory, FinalCookPlatform);
if (!CommandUtils.FileExists(RawProjectPath.FullName))
{
throw new AutomationException("Can't find uproject file {0}.", RawProjectPathOrName);
}
ProjectRoot = CommandUtils.CombinePaths(CommandUtils.GetDirectoryName(RawProjectPath.FullName));
if (!CommandUtils.DirectoryExists(ProjectRoot))
{
throw new AutomationException("Project Directory {0} doesn't exist.", ProjectRoot);
}
RelativeProjectRootForStage = ShortProjectName;
ProjectArgForCommandLines = CommandUtils.MakePathSafeToUseWithCommandLine(RawProjectPath.FullName);
CookSourceRuntimeRootDir = RuntimeRootDir = LocalRoot;
RuntimeProjectRootDir = ProjectRoot;
RelativeProjectRootForUnrealPak = CommandUtils.CombinePaths(RelativeProjectRootForStage).Replace("\\", "/");
if (RelativeProjectRootForUnrealPak.StartsWith("/"))
{
RelativeProjectRootForUnrealPak = RelativeProjectRootForUnrealPak.Substring(1);
RelativeProjectRootForStage = RelativeProjectRootForStage.Substring(1);
}
SourceRelativeProjectRoot = RelativeProjectRootForStage; // for foreign projects this doesn't make much sense, but it turns into a noop on staging files
if (ProjectRoot.StartsWith(LocalRoot, StringComparison.InvariantCultureIgnoreCase))
{
SourceRelativeProjectRoot = ProjectRoot.Substring(LocalRoot.Length);
}
if (SourceRelativeProjectRoot.StartsWith("/") || SourceRelativeProjectRoot.StartsWith("\\"))
{
SourceRelativeProjectRoot = SourceRelativeProjectRoot.Substring(1);
}
if (Stage)
{
CommandUtils.CreateDirectory(StageDirectory);
StageProjectRoot = CommandUtils.CombinePaths(StageDirectory, RelativeProjectRootForStage);
RuntimeRootDir = StageDirectory;
CookSourceRuntimeRootDir = CommandUtils.CombinePaths(BaseStageDirectory, CookPlatform);
RuntimeProjectRootDir = StageProjectRoot;
ProjectArgForCommandLines = CommandUtils.MakePathSafeToUseWithCommandLine(UProjectCommandLineArgInternalRoot + RelativeProjectRootForStage + "/" + ShortProjectName + ".uproject");
}
if (Archive)
{
CommandUtils.CreateDirectory(ArchiveDirectory);
}
ProjectArgForCommandLines = ProjectArgForCommandLines.Replace("\\", "/");
ProjectBinariesFolder = CommandUtils.CombinePaths(ProjectUtils.GetClientProjectBinariesRootPath(RawProjectPath, TargetRules.TargetType.Game, IsCodeBasedProject), PlatformDir);
}
public void StageFile(StagedFileType FileType, string InputPath, string OutputPath = null, bool bRemap = true)
{
InputPath = InputPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
if(OutputPath == null)
{
if(InputPath.StartsWith(ProjectRoot, StringComparison.InvariantCultureIgnoreCase))
{
OutputPath = CommandUtils.CombinePaths(RelativeProjectRootForStage, InputPath.Substring(ProjectRoot.Length).TrimStart('/', '\\'));
}
else if (InputPath.StartsWith(LocalRoot, StringComparison.InvariantCultureIgnoreCase))
{
OutputPath = CommandUtils.CombinePaths(InputPath.Substring(LocalRoot.Length).TrimStart('/', '\\'));
}
else
{
throw new AutomationException("Can't deploy {0} because it doesn't start with {1} or {2}", InputPath, ProjectRoot, LocalRoot);
}
}
if(bRemap)
{
OutputPath = StageTargetPlatform.Remap(OutputPath);
}
if (FileType == StagedFileType.UFS)
{
AddUniqueStagingFile(UFSStagingFiles, InputPath, OutputPath);
}
else if (FileType == StagedFileType.NonUFS)
{
AddStagingFile(NonUFSStagingFiles, InputPath, OutputPath);
}
else if (FileType == StagedFileType.DebugNonUFS)
{
AddStagingFile(NonUFSStagingFilesDebug, InputPath, OutputPath);
}
}
public void StageBuildProductsFromReceipt(TargetReceipt Receipt, bool RequireDependenciesToExist, bool TreatNonShippingBinariesAsDebugFiles)
{
// Stage all the build products needed at runtime
foreach(BuildProduct BuildProduct in Receipt.BuildProducts)
{
// allow missing files if needed
if (RequireDependenciesToExist == false && File.Exists(BuildProduct.Path) == false)
{
continue;
}
if(BuildProduct.Type == BuildProductType.Executable || BuildProduct.Type == BuildProductType.DynamicLibrary || BuildProduct.Type == BuildProductType.RequiredResource)
{
StagedFileType FileTypeToUse = StagedFileType.NonUFS;
if (TreatNonShippingBinariesAsDebugFiles && Receipt.Configuration != UnrealTargetConfiguration.Shipping)
{
FileTypeToUse = StagedFileType.DebugNonUFS;
}
StageFile(FileTypeToUse, BuildProduct.Path);
}
else if(BuildProduct.Type == BuildProductType.SymbolFile)
{
StageFile(StagedFileType.DebugNonUFS, BuildProduct.Path);
}
}
}
public void StageRuntimeDependenciesFromReceipt(TargetReceipt Receipt, bool RequireDependenciesToExist, bool bUsingPakFile)
{
// Patterns to exclude from wildcard searches. Any maps and assets must be cooked.
List<string> ExcludePatterns = new List<string>();
ExcludePatterns.Add(".../*.umap");
ExcludePatterns.Add(".../*.uasset");
// Also stage any additional runtime dependencies, like ThirdParty DLLs
foreach(RuntimeDependency RuntimeDependency in Receipt.RuntimeDependencies)
{
foreach(FileReference File in CommandUtils.ResolveFilespec(CommandUtils.RootDirectory, RuntimeDependency.Path, ExcludePatterns))
{
// allow missing files if needed
if ((RequireDependenciesToExist && RuntimeDependency.Type != StagedFileType.DebugNonUFS) || File.Exists())
{
bool bRemap = RuntimeDependency.Type != StagedFileType.UFS || !bUsingPakFile;
StageFile(RuntimeDependency.Type, File.FullName, bRemap: bRemap);
}
}
}
}
public void StageFiles(StagedFileType FileType, string InPath, string Wildcard = "*", bool bRecursive = true, string[] ExcludeWildcard = null, string NewPath = null, bool bAllowNone = false, bool bRemap = true, string NewName = null, bool bAllowNotForLicenseesFiles = true, bool bStripFilesForOtherPlatforms = true)
{
int FilesAdded = 0;
// make sure any ..'s are removed
Utils.CollapseRelativeDirectories(ref InPath);
if (CommandUtils.DirectoryExists(InPath))
{
var All = CommandUtils.FindFiles(Wildcard, bRecursive, InPath);
var Exclude = new HashSet<string>();
if (ExcludeWildcard != null)
{
foreach (var Excl in ExcludeWildcard)
{
var Remove = CommandUtils.FindFiles(Excl, bRecursive, InPath);
foreach (var File in Remove)
{
Exclude.Add(CommandUtils.CombinePaths(File));
}
}
}
foreach (var AllFile in All)
{
var FileToCopy = CommandUtils.CombinePaths(AllFile);
if (Exclude.Contains(FileToCopy))
{
continue;
}
if (!bAllowNotForLicenseesFiles && (FileToCopy.Contains("NotForLicensees") || FileToCopy.Contains("NoRedist")))
{
continue;
}
if (bStripFilesForOtherPlatforms && !bIsCombiningMultiplePlatforms)
{
bool OtherPlatform = false;
foreach (UnrealTargetPlatform Plat in Enum.GetValues(typeof(UnrealTargetPlatform)))
{
bool bMatchesIniPlatform = (AllFile.EndsWith(".ini") && Plat == StageTargetPlatform.IniPlatformType); // filter ini files for the ini file platform
bool bMatchesTargetPlatform = (Plat == StageTargetPlatform.PlatformType || Plat == UnrealTargetPlatform.Unknown); // filter platform files for the target platform
if (!bMatchesIniPlatform && !bMatchesTargetPlatform)
{
var Search = FileToCopy;
if (Search.StartsWith(LocalRoot, StringComparison.InvariantCultureIgnoreCase))
{
if (LocalRoot.EndsWith("\\") || LocalRoot.EndsWith("/"))
{
Search = Search.Substring(LocalRoot.Length - 1);
}
else
{
Search = Search.Substring(LocalRoot.Length);
}
}
if (Search.StartsWith(ProjectRoot, StringComparison.InvariantCultureIgnoreCase))
{
if (ProjectRoot.EndsWith("\\") || ProjectRoot.EndsWith("/"))
{
Search = Search.Substring(ProjectRoot.Length - 1);
}
else
{
Search = Search.Substring(ProjectRoot.Length);
}
}
if (Search.IndexOf(CommandUtils.CombinePaths("/" + Plat.ToString() + "/"), 0, StringComparison.InvariantCultureIgnoreCase) >= 0)
{
OtherPlatform = true;
break;
}
}
}
if (OtherPlatform)
{
continue;
}
}
string Dest;
if (!FileToCopy.StartsWith(InPath))
{
throw new AutomationException("Can't deploy {0}; it was supposed to start with {1}", FileToCopy, InPath);
}
string FileToRemap = FileToCopy;
// If the specified a new directory, first we deal with that, then apply the other things
// this is used to collapse the sandbox, among other things
if (NewPath != null)
{
Dest = FileToRemap.Substring(InPath.Length);
if (Dest.StartsWith("/") || Dest.StartsWith("\\"))
{
Dest = Dest.Substring(1);
}
Dest = CommandUtils.CombinePaths(NewPath, Dest);
#if false // if the cooker rebases, I don't think we need to ever rebase while staging to a new path
if (Dest.StartsWith("/") || Dest.StartsWith("\\"))
{
Dest = Dest.Substring(1);
}
// project relative stuff in a collapsed sandbox
if (Dest.StartsWith(SourceRelativeProjectRoot, StringComparison.InvariantCultureIgnoreCase))
{
Dest = Dest.Substring(SourceRelativeProjectRoot.Length);
if (Dest.StartsWith("/") || Dest.StartsWith("\\"))
{
Dest = Dest.Substring(1);
}
Dest = CommandUtils.CombinePaths(RelativeProjectRootForStage, Dest);
}
#endif
}
// project relative file
else if (FileToRemap.StartsWith(ProjectRoot, StringComparison.InvariantCultureIgnoreCase))
{
Dest = FileToRemap.Substring(ProjectRoot.Length);
if (Dest.StartsWith("/") || Dest.StartsWith("\\"))
{
Dest = Dest.Substring(1);
}
Dest = CommandUtils.CombinePaths(RelativeProjectRootForStage, Dest);
}
// engine relative file
else if (FileToRemap.StartsWith(LocalRoot, StringComparison.InvariantCultureIgnoreCase))
{
Dest = CommandUtils.CombinePaths(FileToRemap.Substring(LocalRoot.Length));
}
else
{
throw new AutomationException("Can't deploy {0} because it doesn't start with {1} or {2}", FileToRemap, ProjectRoot, LocalRoot);
}
if (Dest.StartsWith("/") || Dest.StartsWith("\\"))
{
Dest = Dest.Substring(1);
}
if (NewName != null)
{
Dest = CommandUtils.CombinePaths(Path.GetDirectoryName(Dest), NewName);
}
if (bRemap)
{
Dest = StageTargetPlatform.Remap(Dest);
}
if (FileType == StagedFileType.UFS)
{
AddUniqueStagingFile(UFSStagingFiles, FileToCopy, Dest);
}
else if (FileType == StagedFileType.NonUFS)
{
AddStagingFile(NonUFSStagingFiles, FileToCopy, Dest);
}
else if (FileType == StagedFileType.DebugNonUFS)
{
AddStagingFile(NonUFSStagingFilesDebug, FileToCopy, Dest);
}
FilesAdded++;
}
}
if (FilesAdded == 0 && !bAllowNone && !bIsCombiningMultiplePlatforms)
{
throw new AutomationException(ExitCode.Error_StageMissingFile, "No files found to deploy for {0} with wildcard {1} and exclusions {2}", InPath, Wildcard, ExcludeWildcard);
}
}
private void AddUniqueStagingFile(Dictionary<string, string> FilesToStage, string FileToCopy, string Dest)
{
string ExistingDest;
if (FilesToStage.TryGetValue(FileToCopy, out ExistingDest))
{
// If the file already exists, it must have the same dest
if (String.Compare(ExistingDest, Dest, true) != 0)
{
throw new AutomationException("Attempting to add \"{0}\" to staging map but it already exists with a different destination (existing: \"{1}\", new: \"{2}\"",
FileToCopy, ExistingDest, Dest);
}
}
else
{
FilesToStage.Add(FileToCopy, Dest);
}
}
private void AddStagingFile(Dictionary<string, List<string>> FilesToStage, string FileToCopy, string Dest)
{
List<string> ExistingDest;
if (FilesToStage.TryGetValue(FileToCopy, out ExistingDest))
{
if (!FilesToStage[FileToCopy].Contains(Dest))
{
FilesToStage[FileToCopy].Add(Dest);
}
}
else
{
FilesToStage.Add(FileToCopy, new List<string>(){Dest});
}
}
public int ArchiveFiles(string InPath, string Wildcard = "*", bool bRecursive = true, string[] ExcludeWildcard = null, string NewPath = null)
{
int FilesAdded = 0;
if (CommandUtils.DirectoryExists(InPath))
{
var All = CommandUtils.FindFiles(Wildcard, bRecursive, InPath);
var Exclude = new HashSet<string>();
if (ExcludeWildcard != null)
{
foreach (var Excl in ExcludeWildcard)
{
var Remove = CommandUtils.FindFiles(Excl, bRecursive, InPath);
foreach (var File in Remove)
{
Exclude.Add(CommandUtils.CombinePaths(File));
}
}
}
foreach (var AllFile in All)
{
var FileToCopy = CommandUtils.CombinePaths(AllFile);
if (Exclude.Contains(FileToCopy))
{
continue;
}
if (!bIsCombiningMultiplePlatforms)
{
bool OtherPlatform = false;
foreach (UnrealTargetPlatform Plat in Enum.GetValues(typeof(UnrealTargetPlatform)))
{
if (Plat != StageTargetPlatform.PlatformType && Plat != UnrealTargetPlatform.Unknown)
{
var Search = FileToCopy;
if (Search.StartsWith(LocalRoot, StringComparison.InvariantCultureIgnoreCase))
{
if (LocalRoot.EndsWith("\\") || LocalRoot.EndsWith("/"))
{
Search = Search.Substring(LocalRoot.Length - 1);
}
else
{
Search = Search.Substring(LocalRoot.Length);
}
}
if (Search.StartsWith(ProjectRoot, StringComparison.InvariantCultureIgnoreCase))
{
if (ProjectRoot.EndsWith("\\") || ProjectRoot.EndsWith("/"))
{
Search = Search.Substring(ProjectRoot.Length - 1);
}
else
{
Search = Search.Substring(ProjectRoot.Length);
}
}
if (Search.IndexOf(CommandUtils.CombinePaths("/" + Plat.ToString() + "/"), 0, StringComparison.InvariantCultureIgnoreCase) >= 0)
{
OtherPlatform = true;
break;
}
}
}
if (OtherPlatform)
{
continue;
}
}
string Dest;
if (!FileToCopy.StartsWith(InPath))
{
throw new AutomationException("Can't archive {0}; it was supposed to start with {1}", FileToCopy, InPath);
}
// If the specified a new directory, first we deal with that, then apply the other things
// this is used to collapse the sandbox, among other things
if (NewPath != null)
{
Dest = FileToCopy.Substring(InPath.Length);
if (Dest.StartsWith("/") || Dest.StartsWith("\\"))
{
Dest = Dest.Substring(1);
}
Dest = CommandUtils.CombinePaths(NewPath, Dest);
}
else
{
Dest = FileToCopy.Substring(InPath.Length);
}
if (Dest.StartsWith("/") || Dest.StartsWith("\\"))
{
Dest = Dest.Substring(1);
}
if (ArchivedFiles.ContainsKey(FileToCopy))
{
if (ArchivedFiles[FileToCopy] != Dest)
{
throw new AutomationException("Can't archive {0}: it was already in the files to archive with a different destination '{1}'", FileToCopy, Dest);
}
}
else
{
ArchivedFiles.Add(FileToCopy, Dest);
}
FilesAdded++;
}
}
return FilesAdded;
}
public String GetUFSDeploymentDeltaPath(string DeviceName)
{
return Path.Combine(StageDirectory, UFSDeployDeltaFileName + DeviceName);
}
public String GetNonUFSDeploymentDeltaPath(string DeviceName)
{
return Path.Combine(StageDirectory, NonUFSDeployDeltaFileName + DeviceName);
}
public String GetUFSDeploymentObsoletePath(string DeviceName)
{
return Path.Combine(StageDirectory, UFSDeployObsoleteFileName + DeviceName);
}
public String GetNonUFSDeploymentObsoletePath(string DeviceName)
{
return Path.Combine(StageDirectory, NonUFSDeployObsoleteFileName + DeviceName);
}
public string UFSDeployedManifestFileName
{
get
{
return "Manifest_UFSFiles_" + StageTargetPlatform.PlatformType.ToString() + ".txt";
}
}
public string NonUFSDeployedManifestFileName
{
get
{
return "Manifest_NonUFSFiles_" + StageTargetPlatform.PlatformType.ToString() + ".txt";
}
}
public static string GetNonUFSDeployedManifestFileName(UnrealTargetPlatform PlatformType)
{
return "Manifest_NonUFSFiles_" + PlatformType.ToString() + ".txt";
}
public static string GetUFSDeployedManifestFileName(UnrealTargetPlatform PlatformType)
{
return "Manifest_UFSFiles_" + PlatformType.ToString() + ".txt";
}
public static string GetDebugFilesManifestFileName(UnrealTargetPlatform PlatformType)
{
return "Manifest_DebugFiles_" + PlatformType.ToString() + ".txt";
}
}