You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
==========================
MAJOR FEATURES + CHANGES
==========================
Change 2909886 on 2016/03/15 by Matthew.Griffin
Adding a build exception to give a message instead of crashing when trying to generate all project files from an installed build.
Change 2911727 on 2016/03/16 by Matthew.Griffin
Added Platform Type and Architecture to Installed Platform Info
Reworked the different IsValid... functions to use lamdas to reduce duplicated code looping and checking receipts
Moved the code to write config file entries into InstalledPlatformInfo so that it can be reused by anyone wanting to make installed builds
Added temporary hack to write Android architecture until I can get it from build process
Change 2913692 on 2016/03/17 by Ben.Marsh
UAT: Move script to archive a build for UGS into a public folder.
Change 2915445 on 2016/03/18 by Ben.Marsh
UAT: Reduce the number of redundant log warnings/errors after a reported build failure, and simplify calls to ParallelExecutor which don't need retrying.
Change 2915450 on 2016/03/18 by Ben.Marsh
UAT: Suppress warning messages trying to kill child processes if the operation failed because it's already exited.
Change 2925830 on 2016/03/29 by Matthew.Griffin
Added new selective download tags
Added a test for whether installed platforms are missing required files so that we can try to open the launcher to the installer settings
Change 2926437 on 2016/03/29 by Ben.Marsh
PR #2210: Fix "Rebuild.bat" for paths with parentheses (Contributed by amcofi)
Change 2927399 on 2016/03/30 by Matthew.Griffin
Updating use of PDBCopy to look in VS2015 folder and fall back to VS2013 version if it doesn't exist.
Change 2933093 on 2016/04/05 by Ben.Marsh
PR #2232: Updated copyright text to 2016 (Contributed by erikbye)
Change 2936221 on 2016/04/07 by Matthew.Griffin
Adding checks on architecture for android config options
Change 2938021 on 2016/04/08 by Ben.Marsh
UAT: Prevent UnauthorizedAccessException when enumerating crash files on Mac from a restricted user account.
Change 2939332 on 2016/04/11 by Matthew.Griffin
Added AdditionalBundleResources to external file list so that they should be included in Launcher releases
Change 2939767 on 2016/04/11 by Ben.Marsh
BuildGraph: Add a -preprocess option, which will cause the preprocessed and culled graph out to an XML file for debugging.
Change 2941611 on 2016/04/12 by Ben.Marsh
UAT: Prevent warning about commands requiring P4 if -p4 is specified on the command line.
Change 2942037 on 2016/04/13 by Ben.Marsh
UBT: Only print 'Detailed Action Stats' message footer if there were any detailed action stats.
Change 2942640 on 2016/04/13 by Ben.Marsh
GUBP: Trigger GitHub promotions by triggering a new procedure rather than scanning for labels.
Change 2942728 on 2016/04/13 by Ben.Marsh
BuildGraph: Rename "AgentGroup" to "Agent" for consistency with XML.
Change 2942735 on 2016/04/13 by Ben.Marsh
BuildGraph: Few renames to match class names (Build.cs -> BuildGraph.cs, AgentGroup.cs -> Agent.cs)
Change 2943568 on 2016/04/14 by Ben.Marsh
EC: Print out the log folder at the start of each job.
Change 2944421 on 2016/04/14 by Ben.Marsh
EC: Add GitHub dashboard page which shows the current syncing state
#lockdown Nick.Penwarden
[CL 2944733 by Ben Marsh in Main branch]
322 lines
12 KiB
C#
322 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Xml;
|
|
using UnrealBuildTool;
|
|
|
|
namespace AutomationTool
|
|
{
|
|
/// <summary>
|
|
/// Specifies validation that should be performed on a task parameter.
|
|
/// </summary>
|
|
public enum TaskParameterValidationType
|
|
{
|
|
/// <summary>
|
|
/// Allow any valid values for the field type.
|
|
/// </summary>
|
|
Default,
|
|
|
|
/// <summary>
|
|
/// A standard name; alphanumeric characters, plus underscore and space. Spaces at the start or end, or more than one in a row are prohibited.
|
|
/// </summary>
|
|
Name,
|
|
|
|
/// <summary>
|
|
/// A list of names separated by semicolons
|
|
/// </summary>
|
|
NameList,
|
|
|
|
/// <summary>
|
|
/// A tag name (a regular name with '#' prefix)
|
|
/// </summary>
|
|
Tag,
|
|
|
|
/// <summary>
|
|
/// A list of tag names separated by semicolons
|
|
/// </summary>
|
|
TagList,
|
|
|
|
/// <summary>
|
|
/// A standard name or tag name
|
|
/// </summary>
|
|
NameOrTag,
|
|
|
|
/// <summary>
|
|
/// A list of standard name or tag names separated by semicolons
|
|
/// </summary>
|
|
NameOrTagList,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attribute to mark parameters to a task, which should be read as XML attributes from the script file.
|
|
/// </summary>
|
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
|
public class TaskParameterAttribute : Attribute
|
|
{
|
|
/// <summary>
|
|
/// Whether the parameter can be omitted
|
|
/// </summary>
|
|
public bool Optional
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets additional restrictions on how this field is validated in the schema. Default is to allow any valid field type.
|
|
/// </summary>
|
|
public TaskParameterValidationType ValidationType
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attribute used to associate an XML element name with a parameter block that can be used to construct tasks
|
|
/// </summary>
|
|
[AttributeUsage(AttributeTargets.Class)]
|
|
public class TaskElementAttribute : Attribute
|
|
{
|
|
/// <summary>
|
|
/// Name of the XML element that can be used to denote this class
|
|
/// </summary>
|
|
public string Name;
|
|
|
|
/// <summary>
|
|
/// Type to be constructed from the deserialized element
|
|
/// </summary>
|
|
public Type ParametersType;
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <param name="InName">Name of the XML element used to denote this object</param>
|
|
/// <param name="InParametersType">Type to be constructed from this object</param>
|
|
public TaskElementAttribute(string InName, Type InParametersType)
|
|
{
|
|
Name = InName;
|
|
ParametersType = InParametersType;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Base class for all custom build tasks
|
|
/// </summary>
|
|
public abstract class CustomTask
|
|
{
|
|
/// <summary>
|
|
/// Allow this task to merge with other tasks within the same node if it can. This can be useful to allow tasks to execute in parallel.
|
|
/// </summary>
|
|
/// <param name="OtherTasks">Other tasks that this task can merge with. If a merge takes place, the other tasks should be removed from the list.</param>
|
|
public virtual void Merge(List<CustomTask> OtherTasks)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Execute this node.
|
|
/// </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>Whether the task succeeded or not. Exiting with an exception will be caught and treated as a failure.</returns>
|
|
public abstract bool Execute(JobContext Job, HashSet<FileReference> BuildProducts, Dictionary<string, HashSet<FileReference>> TagNameToFileSet);
|
|
|
|
/// <summary>
|
|
/// Output this task out to an XML writer.
|
|
/// </summary>
|
|
public abstract void Write(XmlWriter Writer);
|
|
|
|
/// <summary>
|
|
/// Writes this task to an XML writer, using the given parameters object.
|
|
/// </summary>
|
|
/// <param name="Writer"></param>
|
|
/// <param name="Task"></param>
|
|
protected void Write(XmlWriter Writer, object Parameters)
|
|
{
|
|
TaskElementAttribute Element = GetType().GetCustomAttribute<TaskElementAttribute>();
|
|
Writer.WriteStartElement(Element.Name);
|
|
|
|
foreach (FieldInfo Field in Parameters.GetType().GetFields())
|
|
{
|
|
if (Field.MemberType == MemberTypes.Field)
|
|
{
|
|
TaskParameterAttribute ParameterAttribute = Field.GetCustomAttribute<TaskParameterAttribute>();
|
|
if (ParameterAttribute != null)
|
|
{
|
|
object Value = Field.GetValue(Parameters);
|
|
if (Value != null && Field.FieldType == typeof(bool) && (bool)Value == false)
|
|
{
|
|
Value = null;
|
|
}
|
|
if (Value != null)
|
|
{
|
|
Writer.WriteAttributeString(Field.Name, Value.ToString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Writer.WriteEndElement();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resolves a single name to a file reference, resolving relative paths to the root of the current path.
|
|
/// </summary>
|
|
/// <param name="Name">Name of the file</param>
|
|
/// <returns>Fully qualified file reference</returns>
|
|
public static FileReference ResolveFile(string Name)
|
|
{
|
|
if(Path.IsPathRooted(Name))
|
|
{
|
|
return new FileReference(Name);
|
|
}
|
|
else
|
|
{
|
|
return new FileReference(Path.Combine(CommandUtils.CmdEnv.LocalRoot, Name));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resolves a directory reference from the given string. Assumes the root directory is the root of the current branch.
|
|
/// </summary>
|
|
/// <param name="Name">Name of the directory. May be null or empty.</param>
|
|
/// <returns>The resolved directory</returns>
|
|
public static DirectoryReference ResolveDirectory(string Name)
|
|
{
|
|
if(String.IsNullOrEmpty(Name))
|
|
{
|
|
return CommandUtils.RootDirectory;
|
|
}
|
|
else if(Path.IsPathRooted(Name))
|
|
{
|
|
return new DirectoryReference(Name);
|
|
}
|
|
else
|
|
{
|
|
return DirectoryReference.Combine(CommandUtils.RootDirectory, Name);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Finds or adds a set containing files with the given tag
|
|
/// </summary>
|
|
/// <param name="Name">The tag name to return a set for. An leading '#' character is optional.</param>
|
|
/// <returns>Set of files</returns>
|
|
public static HashSet<FileReference> FindOrAddTagSet(Dictionary<string, HashSet<FileReference>> TagNameToFileSet, string Name)
|
|
{
|
|
// Get the clean tag name, without the leading '#' character
|
|
string TagName = Name.StartsWith("#")? Name.Substring(1) : Name;
|
|
|
|
// Find the files which match this tag
|
|
HashSet<FileReference> Files;
|
|
if(!TagNameToFileSet.TryGetValue(TagName, out Files))
|
|
{
|
|
Files = new HashSet<FileReference>();
|
|
TagNameToFileSet.Add(TagName, Files);
|
|
}
|
|
|
|
// If we got a null reference, it's because the tag is not listed as an input for this node (see RunGraph.BuildSingleNode). Fill it in, but only with an error.
|
|
if(Files == null)
|
|
{
|
|
CommandUtils.LogError("Attempt to reference tag '{0}', which is not listed as a dependency of this node.", Name);
|
|
Files = new HashSet<FileReference>();
|
|
TagNameToFileSet.Add(TagName, Files);
|
|
}
|
|
return Files;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resolve a list of files, tag names or file specifications separated by semicolons. Supported entries may be:
|
|
/// a) The name of a tag set (eg. #CompiledBinaries)
|
|
/// b) Relative or absolute filenames
|
|
/// c) A simple file pattern (eg. Foo/*.cpp)
|
|
/// d) A full directory wildcard (eg. Engine/...)
|
|
/// Note that wildcards may only match the last fragment in a pattern, so matches like "/*/Foo.txt" and "/.../Bar.txt" are illegal.
|
|
/// </summary>
|
|
/// <param name="DefaultDirectory">The default directory to resolve relative paths to</param>
|
|
/// <param name="DelimitedPatterns">List of files, tag names, or file specifications to include separated by semicolons.</param>
|
|
/// <param name="TagNameToFileSet">Mapping of tag name to fileset, as passed to the Execute() method</param>
|
|
/// <returns>Set of matching files.</returns>
|
|
public static HashSet<FileReference> ResolveFilespec(DirectoryReference DefaultDirectory, string DelimitedPatterns, Dictionary<string, HashSet<FileReference>> TagNameToFileSet)
|
|
{
|
|
List<string> ExcludePatterns = new List<string>();
|
|
return ResolveFilespecWithExcludePatterns(DefaultDirectory, DelimitedPatterns, ExcludePatterns, TagNameToFileSet);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resolve a list of files, tag names or file specifications separated by semicolons as above, but preserves any directory references for further processing.
|
|
/// </summary>
|
|
/// <param name="DefaultDirectory">The default directory to resolve relative paths to</param>
|
|
/// <param name="DelimitedPatterns">List of files, tag names, or file specifications to include separated by semicolons.</param>
|
|
/// <param name="ExcludePatterns">Set of patterns to apply to directory searches. This can greatly speed up enumeration by earlying out of recursive directory searches if large directories are excluded (eg. .../Intermediate/...).</param>
|
|
/// <param name="TagNameToFileSet">Mapping of tag name to fileset, as passed to the Execute() method</param>
|
|
/// <returns>Set of matching files.</returns>
|
|
public static HashSet<FileReference> ResolveFilespecWithExcludePatterns(DirectoryReference DefaultDirectory, string DelimitedPatterns, List<string> ExcludePatterns, Dictionary<string, HashSet<FileReference>> TagNameToFileSet)
|
|
{
|
|
// Split the argument into a list of patterns
|
|
string[] Patterns = SplitDelimitedList(DelimitedPatterns);
|
|
|
|
// Parse each of the patterns, and add the results into the given sets
|
|
HashSet<FileReference> Files = new HashSet<FileReference>();
|
|
foreach(string Pattern in Patterns)
|
|
{
|
|
// Check if it's a tag name
|
|
if(Pattern.StartsWith("#"))
|
|
{
|
|
Files.UnionWith(FindOrAddTagSet(TagNameToFileSet, Pattern.Substring(1)));
|
|
continue;
|
|
}
|
|
|
|
// If it doesn't contain any wildcards, just add the pattern directly
|
|
int WildcardIdx = FileFilter.FindWildcardIndex(Pattern);
|
|
if(WildcardIdx == -1)
|
|
{
|
|
Files.Add(FileReference.Combine(DefaultDirectory, Pattern));
|
|
continue;
|
|
}
|
|
|
|
// Find the base directory for the search. We construct this in a very deliberate way including the directory separator itself, so matches
|
|
// against the OS root directory will resolve correctly both on Mac (where / is the filesystem root) and Windows (where / refers to the current drive).
|
|
int LastDirectoryIdx = Pattern.LastIndexOfAny(new char[]{ Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, WildcardIdx);
|
|
DirectoryReference BaseDir = DirectoryReference.Combine(DefaultDirectory, Pattern.Substring(0, LastDirectoryIdx + 1));
|
|
|
|
// Construct the absolute include pattern to match against, re-inserting the resolved base directory to construct a canonical path.
|
|
string IncludePattern = BaseDir.FullName.TrimEnd(new char[]{ Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }) + "/" + Pattern.Substring(LastDirectoryIdx + 1);
|
|
|
|
// Construct a filter and apply it to the directory
|
|
if(BaseDir.Exists())
|
|
{
|
|
FileFilter Filter = new FileFilter();
|
|
Filter.AddRule(IncludePattern, FileFilterType.Include);
|
|
Filter.AddRules(ExcludePatterns, FileFilterType.Exclude);
|
|
Files.UnionWith(Filter.ApplyToDirectory(BaseDir, BaseDir.FullName, true));
|
|
}
|
|
}
|
|
|
|
// If we have exclude rules, create and run a filter against all the output files to catch things that weren't added from an include
|
|
if(ExcludePatterns.Count > 0)
|
|
{
|
|
FileFilter Filter = new FileFilter(FileFilterType.Include);
|
|
Filter.AddRules(ExcludePatterns, FileFilterType.Exclude);
|
|
Files.RemoveWhere(x => !Filter.Matches(x.FullName));
|
|
}
|
|
return Files;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Splits a string separated by semicolons into a list, removing empty entries
|
|
/// </summary>
|
|
/// <param name="Text">The input string</param>
|
|
/// <returns>Array of the parsed items</returns>
|
|
public static string[] SplitDelimitedList(string Text)
|
|
{
|
|
return Text.Split(';').Select(x => x.Trim()).Where(x => x.Length > 0).ToArray();
|
|
}
|
|
}
|
|
}
|