2019-12-26 23:01:54 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2016-12-08 08:52:44 -05:00
2021-11-09 12:36:25 -05:00
using EpicGames.BuildGraph ;
2016-12-08 08:52:44 -05:00
using System ;
2016-05-10 08:49:41 -04:00
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
2021-06-10 10:32:10 -04:00
using System.Text.RegularExpressions ;
2016-05-10 08:49:41 -04:00
using System.Threading.Tasks ;
using System.Xml ;
2020-12-21 23:07:37 -04:00
using EpicGames.Core ;
2021-06-11 18:20:44 -04:00
using UnrealBuildBase ;
2016-05-10 08:49:41 -04:00
using UnrealBuildTool ;
namespace AutomationTool.Tasks
{
/// <summary>
/// Parameters for the submit task
/// </summary>
public class SubmitTaskParameters
{
/// <summary>
2019-10-11 16:59:16 -04:00
/// The description for the submitted changelist.
2016-05-10 08:49:41 -04:00
/// </summary>
[TaskParameter]
public string Description ;
/// <summary>
2019-10-11 16:59:16 -04:00
/// The files to submit.
2016-05-10 08:49:41 -04:00
/// </summary>
2016-08-18 10:28:43 -04:00
[TaskParameter(ValidationType = TaskParameterValidationType.FileSpec)]
2016-05-10 08:49:41 -04:00
public string Files ;
/// <summary>
2019-10-11 16:59:16 -04:00
/// The Perforce file type for the submitted files (for example, binary+FS32).
2016-05-10 08:49:41 -04:00
/// </summary>
[TaskParameter(Optional = true)]
public string FileType ;
/// <summary>
2016-08-18 10:28:43 -04:00
/// The workspace name. If specified, a new workspace will be created using the given stream and root directory to submit the files. If not, the current workspace will be used.
2016-05-10 08:49:41 -04:00
/// </summary>
[TaskParameter(Optional=true)]
public string Workspace ;
/// <summary>
2019-10-11 16:59:16 -04:00
/// The stream for the workspace -- defaults to the current stream. Ignored unless the Workspace attribute is also specified.
2016-05-10 08:49:41 -04:00
/// </summary>
[TaskParameter(Optional = true)]
public string Stream ;
2021-06-10 10:32:10 -04:00
/// <summary>
/// Branch for the workspace (legacy P4 depot path). May not be used in conjunction with Stream.
/// </summary>
[TaskParameter(Optional = true)]
public string Branch ;
2016-05-10 08:49:41 -04:00
/// <summary>
/// Root directory for the stream. If not specified, defaults to the current root directory.
/// </summary>
2018-09-27 16:51:24 -04:00
[TaskParameter(Optional = true)]
public DirectoryReference RootDir ;
2017-03-14 15:48:33 -04:00
/// <summary>
2019-10-11 16:59:16 -04:00
/// Whether to revert unchanged files before attempting to submit.
2017-03-14 15:48:33 -04:00
/// </summary>
[TaskParameter(Optional = true)]
public bool RevertUnchanged ;
2019-01-14 12:11:24 -05:00
/// <summary>
2019-10-11 16:59:16 -04:00
/// Force the submit to happen -- even if a resolve is needed (always accept current version).
2019-01-14 12:11:24 -05:00
/// </summary>
[TaskParameter(Optional = true)]
public bool Force ;
2020-10-15 11:51:57 -04:00
/// <summary>
/// Allow verbose P4 output (spew).
/// </summary>
2020-10-15 12:12:20 -04:00
[TaskParameter(Optional = true)]
2020-10-15 11:51:57 -04:00
public bool P4Verbose ;
2016-05-10 08:49:41 -04:00
}
/// <summary>
2016-08-18 10:28:43 -04:00
/// Creates a new changelist and submits a set of files to a Perforce stream.
2016-05-10 08:49:41 -04:00
/// </summary>
[TaskElement("Submit", typeof(SubmitTaskParameters))]
2021-12-10 15:36:47 -05:00
public class SubmitTask : BgTaskImpl
2016-05-10 08:49:41 -04:00
{
/// <summary>
/// Parameters for the task
/// </summary>
SubmitTaskParameters Parameters ;
/// <summary>
/// Construct a version task
/// </summary>
/// <param name="InParameters">Parameters for this task</param>
public SubmitTask ( SubmitTaskParameters InParameters )
{
Parameters = InParameters ;
}
/// <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>
2021-12-10 15:36:47 -05:00
public override Task ExecuteAsync ( JobContext Job , HashSet < FileReference > BuildProducts , Dictionary < string , HashSet < FileReference > > TagNameToFileSet )
2016-05-10 08:49:41 -04:00
{
2021-06-11 18:20:44 -04:00
HashSet < FileReference > Files = ResolveFilespec ( Unreal . RootDirectory , Parameters . Files , TagNameToFileSet ) ;
2018-04-26 14:11:04 -04:00
if ( Files . Count = = 0 )
{
Log . TraceInformation ( "No files to submit." ) ;
}
else if ( ! CommandUtils . AllowSubmit )
{
Log . TraceWarning ( "Submitting to Perforce is disabled by default. Run with the -submit argument to allow." ) ;
}
else
2016-05-10 08:49:41 -04:00
{
// Get the connection that we're going to submit with
P4Connection SubmitP4 = CommandUtils . P4 ;
if ( Parameters . Workspace ! = null )
{
// Create a brand new workspace
P4ClientInfo Client = new P4ClientInfo ( ) ;
2017-07-21 12:42:36 -04:00
Client . Owner = CommandUtils . P4Env . User ;
2021-03-11 23:17:52 -04:00
Client . Host = Environment . MachineName ;
2021-06-11 18:20:44 -04:00
Client . RootPath = Parameters . RootDir . FullName ? ? Unreal . RootDirectory . FullName ;
2021-06-10 10:32:10 -04:00
Client . Name = $"{Parameters.Workspace}_{Regex.Replace(Client.Host, " [ ^ a - zA - Z0 - 9 ] ", " - ")}_{ContentHash.MD5((CommandUtils.P4Env.ServerAndPort ?? " ").ToUpperInvariant())}" ;
2016-05-10 08:49:41 -04:00
Client . Options = P4ClientOption . NoAllWrite | P4ClientOption . Clobber | P4ClientOption . NoCompress | P4ClientOption . Unlocked | P4ClientOption . NoModTime | P4ClientOption . RmDir ;
Client . LineEnd = P4LineEnd . Local ;
2021-06-10 21:40:41 -04:00
if ( ! String . IsNullOrEmpty ( Parameters . Branch ) )
2021-06-10 10:32:10 -04:00
{
Client . View . Add ( new KeyValuePair < string , string > ( $"{Parameters.Branch}/..." , $"/..." ) ) ;
}
else
{
Client . Stream = Parameters . Stream ? ? CommandUtils . P4Env . Branch ;
}
2020-10-15 11:51:57 -04:00
CommandUtils . P4 . CreateClient ( Client , AllowSpew : Parameters . P4Verbose ) ;
2016-05-10 08:49:41 -04:00
// Create a new connection for it
SubmitP4 = new P4Connection ( Client . Owner , Client . Name ) ;
}
// Get the latest version of it
2018-05-23 21:04:31 -04:00
int NewCL = SubmitP4 . CreateChange ( Description : Parameters . Description . Replace ( "\\n" , "\n" ) ) ;
2016-05-10 08:49:41 -04:00
foreach ( FileReference File in Files )
{
2020-10-15 11:51:57 -04:00
SubmitP4 . Revert ( String . Format ( "-k \"{0}\"" , File . FullName ) , AllowSpew : Parameters . P4Verbose ) ;
SubmitP4 . Sync ( String . Format ( "-k \"{0}\"" , File . FullName ) , AllowSpew : Parameters . P4Verbose ) ;
2016-05-10 08:49:41 -04:00
SubmitP4 . Add ( NewCL , String . Format ( "\"{0}\"" , File . FullName ) ) ;
2020-10-15 11:51:57 -04:00
SubmitP4 . Edit ( NewCL , String . Format ( "\"{0}\"" , File . FullName ) , AllowSpew : Parameters . P4Verbose ) ;
2016-05-10 08:49:41 -04:00
if ( Parameters . FileType ! = null )
{
2020-10-15 11:51:57 -04:00
SubmitP4 . P4 ( String . Format ( "reopen -t \"{0}\" \"{1}\"" , Parameters . FileType , File . FullName ) , AllowSpew : Parameters . P4Verbose ) ;
2016-05-10 08:49:41 -04:00
}
}
2017-03-14 15:48:33 -04:00
// Revert any unchanged files
if ( Parameters . RevertUnchanged )
{
SubmitP4 . RevertUnchanged ( NewCL ) ;
if ( SubmitP4 . TryDeleteEmptyChange ( NewCL ) )
{
2018-08-14 18:32:34 -04:00
CommandUtils . LogInformation ( "No files to submit; ignored." ) ;
2021-12-10 15:36:47 -05:00
return Task . CompletedTask ;
2017-03-14 15:48:33 -04:00
}
}
2016-05-10 08:49:41 -04:00
// Submit it
int SubmittedCL ;
2019-01-14 12:11:24 -05:00
SubmitP4 . Submit ( NewCL , out SubmittedCL , Force : Parameters . Force ) ;
2016-05-10 08:49:41 -04:00
if ( SubmittedCL < = 0 )
{
throw new AutomationException ( "Submit failed." ) ;
}
2018-08-14 18:32:34 -04:00
CommandUtils . LogInformation ( "Submitted in changelist {0}" , SubmittedCL ) ;
2016-05-10 08:49:41 -04:00
}
2021-12-10 15:36:47 -05:00
return Task . CompletedTask ;
2016-05-10 08:49:41 -04:00
}
/// <summary>
/// Output this task out to an XML writer.
/// </summary>
public override void Write ( XmlWriter Writer )
{
Write ( Writer , Parameters ) ;
}
2016-06-21 09:17:49 -04:00
/// <summary>
/// Find all the tags which are used as inputs to this task
/// </summary>
/// <returns>The tag names which are read by this task</returns>
public override IEnumerable < string > FindConsumedTagNames ( )
{
return FindTagNamesFromFilespec ( Parameters . Files ) ;
}
/// <summary>
/// Find all the tags which are modified by this task
/// </summary>
/// <returns>The tag names which are modified by this task</returns>
public override IEnumerable < string > FindProducedTagNames ( )
{
yield break ;
}
2016-05-10 08:49:41 -04:00
}
}