// Copyright Epic Games, Inc. All Rights Reserved. using System.Collections.Generic; using System.Threading.Tasks; using System.Xml; using EpicGames.Core; using Microsoft.Extensions.Logging; using UnrealBuildBase; namespace AutomationTool.Tasks { /// /// Parameters for a Git-Checkout task /// public class GitCloneTaskParameters { /// /// Directory for the repository /// [TaskParameter] public string Dir { get; set; } /// /// The remote to add /// [TaskParameter(Optional = true)] public string Remote { get; set; } /// /// The branch to check out on the remote /// [TaskParameter] public string Branch { get; set; } /// /// Configuration file for the repo. This can be used to set up a remote to be fetched and/or provide credentials. /// [TaskParameter(Optional = true)] public string ConfigFile { get; set; } } /// /// Clones a Git repository into a local path. /// [TaskElement("Git-Clone", typeof(GitCloneTaskParameters))] public class GitCloneTask : BgTaskImpl { /// /// Parameters for this task /// readonly GitCloneTaskParameters _parameters; /// /// Construct a Git task /// /// Parameters for the task public GitCloneTask(GitCloneTaskParameters parameters) { _parameters = parameters; } /// /// ExecuteAsync the task. /// /// Information about the current job /// Set of build products produced by this node. /// Mapping from tag names to the set of files they include public override async Task ExecuteAsync(JobContext job, HashSet buildProducts, Dictionary> tagNameToFileSet) { FileReference gitExe = CommandUtils.FindToolInPath("git"); if (gitExe == null) { throw new AutomationException("Unable to find path to Git. Check you have it installed, and it is on your PATH."); } DirectoryReference dir = ResolveDirectory(_parameters.Dir); Logger.LogInformation("Cloning Git repository into {Dir}", _parameters.Dir); using (LogIndentScope scope = new LogIndentScope(" ")) { DirectoryReference gitDir = DirectoryReference.Combine(dir, ".git"); if (!FileReference.Exists(FileReference.Combine(gitDir, "HEAD"))) { await RunGit(gitExe, $"init \"{dir}\"", Unreal.RootDirectory); } if (_parameters.ConfigFile != null) { CommandUtils.CopyFile(_parameters.ConfigFile, FileReference.Combine(gitDir, "config").FullName); } if (_parameters.Remote != null) { await RunGit(gitExe, $"remote add origin {_parameters.Remote}", dir); } await RunGit(gitExe, "clean -dxf", dir); await RunGit(gitExe, "fetch --all", dir); await RunGit(gitExe, $"reset --hard {_parameters.Branch}", dir); } } /// /// Runs a git command /// /// /// /// static Task RunGit(FileReference toolFile, string arguments, DirectoryReference workingDir) { IProcessResult result = CommandUtils.Run(toolFile.FullName, arguments, WorkingDir: workingDir.FullName); if (result.ExitCode != 0) { throw new AutomationException("Git terminated with an exit code indicating an error ({0})", result.ExitCode); } return Task.CompletedTask; } /// /// Output this task out to an XML writer. /// public override void Write(XmlWriter writer) { Write(writer, _parameters); } /// /// Find all the tags which are used as inputs to this task /// /// The tag names which are read by this task public override IEnumerable FindConsumedTagNames() { yield break; } /// /// Find all the tags which are modified by this task /// /// The tag names which are modified by this task public override IEnumerable FindProducedTagNames() { yield break; } } }