diff options
author | Pranav K <prkrishn@hotmail.com> | 2020-04-21 03:25:24 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-21 03:25:24 +0300 |
commit | 6c23730fa8d04e3b9d62d9d16220a02f9b9820b0 (patch) | |
tree | e30d403afe01003f87e9913c5bd44c7d643ddd3e /src/Components/WebAssembly | |
parent | 202d21431e6f85aac75d3cc81589156ea42ee33c (diff) |
Compute SHA256s for blazor.boot.json in parallel (#21021)
* Compute SHA256s for blazor.boot.json in parallel
Diffstat (limited to 'src/Components/WebAssembly')
-rw-r--r-- | src/Components/WebAssembly/Build/src/Tasks/BlazorGetFileHash.cs | 135 | ||||
-rw-r--r-- | src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets | 6 |
2 files changed, 139 insertions, 2 deletions
diff --git a/src/Components/WebAssembly/Build/src/Tasks/BlazorGetFileHash.cs b/src/Components/WebAssembly/Build/src/Tasks/BlazorGetFileHash.cs new file mode 100644 index 0000000000..f10f53a748 --- /dev/null +++ b/src/Components/WebAssembly/Build/src/Tasks/BlazorGetFileHash.cs @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Microsoft.Build.Tasks +{ + /// <summary> + /// Computes the checksum for a single file. + /// </summary> + public sealed class BlazorGetFileHash : Task + { + internal const string _defaultFileHashAlgorithm = "SHA256"; + internal const string _hashEncodingBase64 = "base64"; + + /// <summary> + /// The files to be hashed. + /// </summary> + [Required] + public ITaskItem[] Files { get; set; } + + /// <summary> + /// The algorithm. Allowed values: SHA256, SHA384, SHA512. Default = SHA256. + /// </summary> + public string Algorithm { get; set; } = _defaultFileHashAlgorithm; + + /// <summary> + /// The metadata name where the hash is stored in each item. Defaults to "FileHash". + /// </summary> + public string MetadataName { get; set; } = "FileHash"; + + /// <summary> + /// The encoding to use for generated hashs. Defaults to "hex". Allowed values = "base64". + /// </summary> + public string HashEncoding { get; set; } = _hashEncodingBase64; + + /// <summary> + /// The hash of the file. This is only set if there was one item group passed in. + /// </summary> + [Output] + public string Hash { get; set; } + + /// <summary> + /// The input files with additional metadata set to include the file hash. + /// </summary> + [Output] + public ITaskItem[] Items { get; set; } + + public override bool Execute() + { + if (!SupportsAlgorithm(Algorithm)) + { + Log.LogError("Unrecognized HashAlgorithm {0}", Algorithm); + return false; + } + + System.Threading.Tasks.Parallel.ForEach(Files, file => + { + if (!File.Exists(file.ItemSpec)) + { + Log.LogError("File not found '{0}", file.ItemSpec); + } + }); + + if (Log.HasLoggedErrors) + { + return false; + } + + System.Threading.Tasks.Parallel.ForEach(Files, file => + { + var hash = ComputeHash(Algorithm, file.ItemSpec); + file.SetMetadata("FileHashAlgorithm", Algorithm); + file.SetMetadata(MetadataName, EncodeHash(hash)); + }); + + Items = Files; + + if (Files.Length == 1) + { + Hash = Files[0].GetMetadata(MetadataName); + } + + return !Log.HasLoggedErrors; + } + + internal static string EncodeHash(byte[] hash) + { + return Convert.ToBase64String(hash); + } + + internal static bool SupportsAlgorithm(string algorithmName) + => _supportedAlgorithms.Contains(algorithmName); + + internal static byte[] ComputeHash(string algorithmName, string filePath) + { + using (var stream = File.OpenRead(filePath)) + using (var algorithm = CreateAlgorithm(algorithmName)) + { + return algorithm.ComputeHash(stream); + } + } + + private static readonly HashSet<string> _supportedAlgorithms + = new HashSet<string>(StringComparer.OrdinalIgnoreCase) + { + "SHA256", + "SHA384", + "SHA512", + }; + + private static HashAlgorithm CreateAlgorithm(string algorithmName) + { + if (string.Equals(algorithmName, "SHA256", StringComparison.OrdinalIgnoreCase)) + { + return SHA256.Create(); + } + else if (string.Equals(algorithmName, "SHA384", StringComparison.OrdinalIgnoreCase)) + { + return SHA384.Create(); + } + else if (string.Equals(algorithmName, "SHA512", StringComparison.OrdinalIgnoreCase)) + { + return SHA512.Create(); + } + + throw new ArgumentOutOfRangeException(); + } + } +}
\ No newline at end of file diff --git a/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets b/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets index 8c16457068..1b7614bbae 100644 --- a/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets +++ b/src/Components/WebAssembly/Build/src/targets/Blazor.MonoRuntime.targets @@ -1,4 +1,6 @@ <Project> + <UsingTask TaskName="BlazorGetFileHash" AssemblyFile="$(_BlazorTasksPath)" /> + <PropertyGroup> <BlazorWebAssemblyEnableLinking Condition="'$(BlazorWebAssemblyEnableLinking)' == '' AND '$(Configuration)' != 'Debug'">true</BlazorWebAssemblyEnableLinking> <BlazorWebAssemblyEnableLinking Condition="'$(BlazorWebAssemblyEnableLinking)' == ''">false</BlazorWebAssemblyEnableLinking> @@ -153,9 +155,9 @@ <_ExistingBlazorOutputWithTargetPath Include="@(_BlazorOutputWithTargetPath)" Condition="Exists('%(FullPath)')" /> </ItemGroup> - <GetFileHash Files="@(_ExistingBlazorOutputWithTargetPath)" Algorithm="SHA256" HashEncoding="base64"> + <BlazorGetFileHash Files="@(_ExistingBlazorOutputWithTargetPath)" Algorithm="SHA256" HashEncoding="base64"> <Output TaskParameter="Items" ItemName="_BlazorOutputWithHash" /> - </GetFileHash> + </BlazorGetFileHash> <ItemGroup> <_BlazorOutputWithIntegrity Include="@(_BlazorOutputWithHash)"> |