From 306f1d0c528cb6c151594ff96a41b5c01a5c4d9b Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Sat, 21 Jul 2018 07:36:34 -0700 Subject: Integrate tools from Core project --- .../GenerateCompileWithObjectPath.cs | 146 +++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 src/WixToolset.BuildTasks/GenerateCompileWithObjectPath.cs (limited to 'src/WixToolset.BuildTasks/GenerateCompileWithObjectPath.cs') diff --git a/src/WixToolset.BuildTasks/GenerateCompileWithObjectPath.cs b/src/WixToolset.BuildTasks/GenerateCompileWithObjectPath.cs new file mode 100644 index 00000000..06c8b98a --- /dev/null +++ b/src/WixToolset.BuildTasks/GenerateCompileWithObjectPath.cs @@ -0,0 +1,146 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BuildTasks +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.IO; + using System.Security.Cryptography; + using System.Text; + using Microsoft.Build.Framework; + using Microsoft.Build.Utilities; + + /// + /// This task generates metadata on the for compile output objects. + /// + public class GenerateCompileWithObjectPath : Task + { + /// + /// The list of files to generate outputs for. + /// + [Required] + public ITaskItem[] Compile + { + get; + set; + } + + /// + /// The list of files with ObjectPath metadata. + /// + [Output] + public ITaskItem[] CompileWithObjectPath + { + get; + private set; + } + + /// + /// The folder under which all ObjectPaths should reside. + /// + [Required] + public string IntermediateOutputPath + { + get; + set; + } + + /// + /// Generate an identifier by hashing data from the row. + /// + /// Three letter or less prefix for generated row identifier. + /// Information to hash. + /// The generated identifier. + [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.InvalidOperationException.#ctor(System.String)")] + public static string GenerateIdentifier(string prefix, params string[] args) + { + string stringData = String.Join("|", args); + byte[] data = Encoding.Unicode.GetBytes(stringData); + + // hash the data + byte[] hash; + + using (MD5 md5 = new MD5CryptoServiceProvider()) + { + hash = md5.ComputeHash(data); + } + + // build up the identifier + StringBuilder identifier = new StringBuilder(35, 35); + identifier.Append(prefix); + + // hard coded to 16 as that is the most bytes that can be used to meet the length requirements. SHA1 is 20 bytes. + for (int i = 0; i < 16; i++) + { + identifier.Append(hash[i].ToString("X2", CultureInfo.InvariantCulture.NumberFormat)); + } + + return identifier.ToString(); + } + + /// + /// Gets the full path of the directory in which the file is found. + /// + /// The file from which to extract the directory. + /// The generated identifier. + private static string GetDirectory(ITaskItem file) + { + return file.GetMetadata("RootDir") + file.GetMetadata("Directory"); + } + + /// + /// Sets the object path to use for the file. + /// + /// The file on which to set the ObjectPath metadata. + /// + /// For the same input path it will return the same ObjectPath. Case is not ignored, however that isn't a problem. + /// + private void SetObjectPath(ITaskItem file) + { + // If the source file is in the project directory or in the intermediate directory, use the intermediate directory. + if (string.IsNullOrEmpty(file.GetMetadata("RelativeDir")) || string.Compare(file.GetMetadata("RelativeDir"), this.IntermediateOutputPath, StringComparison.OrdinalIgnoreCase) == 0) + { + file.SetMetadata("ObjectPath", this.IntermediateOutputPath); + } + // Otherwise use a subdirectory of the intermediate directory. The subfolder's name is based on the full path of the folder containing the source file. + else + { + file.SetMetadata("ObjectPath", Path.Combine(this.IntermediateOutputPath, GenerateIdentifier("pth", GetDirectory(file))) + Path.DirectorySeparatorChar); + } + } + + /// + /// Gets a complete list of external cabs referenced by the given installer database file. + /// + /// True upon completion of the task execution. + public override bool Execute() + { + if (string.IsNullOrEmpty(this.IntermediateOutputPath)) + { + this.Log.LogError("IntermediateOutputPath parameter is required and cannot be empty"); + return false; + } + + if (this.Compile == null || this.Compile.Length == 0) + { + return true; + } + + this.CompileWithObjectPath = new ITaskItem[this.Compile.Length]; + for (int i = 0; i < this.Compile.Length; ++i) + { + this.CompileWithObjectPath[i] = new TaskItem(this.Compile[i].ItemSpec, this.Compile[i].CloneCustomMetadata()); + + // Do not overwrite the ObjectPath metadata if it already was set. + if (string.IsNullOrEmpty(this.CompileWithObjectPath[i].GetMetadata("ObjectPath"))) + { + SetObjectPath(this.CompileWithObjectPath[i]); + } + } + + return true; + } + } +} -- cgit v1.2.3-55-g6feb