2016-03-16 21:16:51 -04:00
using AutomationTool ;
Copying //UE4/Orion-Staging to //UE4/Main (Origin: //Orion/Dev-General @ 2904087)
==========================
MAJOR FEATURES + CHANGES
==========================
#lockdown Nick.Penwarden
Change 2903938 on 2016/03/10 by Frank.Gigliotti
Added an instance ID to FAnimMontageInstance
#CodeReview Laurent.Delayen
#RB Laurent.Delayen
#Tests PIE
Change 2903745 on 2016/03/10 by Wes.Hunt
Update Oodle TPS
#rb none
#tests none
#codereview:john.pollard
Change 2903689 on 2016/03/10 by Uriel.Doyon
New "LogHeroMaterials" console command, displaying the current state of materials and textures on the character hero.
#rb marcus.wasmer
#codereview marcus.wassmer
#tests editor, playing PC games, trying the new command
Change 2903669 on 2016/03/10 by Aaron.McLeran
OR-17180 Make stat soundcues and stat soundwaves NOT display zero volume sounds
- Change only effects debug stat commands for audio guys
#rb none
#tests played paragon with new debug stat commands, confirms doesn't show zero-volume sounds
Change 2903625 on 2016/03/10 by John.Pollard
XB1 Oodle SDK
#rb none
#tests none
#codereview Jeff.Campeau
Change 2903577 on 2016/03/10 by Ben.Marsh
Remaking latest build scripts from //UE4/Main @ 2900980.
Change 2903560 on 2016/03/10 by Ben.Marsh
Initial version of BuildGraph scripts - used to create build processes in UE4 which can be run locally or in parallel across a build farm (assuming synchronization and resource allocation implemented by a separate system). Intended to supersede GUBP.
Build graphs are declared using an XML script using syntax similar to MSBuild, ANT or NAnt, and consist of the following components:
* Tasks: Building blocks which can be executed as part of the build process. Many predefined tasks are provided (<Cook>, <Compile>, <Copy>, <Stage>, <Log>, <PakFile>, etc...), and additional tasks may be added be declaring classes derived from AutomationTool.CustomTask in other UAT modules.
* Nodes: A named sequence of tasks which is executed to produce outputs. Nodes may have input dependencies on other nodes before they can be executed. Declared with the <Node> element in scripts.
* Agent Groups: A set of nodes nodes which is executed on the same machine if running as part of a build system. Has no effect when building locally. Declared with the <Group> element in scripts.
* Triggers: Container for groups which should only be executed when explicitly triggered (using the -Trigger=<Name> or -SkipTriggers command line argument). Declared with the <Trigger> element in scripts.
* Notifiers: Specifies email recipients for failures in one or more nodes, whether they should receive notifications on warnings, and so on.
Properties can be passed in to a script on the command line, or set procedurally with the <Property Name="Foo" Value="Bar"/> syntax. Properties referenced with the $(Property Name) notation are valid within all strings, and will be expanded as macros when the script is read. If a property name is not set explicitly, it defaults to the contents of an environment variable with the same name.
Local properties, which only affect the scope of the containing XML element (node, group, etc...) are declared with the <Local Name="Foo" Value="Bar"/> element, and will override a similarly named global property for the local property's scope.
Any elements can be conditionally defined via the "If" attribute, and are largely identical to MSBuild conditions. Literals in conditions may be quoted with single (') or double (") quotes, or an unquoted sequence of letters, digits and underscore characters. All literals are considered identical regardless of how they are declared, and are considered case-insensitive for comparisons (so true equals 'True', equals "TRUE"). Available operators are "==", "!=", "And", "Or", "!", "(...)", "Exists(...)" and "HasTrailingSlash(...)". A full grammar is written up in Condition.cs.
File manipulation is done using wildcards and tags. Any attribute that accepts a list of files may consist of: a Perforce-style wildcard (matching any number of "...", "*" and "?" patterns in any location), a full path name, or a reference to a tagged collection of files, denoted by prefixing with a '#' character. Files may be added to a tag set using the <Tag> Task, which also allows performing set union/difference style operations. Each node can declare multiple outputs in the form of a list of named tags, which other nodes can then depend on.
Build graphs may be executed in parallel as part build system. To do so, the initial graph configuration is generated by running with the -Export=<Filename> argument (producing a JSON file listing the nodes and dependencies to execute). Each participating agent should be synced to the same changelist, and UAT should be re-run with the appropriate -Node=<Name> argument. Outputs from different nodes are transferred between agents via shared storage, typically a network share, the path to which can be specified on the command line using the -SharedStorageDir=<Path> argument. Note that the allocation of machines, and coordination between them, is assumed to be managed by an external system.
A schema for the known set of tasks can be generated by running UAT with the "-Schema=<FileName>" option. Generating a schema and referencing it from a BuildGraph script allows Visual Studio to validate and auto-complete elements as you type.
#rb none
#codereview Marc.Audy, Wes.Hunt, Matthew.Griffin, Richard.Fawcett
#tests local only so far, but not part of any build process yet
Change 2903539 on 2016/03/10 by John.Pollard
Improve replay playback debugging of character movement
#rb none
#tests replays
Change 2903526 on 2016/03/10 by Ben.Marsh
Remake changes from //UE4/Main without integration history, to add support for BuildGraph tasks.
#rb none
#tests none
Change 2903512 on 2016/03/10 by Dan.Youhon
Modify minimum Duration values for JumpForce and MoveToForce ability tasks so that having minimum Duration values doesn't trigger check()s
#rb None
#tests Compiles
Change 2903474 on 2016/03/10 by Marc.Audy
Fix crash if ChildActor is null
#rb None
#tests None
Change 2903314 on 2016/03/10 by Marc.Audy
Fix ParentComponent not being persisted and fixup content that was saved in the window it was broken
#rb James.Golding
#tests Selection of child actors works as expected
#jira UE-28201
Change 2903298 on 2016/03/10 by Simon.Tovey
Disabling the trails optimization.
#tests none
#rb none
#codereview Olaf.Piesche
Change 2903124 on 2016/03/10 by Robert.Manuszewski
Small refactor to pak signing to help with exe protection
#rb none
#tests none
[CL 2907678 by Andrew Grant in Main branch]
2016-03-13 18:53:13 -04:00
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
using System.Xml ;
using UnrealBuildTool ;
namespace BuildGraph.Tasks
{
/// <summary>
/// Parameters for a task that compiles a MsBuild project
/// </summary>
public class MsBuildTaskParameters
{
/// <summary>
/// The MsBuild project file to be compile. More than one project file can be specified by separating with semicolons.
/// </summary>
[TaskParameter]
public string Project ;
/// <summary>
/// The configuration to compile
/// </summary>
[TaskParameter(Optional = true)]
public string Configuration ;
/// <summary>
/// The platform to compile
/// </summary>
[TaskParameter(Optional = true)]
public string Platform ;
/// <summary>
/// Additional options to pass to the compiler
/// </summary>
[TaskParameter(Optional = true)]
public string Arguments ;
/// <summary>
/// Directory containing output files
/// </summary>
[TaskParameter(Optional = true)]
public string OutputDir ;
/// <summary>
/// Patterns for output files
/// </summary>
[TaskParameter(Optional = true)]
public string OutputFiles ;
/// <summary>
/// Only enumerate build products; do not actually compile the projects.
/// </summary>
[TaskParameter(Optional = true)]
public bool EnumerateOnly ;
}
/// <summary>
/// Compile a MSBuild project file
/// </summary>
[TaskElement("MsBuild", typeof(MsBuildTaskParameters))]
public class MsBuildTask : CustomTask
{
/// <summary>
/// Parameters for the task
/// </summary>
MsBuildTaskParameters Parameters ;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="InParameters">Parameters for this task</param>
public MsBuildTask ( MsBuildTaskParameters 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>
/// <returns>True if the task succeeded</returns>
public override bool Execute ( JobContext Job , HashSet < FileReference > BuildProducts , Dictionary < string , HashSet < FileReference > > TagNameToFileSet )
{
// Get the project file
2016-03-21 21:11:39 -04:00
HashSet < FileReference > ProjectFiles = ResolveFilespec ( CommandUtils . RootDirectory , Parameters . Project , TagNameToFileSet ) ;
Copying //UE4/Orion-Staging to //UE4/Main (Origin: //Orion/Dev-General @ 2904087)
==========================
MAJOR FEATURES + CHANGES
==========================
#lockdown Nick.Penwarden
Change 2903938 on 2016/03/10 by Frank.Gigliotti
Added an instance ID to FAnimMontageInstance
#CodeReview Laurent.Delayen
#RB Laurent.Delayen
#Tests PIE
Change 2903745 on 2016/03/10 by Wes.Hunt
Update Oodle TPS
#rb none
#tests none
#codereview:john.pollard
Change 2903689 on 2016/03/10 by Uriel.Doyon
New "LogHeroMaterials" console command, displaying the current state of materials and textures on the character hero.
#rb marcus.wasmer
#codereview marcus.wassmer
#tests editor, playing PC games, trying the new command
Change 2903669 on 2016/03/10 by Aaron.McLeran
OR-17180 Make stat soundcues and stat soundwaves NOT display zero volume sounds
- Change only effects debug stat commands for audio guys
#rb none
#tests played paragon with new debug stat commands, confirms doesn't show zero-volume sounds
Change 2903625 on 2016/03/10 by John.Pollard
XB1 Oodle SDK
#rb none
#tests none
#codereview Jeff.Campeau
Change 2903577 on 2016/03/10 by Ben.Marsh
Remaking latest build scripts from //UE4/Main @ 2900980.
Change 2903560 on 2016/03/10 by Ben.Marsh
Initial version of BuildGraph scripts - used to create build processes in UE4 which can be run locally or in parallel across a build farm (assuming synchronization and resource allocation implemented by a separate system). Intended to supersede GUBP.
Build graphs are declared using an XML script using syntax similar to MSBuild, ANT or NAnt, and consist of the following components:
* Tasks: Building blocks which can be executed as part of the build process. Many predefined tasks are provided (<Cook>, <Compile>, <Copy>, <Stage>, <Log>, <PakFile>, etc...), and additional tasks may be added be declaring classes derived from AutomationTool.CustomTask in other UAT modules.
* Nodes: A named sequence of tasks which is executed to produce outputs. Nodes may have input dependencies on other nodes before they can be executed. Declared with the <Node> element in scripts.
* Agent Groups: A set of nodes nodes which is executed on the same machine if running as part of a build system. Has no effect when building locally. Declared with the <Group> element in scripts.
* Triggers: Container for groups which should only be executed when explicitly triggered (using the -Trigger=<Name> or -SkipTriggers command line argument). Declared with the <Trigger> element in scripts.
* Notifiers: Specifies email recipients for failures in one or more nodes, whether they should receive notifications on warnings, and so on.
Properties can be passed in to a script on the command line, or set procedurally with the <Property Name="Foo" Value="Bar"/> syntax. Properties referenced with the $(Property Name) notation are valid within all strings, and will be expanded as macros when the script is read. If a property name is not set explicitly, it defaults to the contents of an environment variable with the same name.
Local properties, which only affect the scope of the containing XML element (node, group, etc...) are declared with the <Local Name="Foo" Value="Bar"/> element, and will override a similarly named global property for the local property's scope.
Any elements can be conditionally defined via the "If" attribute, and are largely identical to MSBuild conditions. Literals in conditions may be quoted with single (') or double (") quotes, or an unquoted sequence of letters, digits and underscore characters. All literals are considered identical regardless of how they are declared, and are considered case-insensitive for comparisons (so true equals 'True', equals "TRUE"). Available operators are "==", "!=", "And", "Or", "!", "(...)", "Exists(...)" and "HasTrailingSlash(...)". A full grammar is written up in Condition.cs.
File manipulation is done using wildcards and tags. Any attribute that accepts a list of files may consist of: a Perforce-style wildcard (matching any number of "...", "*" and "?" patterns in any location), a full path name, or a reference to a tagged collection of files, denoted by prefixing with a '#' character. Files may be added to a tag set using the <Tag> Task, which also allows performing set union/difference style operations. Each node can declare multiple outputs in the form of a list of named tags, which other nodes can then depend on.
Build graphs may be executed in parallel as part build system. To do so, the initial graph configuration is generated by running with the -Export=<Filename> argument (producing a JSON file listing the nodes and dependencies to execute). Each participating agent should be synced to the same changelist, and UAT should be re-run with the appropriate -Node=<Name> argument. Outputs from different nodes are transferred between agents via shared storage, typically a network share, the path to which can be specified on the command line using the -SharedStorageDir=<Path> argument. Note that the allocation of machines, and coordination between them, is assumed to be managed by an external system.
A schema for the known set of tasks can be generated by running UAT with the "-Schema=<FileName>" option. Generating a schema and referencing it from a BuildGraph script allows Visual Studio to validate and auto-complete elements as you type.
#rb none
#codereview Marc.Audy, Wes.Hunt, Matthew.Griffin, Richard.Fawcett
#tests local only so far, but not part of any build process yet
Change 2903539 on 2016/03/10 by John.Pollard
Improve replay playback debugging of character movement
#rb none
#tests replays
Change 2903526 on 2016/03/10 by Ben.Marsh
Remake changes from //UE4/Main without integration history, to add support for BuildGraph tasks.
#rb none
#tests none
Change 2903512 on 2016/03/10 by Dan.Youhon
Modify minimum Duration values for JumpForce and MoveToForce ability tasks so that having minimum Duration values doesn't trigger check()s
#rb None
#tests Compiles
Change 2903474 on 2016/03/10 by Marc.Audy
Fix crash if ChildActor is null
#rb None
#tests None
Change 2903314 on 2016/03/10 by Marc.Audy
Fix ParentComponent not being persisted and fixup content that was saved in the window it was broken
#rb James.Golding
#tests Selection of child actors works as expected
#jira UE-28201
Change 2903298 on 2016/03/10 by Simon.Tovey
Disabling the trails optimization.
#tests none
#rb none
#codereview Olaf.Piesche
Change 2903124 on 2016/03/10 by Robert.Manuszewski
Small refactor to pak signing to help with exe protection
#rb none
#tests none
[CL 2907678 by Andrew Grant in Main branch]
2016-03-13 18:53:13 -04:00
foreach ( FileReference ProjectFile in ProjectFiles )
{
if ( ! ProjectFile . Exists ( ) )
{
CommandUtils . LogError ( "Couldn't find project file '{0}'" , ProjectFile . FullName ) ;
return false ;
}
}
// Get the default properties
Dictionary < string , string > Properties = new Dictionary < string , string > ( StringComparer . InvariantCultureIgnoreCase ) ;
if ( ! String . IsNullOrEmpty ( Parameters . Platform ) )
{
Properties [ "Platform" ] = Parameters . Platform ;
}
if ( ! String . IsNullOrEmpty ( Parameters . Configuration ) )
{
Properties [ "Configuration" ] = Parameters . Configuration ;
}
// Build the arguments and run the build
if ( ! Parameters . EnumerateOnly )
{
List < string > Arguments = new List < string > ( ) ;
foreach ( KeyValuePair < string , string > PropertyPair in Properties )
{
Arguments . Add ( String . Format ( "/property:{0}={1}" , CommandUtils . MakePathSafeToUseWithCommandLine ( PropertyPair . Key ) , CommandUtils . MakePathSafeToUseWithCommandLine ( PropertyPair . Value ) ) ) ;
}
if ( ! String . IsNullOrEmpty ( Parameters . Arguments ) )
{
Arguments . Add ( Parameters . Arguments ) ;
}
foreach ( FileReference ProjectFile in ProjectFiles )
{
CommandUtils . MsBuild ( CommandUtils . CmdEnv , ProjectFile . FullName , String . Join ( " " , Arguments ) , null ) ;
}
}
// Try to figure out the output files
HashSet < FileReference > ProjectBuildProducts ;
if ( ! FindBuildProducts ( ProjectFiles , Properties , out ProjectBuildProducts ) )
{
return false ;
}
// Merge them into the standard set of build products
BuildProducts . UnionWith ( ProjectBuildProducts ) ;
return true ;
}
/// <summary>
/// Find all the build products created by compiling the given project file
/// </summary>
/// <param name="ProjectFile">Initial project file to read. All referenced projects will also be read.</param>
/// <param name="InitialProperties">Mapping of property name to value</param>
/// <param name="OutBuildProducts">Receives a set of build products on success</param>
/// <returns>True if the build products were found, false otherwise.</returns>
static bool FindBuildProducts ( HashSet < FileReference > ProjectFiles , Dictionary < string , string > InitialProperties , out HashSet < FileReference > OutBuildProducts )
{
// Read all the project information into a dictionary
Dictionary < FileReference , MsBuildProjectInfo > FileToProjectInfo = new Dictionary < FileReference , MsBuildProjectInfo > ( ) ;
foreach ( FileReference ProjectFile in ProjectFiles )
{
if ( ! ReadProjectsRecursively ( ProjectFile , InitialProperties , FileToProjectInfo ) )
{
OutBuildProducts = null ;
return false ;
}
}
// Find all the build products
HashSet < FileReference > BuildProducts = new HashSet < FileReference > ( ) ;
foreach ( KeyValuePair < FileReference , MsBuildProjectInfo > Pair in FileToProjectInfo )
{
MsBuildProjectInfo ProjectInfo = Pair . Value ;
// Add the standard build products
DirectoryReference OutputDir = ProjectInfo . GetOutputDir ( Pair . Key . Directory ) ;
ProjectInfo . AddBuildProducts ( OutputDir , BuildProducts ) ;
// Add the referenced assemblies
foreach ( FileReference OtherAssembly in ProjectInfo . References . Where ( x = > x . Value ) . Select ( x = > x . Key ) )
{
FileReference OutputFile = FileReference . Combine ( OutputDir , OtherAssembly . GetFileName ( ) ) ;
BuildProducts . Add ( OutputFile ) ;
FileReference SymbolFile = OtherAssembly . ChangeExtension ( ".pdb" ) ;
if ( SymbolFile . Exists ( ) )
{
BuildProducts . Add ( OutputFile . ChangeExtension ( ".pdb" ) ) ;
}
}
// Add build products from all the referenced projects. MSBuild only copy the directly referenced build products, not recursive references or other assemblies.
foreach ( MsBuildProjectInfo OtherProjectInfo in ProjectInfo . ProjectReferences . Where ( x = > x . Value ) . Select ( x = > FileToProjectInfo [ x . Key ] ) )
{
OtherProjectInfo . AddBuildProducts ( OutputDir , BuildProducts ) ;
}
}
// Update the output set
OutBuildProducts = BuildProducts ;
return true ;
}
/// <summary>
/// Read a project file, plus all the project files it references.
/// </summary>
/// <param name="File">Project file to read</param>
/// <param name="InitialProperties">Mapping of property name to value for the initial project</param>
/// <param name="FileToProjectInfo"></param>
/// <returns>True if the projects were read correctly, false (and prints an error to the log) if not</returns>
static bool ReadProjectsRecursively ( FileReference File , Dictionary < string , string > InitialProperties , Dictionary < FileReference , MsBuildProjectInfo > FileToProjectInfo )
{
// Early out if we've already read this project, return succes
if ( FileToProjectInfo . ContainsKey ( File ) )
{
return true ;
}
// Try to read this project
MsBuildProjectInfo ProjectInfo ;
if ( ! MsBuildProjectInfo . TryRead ( File , InitialProperties , out ProjectInfo ) )
{
CommandUtils . LogError ( "Couldn't read project '{0}'" , File . FullName ) ;
return false ;
}
// Add it to the project lookup, and try to read all the projects it references
FileToProjectInfo . Add ( File , ProjectInfo ) ;
return ProjectInfo . ProjectReferences . Keys . All ( x = > ReadProjectsRecursively ( x , new Dictionary < string , string > ( ) , FileToProjectInfo ) ) ;
}
}
/// <summary>
/// Basic information from a preprocessed project file. Supports reading a project file, expanding simple conditions in it, parsing property values, assembly references and references to other projects.
/// </summary>
class MsBuildProjectInfo
{
/// <summary>
/// Evaluated properties from the project file
/// </summary>
public Dictionary < string , string > Properties ;
/// <summary>
/// Mapping of referenced assemblies to their 'CopyLocal' (aka 'Private') setting.
/// </summary>
public Dictionary < FileReference , bool > References = new Dictionary < FileReference , bool > ( ) ;
/// <summary>
/// Mapping of referenced projects to their 'CopyLocal' (aka 'Private') setting.
/// </summary>
public Dictionary < FileReference , bool > ProjectReferences = new Dictionary < FileReference , bool > ( ) ;
/// <summary>
/// Constructor
/// </summary>
/// <param name="InProperties">Initial mapping of property names to values</param>
MsBuildProjectInfo ( Dictionary < string , string > InProperties )
{
Properties = new Dictionary < string , string > ( InProperties ) ;
}
/// <summary>
/// Resolve the project's output directory
/// </summary>
/// <param name="BaseDirectory">Base directory to resolve relative paths to</param>
/// <returns>The configured output directory</returns>
public DirectoryReference GetOutputDir ( DirectoryReference BaseDirectory )
{
string OutputPath ;
if ( Properties . TryGetValue ( "OutputPath" , out OutputPath ) )
{
return DirectoryReference . Combine ( BaseDirectory , OutputPath ) ;
}
else
{
return BaseDirectory ;
}
}
/// <summary>
/// Adds build products from the project to the given set.
/// </summary>
/// <param name="OutputDir">Output directory for the build products. May be different to the project's output directory in the case that we're copying local to another project.</param>
/// <param name="BuildProducts">Set to receive the list of build products</param>
public bool AddBuildProducts ( DirectoryReference OutputDir , HashSet < FileReference > BuildProducts )
{
string OutputType , AssemblyName ;
if ( Properties . TryGetValue ( "OutputType" , out OutputType ) & & Properties . TryGetValue ( "AssemblyName" , out AssemblyName ) )
{
switch ( OutputType )
{
case "Exe" :
BuildProducts . Add ( FileReference . Combine ( OutputDir , AssemblyName + ".exe" ) ) ;
BuildProducts . Add ( FileReference . Combine ( OutputDir , AssemblyName + ".pdb" ) ) ;
return true ;
case "Library" :
BuildProducts . Add ( FileReference . Combine ( OutputDir , AssemblyName + ".dll" ) ) ;
BuildProducts . Add ( FileReference . Combine ( OutputDir , AssemblyName + ".pdb" ) ) ;
return true ;
}
}
return false ;
}
/// <summary>
/// Attempts to read project information for the given file.
/// </summary>
/// <param name="File">The project file to read</param>
/// <param name="Properties">Initial set of property values</param>
/// <param name="OutProjectInfo">If successful, the parsed project info</param>
/// <returns>True if the project was read successfully, false otherwise</returns>
public static bool TryRead ( FileReference File , Dictionary < string , string > Properties , out MsBuildProjectInfo OutProjectInfo )
{
// Read the project file
XmlDocument Document = new XmlDocument ( ) ;
Document . Load ( File . FullName ) ;
// Check the root element is the right type
2016-03-16 21:16:51 -04:00
// HashSet<FileReference> ProjectBuildProducts = new HashSet<FileReference>();
Copying //UE4/Orion-Staging to //UE4/Main (Origin: //Orion/Dev-General @ 2904087)
==========================
MAJOR FEATURES + CHANGES
==========================
#lockdown Nick.Penwarden
Change 2903938 on 2016/03/10 by Frank.Gigliotti
Added an instance ID to FAnimMontageInstance
#CodeReview Laurent.Delayen
#RB Laurent.Delayen
#Tests PIE
Change 2903745 on 2016/03/10 by Wes.Hunt
Update Oodle TPS
#rb none
#tests none
#codereview:john.pollard
Change 2903689 on 2016/03/10 by Uriel.Doyon
New "LogHeroMaterials" console command, displaying the current state of materials and textures on the character hero.
#rb marcus.wasmer
#codereview marcus.wassmer
#tests editor, playing PC games, trying the new command
Change 2903669 on 2016/03/10 by Aaron.McLeran
OR-17180 Make stat soundcues and stat soundwaves NOT display zero volume sounds
- Change only effects debug stat commands for audio guys
#rb none
#tests played paragon with new debug stat commands, confirms doesn't show zero-volume sounds
Change 2903625 on 2016/03/10 by John.Pollard
XB1 Oodle SDK
#rb none
#tests none
#codereview Jeff.Campeau
Change 2903577 on 2016/03/10 by Ben.Marsh
Remaking latest build scripts from //UE4/Main @ 2900980.
Change 2903560 on 2016/03/10 by Ben.Marsh
Initial version of BuildGraph scripts - used to create build processes in UE4 which can be run locally or in parallel across a build farm (assuming synchronization and resource allocation implemented by a separate system). Intended to supersede GUBP.
Build graphs are declared using an XML script using syntax similar to MSBuild, ANT or NAnt, and consist of the following components:
* Tasks: Building blocks which can be executed as part of the build process. Many predefined tasks are provided (<Cook>, <Compile>, <Copy>, <Stage>, <Log>, <PakFile>, etc...), and additional tasks may be added be declaring classes derived from AutomationTool.CustomTask in other UAT modules.
* Nodes: A named sequence of tasks which is executed to produce outputs. Nodes may have input dependencies on other nodes before they can be executed. Declared with the <Node> element in scripts.
* Agent Groups: A set of nodes nodes which is executed on the same machine if running as part of a build system. Has no effect when building locally. Declared with the <Group> element in scripts.
* Triggers: Container for groups which should only be executed when explicitly triggered (using the -Trigger=<Name> or -SkipTriggers command line argument). Declared with the <Trigger> element in scripts.
* Notifiers: Specifies email recipients for failures in one or more nodes, whether they should receive notifications on warnings, and so on.
Properties can be passed in to a script on the command line, or set procedurally with the <Property Name="Foo" Value="Bar"/> syntax. Properties referenced with the $(Property Name) notation are valid within all strings, and will be expanded as macros when the script is read. If a property name is not set explicitly, it defaults to the contents of an environment variable with the same name.
Local properties, which only affect the scope of the containing XML element (node, group, etc...) are declared with the <Local Name="Foo" Value="Bar"/> element, and will override a similarly named global property for the local property's scope.
Any elements can be conditionally defined via the "If" attribute, and are largely identical to MSBuild conditions. Literals in conditions may be quoted with single (') or double (") quotes, or an unquoted sequence of letters, digits and underscore characters. All literals are considered identical regardless of how they are declared, and are considered case-insensitive for comparisons (so true equals 'True', equals "TRUE"). Available operators are "==", "!=", "And", "Or", "!", "(...)", "Exists(...)" and "HasTrailingSlash(...)". A full grammar is written up in Condition.cs.
File manipulation is done using wildcards and tags. Any attribute that accepts a list of files may consist of: a Perforce-style wildcard (matching any number of "...", "*" and "?" patterns in any location), a full path name, or a reference to a tagged collection of files, denoted by prefixing with a '#' character. Files may be added to a tag set using the <Tag> Task, which also allows performing set union/difference style operations. Each node can declare multiple outputs in the form of a list of named tags, which other nodes can then depend on.
Build graphs may be executed in parallel as part build system. To do so, the initial graph configuration is generated by running with the -Export=<Filename> argument (producing a JSON file listing the nodes and dependencies to execute). Each participating agent should be synced to the same changelist, and UAT should be re-run with the appropriate -Node=<Name> argument. Outputs from different nodes are transferred between agents via shared storage, typically a network share, the path to which can be specified on the command line using the -SharedStorageDir=<Path> argument. Note that the allocation of machines, and coordination between them, is assumed to be managed by an external system.
A schema for the known set of tasks can be generated by running UAT with the "-Schema=<FileName>" option. Generating a schema and referencing it from a BuildGraph script allows Visual Studio to validate and auto-complete elements as you type.
#rb none
#codereview Marc.Audy, Wes.Hunt, Matthew.Griffin, Richard.Fawcett
#tests local only so far, but not part of any build process yet
Change 2903539 on 2016/03/10 by John.Pollard
Improve replay playback debugging of character movement
#rb none
#tests replays
Change 2903526 on 2016/03/10 by Ben.Marsh
Remake changes from //UE4/Main without integration history, to add support for BuildGraph tasks.
#rb none
#tests none
Change 2903512 on 2016/03/10 by Dan.Youhon
Modify minimum Duration values for JumpForce and MoveToForce ability tasks so that having minimum Duration values doesn't trigger check()s
#rb None
#tests Compiles
Change 2903474 on 2016/03/10 by Marc.Audy
Fix crash if ChildActor is null
#rb None
#tests None
Change 2903314 on 2016/03/10 by Marc.Audy
Fix ParentComponent not being persisted and fixup content that was saved in the window it was broken
#rb James.Golding
#tests Selection of child actors works as expected
#jira UE-28201
Change 2903298 on 2016/03/10 by Simon.Tovey
Disabling the trails optimization.
#tests none
#rb none
#codereview Olaf.Piesche
Change 2903124 on 2016/03/10 by Robert.Manuszewski
Small refactor to pak signing to help with exe protection
#rb none
#tests none
[CL 2907678 by Andrew Grant in Main branch]
2016-03-13 18:53:13 -04:00
if ( Document . DocumentElement . Name ! = "Project" )
{
OutProjectInfo = null ;
return false ;
}
// Parse the basic structure of the document, updating properties and recursing into other referenced projects as we go
MsBuildProjectInfo ProjectInfo = new MsBuildProjectInfo ( Properties ) ;
foreach ( XmlElement Element in Document . DocumentElement . ChildNodes . OfType < XmlElement > ( ) )
{
switch ( Element . Name )
{
case "PropertyGroup" :
if ( EvaluateCondition ( Element , ProjectInfo . Properties ) )
{
ParsePropertyGroup ( Element , ProjectInfo . Properties ) ;
}
break ;
case "ItemGroup" :
if ( EvaluateCondition ( Element , ProjectInfo . Properties ) )
{
ParseItemGroup ( File . Directory , Element , ProjectInfo ) ;
}
break ;
}
}
// Return the complete project
OutProjectInfo = ProjectInfo ;
return true ;
}
/// <summary>
/// Parses a 'PropertyGroup' element.
/// </summary>
/// <param name="ParentElement">The parent 'PropertyGroup' element</param>
/// <param name="Properties">Dictionary mapping property names to values</param>
static void ParsePropertyGroup ( XmlElement ParentElement , Dictionary < string , string > Properties )
{
// We need to know the overridden output type and output path for the selected configuration.
foreach ( XmlElement Element in ParentElement . ChildNodes . OfType < XmlElement > ( ) )
{
if ( EvaluateCondition ( Element , Properties ) )
{
Properties [ Element . Name ] = ExpandProperties ( Element . InnerText , Properties ) ;
}
}
}
/// <summary>
/// Parses an 'ItemGroup' element.
/// </summary>
/// <param name="BaseDirectory">Base directory to resolve relative paths against</param>
/// <param name="ParentElement">The parent 'ItemGroup' element</param>
/// <param name="ProjectInfo">Project info object to be updated</param>
static void ParseItemGroup ( DirectoryReference BaseDirectory , XmlElement ParentElement , MsBuildProjectInfo ProjectInfo )
{
// Parse any external assembly references
foreach ( XmlElement ItemElement in ParentElement . ChildNodes . OfType < XmlElement > ( ) )
{
switch ( ItemElement . Name )
{
case "Reference" :
// Reference to an external assembly
if ( EvaluateCondition ( ItemElement , ProjectInfo . Properties ) )
{
ParseReference ( BaseDirectory , ItemElement , ProjectInfo . References ) ;
}
break ;
case "ProjectReference" :
// Reference to another project
if ( EvaluateCondition ( ItemElement , ProjectInfo . Properties ) )
{
ParseProjectReference ( BaseDirectory , ItemElement , ProjectInfo . ProjectReferences ) ;
}
break ;
}
}
}
/// <summary>
/// Parses an assembly reference from a given 'Reference' element
/// </summary>
/// <param name="BaseDirectory">Directory to resolve relative paths against</param>
/// <param name="ParentElement">The parent 'Reference' element</param>
/// <param name="ProjectReferences">Dictionary of project files to a bool indicating whether the assembly should be copied locally to the referencing project.</param>
static void ParseReference ( DirectoryReference BaseDirectory , XmlElement ParentElement , Dictionary < FileReference , bool > References )
{
string HintPath = GetChildElementString ( ParentElement , "HintPath" , null ) ;
if ( ! String . IsNullOrEmpty ( HintPath ) )
{
FileReference AssemblyFile = FileReference . Combine ( BaseDirectory , HintPath ) ;
bool bPrivate = GetChildElementBoolean ( ParentElement , "Private" , true ) ;
References . Add ( AssemblyFile , bPrivate ) ;
}
}
/// <summary>
/// Parses a project reference from a given 'ProjectReference' element
/// </summary>
/// <param name="BaseDirectory">Directory to resolve relative paths against</param>
/// <param name="ParentElement">The parent 'ProjectReference' element</param>
/// <param name="ProjectReferences">Dictionary of project files to a bool indicating whether the outputs of the project should be copied locally to the referencing project.</param>
static void ParseProjectReference ( DirectoryReference BaseDirectory , XmlElement ParentElement , Dictionary < FileReference , bool > ProjectReferences )
{
string IncludePath = ParentElement . GetAttribute ( "Include" ) ;
if ( ! String . IsNullOrEmpty ( IncludePath ) )
{
FileReference ProjectFile = FileReference . Combine ( BaseDirectory , IncludePath ) ;
bool bPrivate = GetChildElementBoolean ( ParentElement , "Private" , true ) ;
ProjectReferences [ ProjectFile ] = bPrivate ;
}
}
/// <summary>
/// Reads the inner text of a child XML element
/// </summary>
/// <param name="ParentElement">The parent element to check</param>
/// <param name="Name">Name of the child element</param>
/// <param name="DefaultValue">Default value to return if the child element is missing</param>
/// <returns>The contents of the child element, or default value if it's not present</returns>
static string GetChildElementString ( XmlElement ParentElement , string Name , string DefaultValue )
{
XmlElement ChildElement = ParentElement . ChildNodes . OfType < XmlElement > ( ) . FirstOrDefault ( x = > x . Name = = Name ) ;
if ( ChildElement = = null )
{
return DefaultValue ;
}
else
{
return ChildElement . InnerText ? ? DefaultValue ;
}
}
/// <summary>
/// Read a child XML element with the given name, and parse it as a boolean.
/// </summary>
/// <param name="ParentElement">Parent element to check</param>
/// <param name="Name">Name of the child element to look for</param>
/// <param name="DefaultValue">Default value to return if the element is missing or not a valid bool</param>
/// <returns>The parsed boolean, or the default value</returns>
static bool GetChildElementBoolean ( XmlElement ParentElement , string Name , bool DefaultValue )
{
string Value = GetChildElementString ( ParentElement , Name , null ) ;
if ( Value = = null )
{
return DefaultValue ;
}
else if ( Value . Equals ( "True" , StringComparison . InvariantCultureIgnoreCase ) )
{
return true ;
}
else if ( Value . Equals ( "False" , StringComparison . InvariantCultureIgnoreCase ) )
{
return false ;
}
else
{
return DefaultValue ;
}
}
/// <summary>
/// Evaluate whether the optional MSBuild condition on an XML element evaluates to true. Currently only supports 'ABC' == 'DEF' style expressions, but can be expanded as needed.
/// </summary>
/// <param name="Element">The XML element to check</param>
/// <param name="Properties">Dictionary mapping from property names to values.</param>
/// <returns></returns>
static bool EvaluateCondition ( XmlElement Element , Dictionary < string , string > Properties )
{
// Read the condition attribute. If it's not present, assume it evaluates to true.
string Condition = Element . GetAttribute ( "Condition" ) ;
if ( String . IsNullOrEmpty ( Condition ) )
{
return true ;
}
// Expand all the properties
Condition = ExpandProperties ( Condition , Properties ) ;
// Tokenize the condition
string [ ] Tokens = Tokenize ( Condition ) ;
// Try to evaluate it. We only support a very limited class of condition expressions at the moment, but it's enough to parse standard projects
bool bResult ;
if ( Tokens . Length = = 3 & & Tokens [ 0 ] . StartsWith ( "'" ) & & Tokens [ 1 ] = = "==" & & Tokens [ 2 ] . StartsWith ( "'" ) )
{
bResult = String . Compare ( Tokens [ 0 ] , Tokens [ 2 ] , StringComparison . InvariantCultureIgnoreCase ) = = 0 ;
}
else
{
throw new AutomationException ( "Couldn't parse condition in project file" ) ;
}
return bResult ;
}
/// <summary>
/// Expand MSBuild properties within a string. If referenced properties are not in this dictionary, the process' environment variables are expanded. Unknown properties are expanded to an empty string.
/// </summary>
/// <param name="Text">The input string to expand</param>
/// <param name="Properties">Dictionary mapping from property names to values.</param>
/// <returns>String with all properties expanded.</returns>
static string ExpandProperties ( string Text , Dictionary < string , string > Properties )
{
string NewText = Text ;
for ( int Idx = NewText . IndexOf ( "$(" ) ; Idx ! = - 1 ; Idx = NewText . IndexOf ( "$(" , Idx ) )
{
// Find the end of the variable name
int EndIdx = NewText . IndexOf ( ')' , Idx + 2 ) ;
if ( EndIdx ! = - 1 )
{
// Extract the variable name from the string
string Name = NewText . Substring ( Idx + 2 , EndIdx - ( Idx + 2 ) ) ;
// Find the value for it, either from the dictionary or the environment block
string Value ;
if ( ! Properties . TryGetValue ( Name , out Value ) )
{
Value = Environment . GetEnvironmentVariable ( Name ) ? ? "" ;
}
// Replace the variable, or skip past it
NewText = NewText . Substring ( 0 , Idx ) + Value + NewText . Substring ( EndIdx + 1 ) ;
// Make sure we skip over the expanded variable; we don't want to recurse on it.
Idx + = Value . Length ;
}
}
return NewText ;
}
/// <summary>
/// Split an MSBuild condition into tokens
/// </summary>
/// <param name="Condition">The condition expression</param>
/// <returns>Array of the parsed tokens</returns>
static string [ ] Tokenize ( string Condition )
{
List < string > Tokens = new List < string > ( ) ;
for ( int Idx = 0 ; Idx < Condition . Length ; Idx + + )
{
if ( Idx + 1 < Condition . Length & & Condition [ Idx ] = = '=' & & Condition [ Idx + 1 ] = = '=' )
{
// "==" operator
Idx + + ;
Tokens . Add ( "==" ) ;
}
else if ( Condition [ Idx ] = = '\'' )
{
// Quoted string
int StartIdx = Idx + + ;
while ( Idx + 1 < Condition . Length & & Condition [ Idx ] ! = '\'' )
{
Idx + + ;
}
Tokens . Add ( Condition . Substring ( StartIdx , Idx - StartIdx ) ) ;
}
else if ( ! Char . IsWhiteSpace ( Condition [ Idx ] ) )
{
// Other token; assume a single character.
string Token = Condition . Substring ( Idx , 1 ) ;
Tokens . Add ( Token ) ;
}
}
return Tokens . ToArray ( ) ;
}
}
}