// Copyright Epic Games, Inc.All Rights Reserved. using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; using AutomationTool; using FileLockInfo; namespace LyraDeployment { // Documentation // https://dev.epicgames.com/docs/services/en-US/EpicGamesStore/TechFeaturesConfig/BPTInstructionsSPT/index.html public class DeployToEpicGameStore : BuildCommand { static string DownloadBuildPackageTool() { // Download build package tool 1.5 string BuildPackageToolUrl = "https://launcher-public-service-prod.ol.epicgames.com/launcher/api/installer/download/BuildPatchTool.zip"; var BuildPathToolDownloadPath = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "BuildPatchTool.zip"); var BuildPathToolInstallPath = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "BPT"); var BuildPathToolPath = CommandUtils.CombinePaths(BuildPathToolInstallPath, "Engine/Binaries/Win64/BuildPatchTool.exe"); if (Directory.Exists(BuildPathToolInstallPath)) { Directory.Delete(BuildPathToolInstallPath, true); } using (var client = new WebClient()) { client.DownloadFile(BuildPackageToolUrl, BuildPathToolDownloadPath); } // Decompress the zip file to the target directory CommandUtils.LogInformation("Decompressing to {0}...", BuildPathToolInstallPath); CommandUtils.LegacyUnzipFiles(BuildPathToolDownloadPath, BuildPathToolInstallPath); CommandUtils.DeleteFile(BuildPathToolDownloadPath); // Make sure the file we need exists. CommandUtils.FileExists(false, BuildPathToolPath); return BuildPathToolPath; } public DeployToEpicGameStore() { } public override void ExecuteBuild() { LogInformation("*************************"); var LogInstanceId = Guid.NewGuid().ToString("N"); var LogFileDirectory = CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Saved", "Logs", "BuildPatchToolLog"); var BuildPathToolPath = DownloadBuildPackageTool(); string ArtifactId = ParseParamValue("ArtifactId", null); string BuildRoot = ParseParamValue("BuildRoot", null); string CloudDir = ParseParamValue("CloudDir", null); string BuildVersion = ParseParamValue("BuildVersion", null); string AppLaunch = ParseParamValue("AppLaunch", null); string AppArgs = ParseParamValue("AppArgs", null); string FileAttributeList = ParseParamValue("FileAttributeList", null); string FileIgnoreList = ParseParamValue("FileIgnoreList", null); string Platform = ParseParamValue("Platform", null); string Label = ParseParamValue("Label", null); string CommandLineFile = ParseParamValue("CommandLineFile", null); if (Directory.Exists(CloudDir)) { Directory.Delete(CloudDir, true); } // Verify nothing is locked before moving on. { CommandUtils.LogInformation("Are Build Files Are Unlocked: Starting"); string[] FilesInBuildRoot = Directory.GetFiles(BuildRoot); // We need to make sure nothing is locking the build files. Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); while (stopwatch.Elapsed.TotalSeconds < 30) { List LockingProcesses = Win32Processes.GetProcessesLockingFiles(FilesInBuildRoot); if (LockingProcesses.Count > 0) { string LockingProcessesString = string.Join(", ", LockingProcesses.Select(c => c.ProcessName)); CommandUtils.LogInformation("The following processes are locking files, {0}", LockingProcessesString); Thread.Sleep(2000); } } stopwatch.Stop(); CommandUtils.LogInformation("Are Build Files Are Unlocked: Done"); } CommandUtils.LogInformation("Running BuildPatchTool Patch Generation on {0}", ArtifactId); { string Args = ""; Args += Arg("mode", "PatchGeneration"); Args += Arg("ArtifactId", ArtifactId); Args += Arg("BuildRoot", Path.GetFullPath(BuildRoot)); Args += Arg("CloudDir", Path.GetFullPath(CloudDir)); Args += Arg("BuildVersion", BuildVersion); Args += Arg("AppLaunch", AppLaunch); Args += Arg("AppArgs", AppArgs); Args += Arg("FileAttributeList", FileAttributeList); Args += Arg("FileIgnoreList", FileIgnoreList); if (!String.IsNullOrEmpty(CommandLineFile)) { Args += " " + File.ReadAllText(Path.GetFullPath(CommandLineFile)); } // Add -stdout so that Horde gets logging. Args += Arg("stdout"); //string LogFileName = String.Concat("BuildPatchTool-PatchGeneration-", LogInstanceId); //string LogFilePath = Path.Combine(LogFileDirectory, String.Concat(LogFileName, ".stdout.log")); try { CommandUtils.RunAndLog(BuildPathToolPath, Args); } catch (AutomationException Ex) { CommandUtils.LogError(Ex.ToString()); //if (File.Exists(LogFilePath)) //{ // CommandUtils.LogInformation(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); // CommandUtils.LogInformation(File.ReadAllText(LogFilePath)); // CommandUtils.LogInformation(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); //} throw Ex; } } CommandUtils.LogInformation("BuildPatchTool Patch Generation Done!"); CommandUtils.LogInformation("Running BuildPatchTool LabelBuild on {0}", ArtifactId); { string Args = ""; Args += Arg("mode", "LabelBuild"); Args += Arg("ArtifactId", ArtifactId); Args += Arg("BuildRoot", Path.GetFullPath(BuildRoot)); Args += Arg("CloudDir", Path.GetFullPath(CloudDir)); Args += Arg("BuildVersion", BuildVersion); Args += Arg("Platform", Platform); Args += Arg("Label", Label); if (!String.IsNullOrEmpty(CommandLineFile)) { Args += " " + File.ReadAllText(Path.GetFullPath(CommandLineFile)); } // Add -stdout so that Horde gets logging. Args += Arg("stdout"); //string LogFileName = String.Concat("BuildPatchTool-LabelBuild-", LogInstanceId); //string LogFilePath = Path.Combine(LogFileDirectory, String.Concat(LogFileName, ".stdout.log")); try { CommandUtils.RunAndLog(BuildPathToolPath, Args/*, LogFilePath*/); } catch (AutomationException Ex) { CommandUtils.LogError(Ex.ToString()); //if (File.Exists(LogFilePath)) //{ // CommandUtils.LogInformation(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); // CommandUtils.LogInformation(File.ReadAllText(LogFilePath)); // CommandUtils.LogInformation(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); //} throw Ex; } } CommandUtils.LogInformation("BuildPatchTool Patch Generation Done!"); LogInformation("*************************"); } private static string Arg(string Key, string Value) { return Value == null ? "" : " -" + Key + "=\"" + Value + "\""; } private static string Arg(string Key, int Value) { return " -" + Key + "=" + Value; } private static string Arg(string Key, ulong Value) { return " -" + Key + "=" + Value; } private static string Arg(string Key) { return " -" + Key; } private static string Arg(string Key, IEnumerable Value) { return " -" + Key + "=\"" + string.Join(",", Value) + "\""; } private static string CustomArgs(string ArgName, List> CustomArgs) { var Result = new StringBuilder(); if (CustomArgs != null) { foreach (var CustomArg in CustomArgs) { Result.Append(string.Format(" -{0}=\"{1}={2}\"", ArgName, CustomArg.Key, CustomArg.Value.ToString())); } } return Result.ToString(); } } }