示例#1
0
        /// <summary>
        /// Execute the task.
        /// </summary>
        /// <param name="Job">Information about the current job</param>
        /// <param name="BuildProducts">Set of build products produced by this node.</param>
        /// <param name="TagNameToFileSet">Mapping from tag names to the set of files they include</param>
        /// <returns>True if the task succeeded</returns>
        public override bool Execute(JobContext Job, HashSet <FileReference> BuildProducts, Dictionary <string, HashSet <FileReference> > TagNameToFileSet)
        {
            bool bSuccess = false;

            UEBuildPlatform Platform  = UEBuildPlatform.GetBuildPlatform(Parameters.Platform);
            UEToolChain     ToolChain = Platform.CreateContext(null, null).CreateToolChainForDefaultCppPlatform();

            // Find the matching files
            List <FileReference> Files = ResolveFilespec(CommandUtils.RootDirectory, Parameters.Files, TagNameToFileSet).ToList();

            // Get the symbol store directory
            DirectoryReference StoreDir = ResolveDirectory(Parameters.StoreDir);

            // Take the lock before accessing the symbol server
            LockFile.TakeLock(StoreDir, TimeSpan.FromMinutes(15), () =>
            {
                bSuccess = ToolChain.PublishSymbols(StoreDir, Files, Parameters.Product);
            });

            if (!bSuccess)
            {
                CommandUtils.LogError("Failure publishing symbol files.");
            }

            return(bSuccess);
        }
示例#2
0
        /// <summary>
        /// Execute the task.
        /// </summary>
        /// <param name="Job">Information about the current job</param>
        /// <param name="BuildProducts">Set of build products produced by this node.</param>
        /// <param name="TagNameToFileSet">Mapping from tag names to the set of files they include</param>
        /// <returns>True if the task succeeded</returns>
        public override bool Execute(JobContext Job, HashSet <FileReference> BuildProducts, Dictionary <string, HashSet <FileReference> > TagNameToFileSet)
        {
            // Get the list of symbol file name patterns from the platform.
            UEBuildPlatform Platform           = UEBuildPlatform.GetBuildPlatform(Parameters.Platform);
            UEToolChain     ToolChain          = Platform.CreateContext(null).CreateToolChainForDefaultCppPlatform();
            var             DirectoryStructure = ToolChain.SymbolServerDirectoryStructure;

            if (DirectoryStructure == null)
            {
                CommandUtils.LogError("Platform does not specify the symbol server structure. Cannot age the symbol server.");
                return(false);
            }

            string Filter = string.IsNullOrWhiteSpace(Parameters.Filter)
                ? string.Empty
                : Parameters.Filter.Trim();

            // Get the time at which to expire files
            DateTime ExpireTimeUtc = DateTime.UtcNow - TimeSpan.FromDays(Parameters.Days);

            CommandUtils.Log("Expiring all files before {0}...", ExpireTimeUtc);

            // Scan the store directory and delete old symbol files
            DirectoryReference SymbolServerDirectory = ResolveDirectory(Parameters.StoreDir);

            LockFile.TakeLock(SymbolServerDirectory, TimeSpan.FromMinutes(15), () =>
            {
                RecurseDirectory(ExpireTimeUtc, new DirectoryInfo(SymbolServerDirectory.FullName), DirectoryStructure, 0, Filter);
            });

            return(true);
        }
        /// <summary>
        /// Execute the task.
        /// </summary>
        /// <param name="Job">Information about the current job</param>
        /// <param name="BuildProducts">Set of build products produced by this node.</param>
        /// <param name="TagNameToFileSet">Mapping from tag names to the set of files they include</param>
        /// <returns>True if the task succeeded</returns>
        public override bool Execute(JobContext Job, HashSet <FileReference> BuildProducts, Dictionary <string, HashSet <FileReference> > TagNameToFileSet)
        {
            // Get the base directory
            DirectoryReference BaseDir = ResolveDirectory(Parameters.BaseDir);

            // Get the output directory
            DirectoryReference OutputDir = ResolveDirectory(Parameters.OutputDir);

            // Make sure the source and destination directories don't overlap. We can't strip in-place at the moment.
            if (BaseDir == OutputDir)
            {
                CommandUtils.LogError("Output directory for stripped files is the same as source directory ({0})", BaseDir.FullName);
                return(false);
            }

            // Find the matching files
            FileReference[] SourceFiles = ResolveFilespec(BaseDir, Parameters.Files, TagNameToFileSet).OrderBy(x => x.FullName).ToArray();

            // Create the matching target files
            FileReference[] TargetFiles = SourceFiles.Select(x => FileReference.Combine(OutputDir, x.MakeRelativeTo(BaseDir))).ToArray();

            // Run the stripping command
            UEBuildPlatform Platform  = UEBuildPlatform.GetBuildPlatform(Parameters.Platform);
            UEToolChain     ToolChain = Platform.CreateContext(null, null).CreateToolChainForDefaultCppPlatform();

            for (int Idx = 0; Idx < SourceFiles.Length; Idx++)
            {
                TargetFiles[Idx].Directory.CreateDirectory();
                CommandUtils.Log("Stripping symbols: {0} -> {1}", SourceFiles[Idx].FullName, TargetFiles[Idx].FullName);
                ToolChain.StripSymbols(SourceFiles[Idx].FullName, TargetFiles[Idx].FullName);
            }

            // Apply the optional tag to the build products
            foreach (string TagName in FindTagNamesFromList(Parameters.Tag))
            {
                FindOrAddTagSet(TagNameToFileSet, TagName).UnionWith(TargetFiles);
            }

            // Add the target files to the set of build products
            BuildProducts.UnionWith(TargetFiles);
            return(true);
        }
示例#4
0
        public override bool PrepTargetForDeployment(UEBuildTarget InTarget)
        {
            string GameName         = InTarget.TargetName;
            string BuildPath        = (GameName == "UE4Game" ? "../../Engine" : InTarget.ProjectDirectory) + "/Binaries/IOS";
            string ProjectDirectory = InTarget.ProjectDirectory;
            bool   bIsUE4Game       = GameName.Contains("UE4Game");

            string DecoratedGameName;

            if (InTarget.Configuration == UnrealTargetConfiguration.Development)
            {
                DecoratedGameName = GameName;
            }
            else
            {
                DecoratedGameName = String.Format("{0}-{1}-{2}", GameName, InTarget.Platform.ToString(), InTarget.Configuration.ToString());
            }

            if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac && Environment.GetEnvironmentVariable("UBT_NO_POST_DEPLOY") != "true")
            {
                return(PrepForUATPackageOrDeploy(GameName, ProjectDirectory, BuildPath + "/" + DecoratedGameName, "../../Engine", false, "", false));
            }
            else
            {
                // If it is requested, send the app bundle back to the platform executing these commands.
                if (BuildConfiguration.bCopyAppBundleBackToDevice)
                {
                    Log.TraceInformation("Copying binaries back to this device...");

                    IOSToolChain Toolchain = UEToolChain.GetPlatformToolChain(CPPTargetPlatform.IOS) as IOSToolChain;

                    try
                    {
                        string BinaryDir = Path.GetDirectoryName(InTarget.OutputPath) + "\\";
                        if (BinaryDir.EndsWith(InTarget.AppName + "\\Binaries\\IOS\\") && InTarget.TargetType != TargetRules.TargetType.Game)
                        {
                            BinaryDir = BinaryDir.Replace(InTarget.TargetType.ToString(), "Game");
                        }

                        // Get the app bundle's name
                        string AppFullName = InTarget.AppName;
                        if (InTarget.Configuration != UnrealTargetConfiguration.Development)
                        {
                            AppFullName += "-" + InTarget.Platform.ToString();
                            AppFullName += "-" + InTarget.Configuration.ToString();
                        }

                        foreach (string BinaryPath in Toolchain.BuiltBinaries)
                        {
                            if (!BinaryPath.Contains("Dummy"))
                            {
                                RPCUtilHelper.CopyFile(Toolchain.ConvertPath(BinaryPath), BinaryPath, false);
                            }
                        }
                        Log.TraceInformation("Copied binaries successfully.");
                    }
                    catch (Exception)
                    {
                        Log.TraceInformation("Copying binaries back to this device failed.");
                    }
                }

                GeneratePList(ProjectDirectory, bIsUE4Game, GameName, Path.GetFileNameWithoutExtension(UnrealBuildTool.GetUProjectFile()), "../../Engine", "");
            }
            return(true);
        }
示例#5
0
        public override bool PrepTargetForDeployment(UEBuildTarget InTarget)
        {
            Log.TraceInformation("Deploying now!");

            string IntermediateDirectory = InTarget.AppName + "/Intermediate/Build/Mac/" + InTarget.AppName + "/" + InTarget.Configuration;

            if (!Directory.Exists("../../" + IntermediateDirectory))
            {
                IntermediateDirectory = "Engine/Intermediate/Build/Mac/" + InTarget.AppName + "/" + InTarget.Configuration;
            }

            MacToolChain Toolchain = UEToolChain.GetPlatformToolChain(CPPTargetPlatform.Mac) as MacToolChain;

            string FixDylibDepsScript      = Path.Combine(IntermediateDirectory, "FixDylibDependencies.sh");
            string FinalizeAppBundleScript = Path.Combine(IntermediateDirectory, "FinalizeAppBundle.sh");

            string RemoteWorkingDir = "";

            bool bIsStaticLibrary = InTarget.OutputPath.EndsWith(".a");

            if (BuildHostPlatform.Current.Platform != UnrealTargetPlatform.Mac)
            {
                if (!bIsStaticLibrary)
                {
                    // Copy the command scripts to the intermediate on the target Mac.
                    string RemoteFixDylibDepsScript = Toolchain.ConvertPath(Path.GetFullPath(FixDylibDepsScript));
                    RemoteFixDylibDepsScript = RemoteFixDylibDepsScript.Replace("../../../../", "../../");
                    RPCUtilHelper.CopyFile("../../" + FixDylibDepsScript, RemoteFixDylibDepsScript, true);

                    if (!InTarget.GlobalLinkEnvironment.Config.bIsBuildingConsoleApplication)
                    {
                        string RemoteFinalizeAppBundleScript = Toolchain.ConvertPath(Path.GetFullPath(FinalizeAppBundleScript));
                        RemoteFinalizeAppBundleScript = RemoteFinalizeAppBundleScript.Replace("../../../../", "../../");
                        RPCUtilHelper.CopyFile("../../" + FinalizeAppBundleScript, RemoteFinalizeAppBundleScript, true);
                    }


                    // run it remotely
                    RemoteWorkingDir = Toolchain.ConvertPath(Path.GetDirectoryName(Path.GetFullPath(FixDylibDepsScript)));

                    Log.TraceInformation("Running FixDylibDependencies.sh...");
                    Hashtable Results = RPCUtilHelper.Command(RemoteWorkingDir, "/bin/sh", "FixDylibDependencies.sh", null);
                    if (Results != null)
                    {
                        string Result = (string)Results["CommandOutput"];
                        if (Result != null)
                        {
                            Log.TraceInformation(Result);
                        }
                    }

                    if (!InTarget.GlobalLinkEnvironment.Config.bIsBuildingConsoleApplication)
                    {
                        Log.TraceInformation("Running FinalizeAppBundle.sh...");
                        Results = RPCUtilHelper.Command(RemoteWorkingDir, "/bin/sh", "FinalizeAppBundle.sh", null);
                        if (Results != null)
                        {
                            string Result = (string)Results["CommandOutput"];
                            if (Result != null)
                            {
                                Log.TraceInformation(Result);
                            }
                        }
                    }
                }


                // If it is requested, send the app bundle back to the platform executing these commands.
                if (BuildConfiguration.bCopyAppBundleBackToDevice)
                {
                    Log.TraceInformation("Copying binaries back to this device...");

                    try
                    {
                        string BinaryDir = Path.GetDirectoryName(InTarget.OutputPath) + "\\";
                        if (BinaryDir.EndsWith(InTarget.AppName + "\\Binaries\\Mac\\") && InTarget.TargetType != TargetRules.TargetType.Game)
                        {
                            BinaryDir = BinaryDir.Replace(InTarget.TargetType.ToString(), "Game");
                        }

                        string RemoteBinariesDir = Toolchain.ConvertPath(BinaryDir);
                        string LocalBinariesDir  = BinaryDir;

                        // Get the app bundle's name
                        string AppFullName = InTarget.AppName;
                        if (InTarget.Configuration != UnrealTargetConfiguration.Development)
                        {
                            AppFullName += "-" + InTarget.Platform.ToString();
                            AppFullName += "-" + InTarget.Configuration.ToString();
                        }

                        if (!InTarget.GlobalLinkEnvironment.Config.bIsBuildingConsoleApplication)
                        {
                            AppFullName += ".app";
                        }

                        List <string> NotBundledBinaries = new List <string>();
                        foreach (string BinaryPath in Toolchain.BuiltBinaries)
                        {
                            if (InTarget.GlobalLinkEnvironment.Config.bIsBuildingConsoleApplication || bIsStaticLibrary || !BinaryPath.StartsWith(LocalBinariesDir + AppFullName))
                            {
                                NotBundledBinaries.Add(BinaryPath);
                            }
                        }

                        // Zip the app bundle for transferring.
                        if (!InTarget.GlobalLinkEnvironment.Config.bIsBuildingConsoleApplication && !bIsStaticLibrary)
                        {
                            string ZipCommand = "zip -0 -r -y -T \"" + AppFullName + ".zip\" \"" + AppFullName + "\"";
                            RPCUtilHelper.Command(RemoteBinariesDir, ZipCommand, "", null);

                            // Copy the AppBundle back to the source machine
                            string LocalZipFileLocation  = LocalBinariesDir + AppFullName + ".zip ";
                            string RemoteZipFileLocation = RemoteBinariesDir + AppFullName + ".zip";

                            RPCUtilHelper.CopyFile(RemoteZipFileLocation, LocalZipFileLocation, false);

                            // Extract the copied app bundle (in zip format) to the local binaries directory
                            using (ZipFile AppBundleZip = ZipFile.Read(LocalZipFileLocation))
                            {
                                foreach (ZipEntry Entry in AppBundleZip)
                                {
                                    Entry.Extract(LocalBinariesDir, ExtractExistingFileAction.OverwriteSilently);
                                }
                            }

                            // Delete the zip as we no longer need/want it.
                            File.Delete(LocalZipFileLocation);
                            RPCUtilHelper.Command(RemoteBinariesDir, "rm -f \"" + AppFullName + ".zip\"", "", null);
                        }

                        if (NotBundledBinaries.Count > 0)
                        {
                            foreach (string BinaryPath in NotBundledBinaries)
                            {
                                RPCUtilHelper.CopyFile(Toolchain.ConvertPath(BinaryPath), BinaryPath, false);
                            }
                        }

                        Log.TraceInformation("Copied binaries successfully.");
                    }
                    catch (Exception)
                    {
                        Log.TraceInformation("Copying binaries back to this device failed.");
                    }
                }
            }

            return(true);
        }
示例#6
0
		public override bool PrepTargetForDeployment(UEBuildTarget InTarget)
		{
			string GameName = InTarget.AppName;
			string BuildPath = InTarget.ProjectDirectory + "/Binaries/IOS";
			string ProjectDirectory = InTarget.ProjectDirectory;

			if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac && Environment.GetEnvironmentVariable("UBT_NO_POST_DEPLOY") != "true")
			{
				string DecoratedGameName;
				if (InTarget.Configuration == UnrealTargetConfiguration.Development)
				{
					DecoratedGameName = GameName;
				}
				else
				{
					DecoratedGameName = String.Format("{0}-{1}-{2}", GameName, InTarget.Platform.ToString(), InTarget.Configuration.ToString());
				}

				return PrepForUATPackageOrDeploy(GameName, ProjectDirectory, BuildPath + "/" + DecoratedGameName, "../../Engine", false, "");
			}
			else
			{
				// If it is requested, send the app bundle back to the platform executing these commands.
				if (BuildConfiguration.bCopyAppBundleBackToDevice)
				{
					Log.TraceInformation("Copying binaries back to this device...");

					IOSToolChain Toolchain = UEToolChain.GetPlatformToolChain(CPPTargetPlatform.IOS) as IOSToolChain;

					try
					{
						string BinaryDir = Path.GetDirectoryName(InTarget.OutputPath) + "\\";
						if (BinaryDir.EndsWith(InTarget.AppName + "\\Binaries\\IOS\\") && InTarget.TargetType != TargetRules.TargetType.Game)
						{
							BinaryDir = BinaryDir.Replace(InTarget.TargetType.ToString(), "Game");
						}

						// Get the app bundle's name
						string AppFullName = InTarget.AppName;
						if (InTarget.Configuration != UnrealTargetConfiguration.Development)
						{
							AppFullName += "-" + InTarget.Platform.ToString();
							AppFullName += "-" + InTarget.Configuration.ToString();
						}

						foreach (string BinaryPath in Toolchain.BuiltBinaries)
						{
							if (!BinaryPath.Contains("Dummy"))
							{
								RPCUtilHelper.CopyFile(Toolchain.ConvertPath(BinaryPath), BinaryPath, false);
							}
						}
						Log.TraceInformation("Copied binaries successfully.");
					}
					catch (Exception)
					{
						Log.TraceInformation("Copying binaries back to this device failed.");
					}
				}

				// install the provision
/*				string ProvisionWithPrefix = "../../Engine/Build/IOS/UE4Game.mobileprovision";
				if (File.Exists(BuildPath + "/" + GameName + ".mobileprovision"))
				{
					ProvisionWithPrefix = BuildPath + "/" + GameName + ".mobileprovision";
				}
				else
				{
					if (File.Exists(BuildPath + "/NotForLicensees/" + GameName + ".mobileprovision"))
					{
						ProvisionWithPrefix = BuildPath + "/NotForLicensees/" + GameName + ".mobileprovision";
					}
					else if (!File.Exists(ProvisionWithPrefix))
					{
						ProvisionWithPrefix = "../../Engine/Build/IOS/NotForLicensees/UE4Game.mobileprovision";
					}
				}
				string LibraryDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "/Apple Computer/MobileDevice/Provisioning Profiles/";
				if (File.Exists(ProvisionWithPrefix))
				{
					Directory.CreateDirectory(LibraryDir);
					File.Copy(ProvisionWithPrefix, LibraryDir + GameName + ".mobileprovision", true);
					FileInfo DestFileInfo = new FileInfo(LibraryDir + GameName + ".mobileprovision");
					DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
				}

				// install the distribution provision
				ProvisionWithPrefix = "../../Engine/Build/IOS/UE4Game_Distro.mobileprovision";
				if (File.Exists(BuildPath + "/" + GameName + "_Distro.mobileprovision"))
				{
					ProvisionWithPrefix = BuildPath + "/" + GameName + "_Distro.mobileprovision";
				}
				else
				{
					if (File.Exists(BuildPath + "/NotForLicensees/" + GameName + "_Distro.mobileprovision"))
					{
						ProvisionWithPrefix = BuildPath + "/NotForLicensees/" + GameName + "_Distro.mobileprovision";
					}
					else if (!File.Exists(ProvisionWithPrefix))
					{
						ProvisionWithPrefix = "../../Engine/Build/IOS/NotForLicensees/UE4Game_Distro.mobileprovision";
					}
				}
				if (File.Exists(ProvisionWithPrefix))
				{
					File.Copy(ProvisionWithPrefix, LibraryDir + GameName + "_Distro.mobileprovision", true);
					FileInfo DestFileInfo = new FileInfo(LibraryDir + GameName + "_Distro.mobileprovision");
					DestFileInfo.Attributes = DestFileInfo.Attributes & ~FileAttributes.ReadOnly;
				}*/
			}
			return true;
		}
        public override void ExecuteBuild()
        {
            // Parse the target list
            string[] Targets = ParseParamValues("Target");
            if (Targets.Length == 0)
            {
                throw new AutomationException("No targets specified (eg. -Target=\"UE4Editor Win64 Development\")");
            }

            // Parse the archive path
            string ArchivePath = ParseParamValue("Archive");

            if (ArchivePath != null && (!ArchivePath.StartsWith("//") || ArchivePath.Sum(x => (x == '/')? 1 : 0) < 4))
            {
                throw new AutomationException("Archive path is not a valid depot filename");
            }

            // Prepare the build agenda
            UE4Build.BuildAgenda Agenda = new UE4Build.BuildAgenda();
            foreach (string Target in Targets)
            {
                string[] Tokens = Target.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                UnrealTargetPlatform      Platform;
                UnrealTargetConfiguration Configuration;
                if (Tokens.Length < 3 || !Enum.TryParse(Tokens[1], true, out Platform) || !Enum.TryParse(Tokens[2], true, out Configuration))
                {
                    throw new AutomationException("Invalid target '{0}' - expected <TargetName> <Platform> <Configuration>");
                }

                Agenda.AddTarget(Tokens[0], Platform, Configuration, InAddArgs: String.Join(" ", Tokens.Skip(3)));
            }

            // Build everything
            UE4Build Builder = new UE4Build(this);

            Builder.Build(Agenda, InUpdateVersionFiles: ArchivePath != null);

            // Include the build products for UAT and UBT if required
            if (ParseParam("WithUAT"))
            {
                Builder.AddUATFilesToBuildProducts();
            }
            if (ParseParam("WithUBT"))
            {
                Builder.AddUBTFilesToBuildProducts();
            }

            // Archive the build products
            if (ArchivePath != null)
            {
                // Create an output folder
                string OutputFolder = Path.Combine(CommandUtils.CmdEnv.LocalRoot, "ArchiveForUGS");
                Directory.CreateDirectory(OutputFolder);

                // Create a temp folder for storing stripped PDB files
                string SymbolsFolder = Path.Combine(OutputFolder, "Symbols");
                Directory.CreateDirectory(SymbolsFolder);

                // Get the Windows toolchain
                UEToolChain WindowsToolChain = UEBuildPlatform.GetBuildPlatform(UnrealTargetPlatform.Win64).CreateContext(null).CreateToolChain(CPPTargetPlatform.Win64);

                // Figure out all the files for the archive
                Ionic.Zip.ZipFile Zip = new Ionic.Zip.ZipFile();
                Zip.UseZip64WhenSaving = Ionic.Zip.Zip64Option.Always;
                foreach (string BuildProduct in Builder.BuildProductFiles)
                {
                    if (!File.Exists(BuildProduct))
                    {
                        throw new AutomationException("Missing build product: {0}", BuildProduct);
                    }
                    if (BuildProduct.EndsWith(".pdb", StringComparison.InvariantCultureIgnoreCase))
                    {
                        string StrippedFileName = CommandUtils.MakeRerootedFilePath(BuildProduct, CommandUtils.CmdEnv.LocalRoot, SymbolsFolder);
                        Directory.CreateDirectory(Path.GetDirectoryName(StrippedFileName));
                        WindowsToolChain.StripSymbols(BuildProduct, StrippedFileName);
                        Zip.AddFile(StrippedFileName, Path.GetDirectoryName(CommandUtils.StripBaseDirectory(StrippedFileName, SymbolsFolder)));
                    }
                    else
                    {
                        Zip.AddFile(BuildProduct, Path.GetDirectoryName(CommandUtils.StripBaseDirectory(BuildProduct, CommandUtils.CmdEnv.LocalRoot)));
                    }
                }
                // Create the zip file
                string ZipFileName = Path.Combine(OutputFolder, "Archive.zip");
                Console.WriteLine("Writing {0}...", ZipFileName);
                Zip.Save(ZipFileName);

                // Submit it to Perforce if required
                if (CommandUtils.AllowSubmit)
                {
                    // Delete any existing clientspec for submitting
                    string ClientName = Environment.MachineName + "_BuildForUGS";

                    // Create a brand new one
                    P4ClientInfo Client = new P4ClientInfo();
                    Client.Owner    = CommandUtils.P4Env.User;
                    Client.Host     = Environment.MachineName;
                    Client.Stream   = ArchivePath.Substring(0, ArchivePath.IndexOf('/', ArchivePath.IndexOf('/', 2) + 1));
                    Client.RootPath = Path.Combine(OutputFolder, "Perforce");
                    Client.Name     = ClientName;
                    Client.Options  = P4ClientOption.NoAllWrite | P4ClientOption.NoClobber | P4ClientOption.NoCompress | P4ClientOption.Unlocked | P4ClientOption.NoModTime | P4ClientOption.RmDir;
                    Client.LineEnd  = P4LineEnd.Local;
                    P4.CreateClient(Client, AllowSpew: false);

                    // Create a new P4 connection for this workspace
                    P4Connection SubmitP4 = new P4Connection(Client.Owner, Client.Name, P4Env.P4Port);
                    SubmitP4.Revert("-k //...");

                    // Figure out where the zip file has to go in Perforce
                    P4WhereRecord WhereZipFile = SubmitP4.Where(ArchivePath, false).FirstOrDefault(x => !x.bUnmap && x.Path != null);
                    if (WhereZipFile == null)
                    {
                        throw new AutomationException("Couldn't locate {0} in this workspace");
                    }

                    // Get the latest version of it
                    int NewCL = SubmitP4.CreateChange(Description: String.Format("[CL {0}] Updated binaries", P4Env.Changelist));
                    SubmitP4.Sync(String.Format("-k \"{0}\"", ArchivePath), AllowSpew: false);
                    CommandUtils.CopyFile(ZipFileName, WhereZipFile.Path);
                    SubmitP4.Add(NewCL, String.Format("\"{0}\"", ArchivePath));
                    SubmitP4.Edit(NewCL, String.Format("\"{0}\"", ArchivePath));

                    // Submit it
                    int SubmittedCL;
                    SubmitP4.Submit(NewCL, out SubmittedCL);
                    if (SubmittedCL <= 0)
                    {
                        throw new AutomationException("Submit failed.");
                    }
                    Console.WriteLine("Submitted in changelist {0}", SubmittedCL);
                }
            }
        }