You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Merging //UE4/Dev-Main to Dev-Editor (//UE4/Dev-Editor) at CL 7473521
#rb none #fyi Max.Chen, Tim.Gautier [CL 7614721 by Chris Gagnon in Dev-Editor branch]
This commit is contained in:
@@ -29,17 +29,28 @@ namespace Tools.DotNETCommon
|
||||
/// </summary>
|
||||
public Dictionary<FileReference, bool> ProjectReferences = new Dictionary<FileReference, bool>();
|
||||
|
||||
/// <summary>
|
||||
/// List of compile references in the project.
|
||||
/// </summary>
|
||||
public List<FileReference> CompileReferences = new List<FileReference>();
|
||||
|
||||
/// <summary>
|
||||
/// Mapping of content IF they are flagged Always or Newer
|
||||
/// </summary>
|
||||
public Dictionary<FileReference, bool> ContentReferences = new Dictionary<FileReference, bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Path to the CSProject file
|
||||
/// </summary>
|
||||
public FileReference ProjectPath;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="InProperties">Initial mapping of property names to values</param>
|
||||
CsProjectInfo(Dictionary<string, string> InProperties)
|
||||
CsProjectInfo(Dictionary<string, string> InProperties, FileReference InProjectPath)
|
||||
{
|
||||
ProjectPath = InProjectPath;
|
||||
Properties = new Dictionary<string, string>(InProperties);
|
||||
}
|
||||
|
||||
@@ -61,6 +72,17 @@ namespace Tools.DotNETCommon
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the assembly name used by this project
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetAssemblyName()
|
||||
{
|
||||
string Output = "";
|
||||
Properties.TryGetValue("AssemblyName", out Output);
|
||||
return Output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all build products from this project. This includes content and other assemblies marked to be copied local.
|
||||
/// </summary>
|
||||
@@ -234,7 +256,7 @@ namespace Tools.DotNETCommon
|
||||
}
|
||||
|
||||
// Parse the basic structure of the document, updating properties and recursing into other referenced projects as we go
|
||||
CsProjectInfo ProjectInfo = new CsProjectInfo(Properties);
|
||||
CsProjectInfo ProjectInfo = new CsProjectInfo(Properties, File);
|
||||
foreach (XmlElement Element in Document.DocumentElement.ChildNodes.OfType<XmlElement>())
|
||||
{
|
||||
switch (Element.Name)
|
||||
@@ -303,6 +325,13 @@ namespace Tools.DotNETCommon
|
||||
ParseProjectReference(BaseDirectory, ItemElement, ProjectInfo.ProjectReferences);
|
||||
}
|
||||
break;
|
||||
case "Compile":
|
||||
// Reference to another project
|
||||
if (EvaluateCondition(ItemElement, ProjectInfo.Properties))
|
||||
{
|
||||
ParseCompileReference(BaseDirectory, ItemElement, ProjectInfo.CompileReferences);
|
||||
}
|
||||
break;
|
||||
case "Content":
|
||||
case "None":
|
||||
// Reference to another project
|
||||
@@ -354,6 +383,22 @@ namespace Tools.DotNETCommon
|
||||
}
|
||||
}
|
||||
|
||||
/// <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="CompileReferences">List of source files.</param>
|
||||
static void ParseCompileReference(DirectoryReference BaseDirectory, XmlElement ParentElement, List<FileReference> CompileReferences)
|
||||
{
|
||||
string IncludePath = UnescapeString(ParentElement.GetAttribute("Include"));
|
||||
if (!String.IsNullOrEmpty(IncludePath))
|
||||
{
|
||||
FileReference SourceFile = FileReference.Combine(BaseDirectory, IncludePath);
|
||||
CompileReferences.Add(SourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses an assembly reference from a given 'Content' element
|
||||
/// </summary>
|
||||
@@ -694,4 +739,37 @@ namespace Tools.DotNETCommon
|
||||
return NewText;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for CsProject support
|
||||
/// </summary>
|
||||
public static class CsProjectInfoExtensionMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds aall input/output properties of a CSProject to a hash collection
|
||||
/// </summary>
|
||||
/// <param name="Hasher"></param>
|
||||
/// <param name="Project"></param>
|
||||
/// <returns></returns>
|
||||
public static bool AddCsProjectInfo(this HashCollection Hasher, CsProjectInfo Project, HashCollection.HashType HashType)
|
||||
{
|
||||
// Get the output assembly and pdb file
|
||||
DirectoryReference ProjectDirectory = Project.ProjectPath.Directory;
|
||||
DirectoryReference OutputDir = Project.GetOutputDir(ProjectDirectory);
|
||||
FileReference OutputFile = FileReference.Combine(OutputDir, Project.GetAssemblyName() + ".dll");
|
||||
FileReference DebugFile = OutputFile.ChangeExtension("pdb");
|
||||
|
||||
// build a list of all input and output files from this module
|
||||
List<FileReference> DependentFiles = new List<FileReference> { Project.ProjectPath, OutputFile, DebugFile };
|
||||
|
||||
DependentFiles.AddRange(Project.CompileReferences);
|
||||
|
||||
if (!Hasher.AddFiles(DependentFiles, HashType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +161,7 @@
|
||||
<Compile Include="ResXResource\UEResXWriter.cs" />
|
||||
<Compile Include="StringUtils.cs" />
|
||||
<Compile Include="ThreadPoolWorkQueue.cs" />
|
||||
<Compile Include="HashCollection.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using System.Linq;
|
||||
using Tools.DotNETCommon;
|
||||
|
||||
namespace Tools.DotNETCommon
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Class that holds a single hash entry. Only the hash is used for comparisons but the
|
||||
/// name and meta fields can hold related data for debugging etc.
|
||||
/// </summary>
|
||||
public class HashEntry : IEquatable<HashEntry>
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string MetaData { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public ContentHash Hash { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "Hash", DataType = "hexBinary")]
|
||||
public byte[] HashBytes
|
||||
{
|
||||
get { return Hash.Bytes; }
|
||||
set { Hash = new ContentHash(value); }
|
||||
}
|
||||
|
||||
public HashEntry(string InName, ContentHash InHash, string InMeta)
|
||||
{
|
||||
Name = InName;
|
||||
Hash = InHash;
|
||||
MetaData = InMeta;
|
||||
}
|
||||
|
||||
// parameterless constructor for serialization
|
||||
public HashEntry()
|
||||
{
|
||||
}
|
||||
|
||||
// Equality check using the underlying content hash
|
||||
public bool Equals(HashEntry RHS)
|
||||
{
|
||||
return Hash == RHS.Hash;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Hash.GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Hash.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class that holds a collection of hashes with helpers for adding files, comparisions, and
|
||||
/// serialization to and from files
|
||||
/// </summary>
|
||||
public class HashCollection
|
||||
{
|
||||
public enum HashType
|
||||
{
|
||||
MetaData,
|
||||
Content
|
||||
}
|
||||
|
||||
// underlying hashset that holds our data
|
||||
public HashSet<HashEntry> Hashes { get; protected set; }
|
||||
|
||||
public HashCollection()
|
||||
{
|
||||
Hashes = new HashSet<HashEntry>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a file to our hash collection. If the specified path does not exist an exception
|
||||
/// will be thrown
|
||||
/// </summary>
|
||||
/// <param name="InPath"></param>
|
||||
/// <param name="HashType"></param>
|
||||
public bool AddFile(FileReference InPath, HashCollection.HashType HashType)
|
||||
{
|
||||
var Fi = new FileInfo(InPath.FullName);
|
||||
|
||||
if (!Fi.Exists)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string MetaData = string.Format("File={0} Size={1} LastWrite={2}", InPath, Fi.Length, Fi.LastWriteTimeUtc.ToString());
|
||||
|
||||
// Hash metadata or content
|
||||
ContentHash Hash = HashType == HashCollection.HashType.MetaData ? ContentHash.SHA1(MetaData) : ContentHash.SHA1(InPath);
|
||||
|
||||
HashEntry Entry = new HashEntry(InPath.FullName, Hash, MetaData);
|
||||
|
||||
Hashes.Add(Entry);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience function that adds a range of files
|
||||
/// </summary>
|
||||
/// <param name="Files"></param>
|
||||
/// <param name="HashType"></param>
|
||||
public bool AddFiles(IEnumerable<FileReference> Files, HashCollection.HashType HashType)
|
||||
{
|
||||
foreach (var File in Files)
|
||||
{
|
||||
if (!AddFile(File, HashType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two collections by comparing the underlying hashsets
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
HashCollection RHS = obj as HashCollection;
|
||||
|
||||
if (RHS == null)
|
||||
{
|
||||
return false;
|
||||
|
||||
}
|
||||
return Hashes.SetEquals(RHS.Hashes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugging helper that returns true if there's a hash with the specified name
|
||||
/// </summary>
|
||||
/// <param name="Name"></param>
|
||||
/// <returns></returns>
|
||||
public bool HasEntryForName(string Name)
|
||||
{
|
||||
return Hashes.Where(E => E.Name == Name).Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debugging helper that returns the hash entry for the specified name
|
||||
/// </summary>
|
||||
/// <param name="Input"></param>
|
||||
/// <returns></returns>
|
||||
public HashEntry GetEntryForName(string Input)
|
||||
{
|
||||
return Hashes.Where(E => E.Name == Input).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs differences between two collections for debugging
|
||||
/// </summary>
|
||||
/// <param name="RHS"></param>
|
||||
public void LogDifferences(HashCollection RHS)
|
||||
{
|
||||
foreach (var Entry in Hashes)
|
||||
{
|
||||
if (!RHS.HasEntryForName(Entry.Name))
|
||||
{
|
||||
Log.TraceInformation("RHS does not have an entry for {0}", Entry.Name);
|
||||
}
|
||||
else if (!RHS.Hashes.Contains(Entry))
|
||||
{
|
||||
HashEntry RHSEntry = RHS.GetEntryForName(Entry.Name);
|
||||
Log.TraceInformation("RHS hash mismatch for {0}", Entry.Name);
|
||||
Log.TraceInformation("Current:\n\t{0}\n\t{1}\n\t{2}", Entry.Hash, Entry.Name, Entry.MetaData);
|
||||
Log.TraceInformation("RHS:\n\t{0}\n\t{1}\n\t{2}", RHSEntry.Hash, RHSEntry.Name, RHSEntry.MetaData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return EqualityComparer<HashSet<HashEntry>>.Default.GetHashCode(Hashes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a hash collection from a previously serialized file
|
||||
/// </summary>
|
||||
/// <param name="InPath"></param>
|
||||
/// <returns></returns>
|
||||
public static HashCollection CreateFromFile(string InPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var stream = System.IO.File.OpenRead(InPath))
|
||||
{
|
||||
var Serializer = new XmlSerializer(typeof(HashCollection));
|
||||
return Serializer.Deserialize(stream) as HashCollection;
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
Log.TraceWarning("Failed to load HashCollection from {0}. {1}", InPath, Ex.Message);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a hash collection to the specified file path as XML.
|
||||
/// </summary>
|
||||
/// <param name="OutPath"></param>
|
||||
public void SaveToFile(string OutPath)
|
||||
{
|
||||
XmlSerializer XS = new XmlSerializer(this.GetType());
|
||||
|
||||
//first serialize the object to memory stream,
|
||||
//in case of exception, the original file is not corrupted
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
XmlWriterSettings Settings = new XmlWriterSettings();
|
||||
Settings.Indent = true;
|
||||
Settings.IndentChars = ("\t");
|
||||
Settings.Encoding = Encoding.UTF8;
|
||||
|
||||
using (XmlWriter Writer = XmlWriter.Create(MS, Settings))
|
||||
{
|
||||
XS.Serialize(Writer, this);
|
||||
}
|
||||
|
||||
MS.Flush();
|
||||
|
||||
string String = Encoding.UTF8.GetString(MS.ToArray());
|
||||
|
||||
File.WriteAllText(OutPath, String);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user