Merge pull request #23666 from dotnet-maestro-bot/merge/release/5.0-preview7-to-master

[automated] Merge branch 'release/5.0-preview7' => 'master'
This commit is contained in:
msftbot[bot] 2020-07-06 04:58:26 +00:00 committed by GitHub
commit 6abfb4f763
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 221 additions and 10 deletions

View File

@ -319,6 +319,22 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
return filePath;
}
public static string DirectoryExists(MSBuildResult result, params string[] paths)
{
if (result == null)
{
throw new ArgumentNullException(nameof(result));
}
var filePath = Path.Combine(result.Project.DirectoryPath, Path.Combine(paths));
if (!Directory.Exists(filePath))
{
throw new DirectoryMissingException(result, filePath);
}
return filePath;
}
public static void FileCountEquals(MSBuildResult result, int expected, string directoryPath, string searchPattern, SearchOption searchOption = SearchOption.AllDirectories)
{
if (result == null)
@ -820,6 +836,19 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
protected override string Heading => $"File: '{FilePath}' was not found.";
}
private class DirectoryMissingException : MSBuildXunitException
{
public DirectoryMissingException(MSBuildResult result, string directoryPath)
: base(result)
{
DirectoryPath = directoryPath;
}
public string DirectoryPath { get; }
protected override string Heading => $"Directory: '{DirectoryPath}' was not found.";
}
private class FileCountException : MSBuildXunitException
{
public FileCountException(MSBuildResult result, int expected, string directoryPath, string searchPattern, string[] files)

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
public class WasmBuildIncrementalismTest
{
[Fact]
public async Task Build_WithLinker_IsIncremental()
public async Task Build_IsIncremental()
{
// Arrange
using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
@ -40,6 +40,37 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
}
[Fact]
public async Task Build_GzipCompression_IsIncremental()
{
// Arrange
using var project = ProjectDirectory.Create("blazorwasm", additionalProjects: new[] { "razorclasslibrary" });
var result = await MSBuildProcessManager.DotnetMSBuild(project);
Assert.BuildPassed(result);
var gzipCompressionDirectory = Path.Combine(project.IntermediateOutputDirectory, "build-gz");
Assert.DirectoryExists(result, gzipCompressionDirectory);
// Act
var thumbPrint = FileThumbPrint.CreateFolderThumbprint(project, gzipCompressionDirectory);
// Assert
for (var i = 0; i < 3; i++)
{
result = await MSBuildProcessManager.DotnetMSBuild(project);
Assert.BuildPassed(result);
var newThumbPrint = FileThumbPrint.CreateFolderThumbprint(project, gzipCompressionDirectory);
Assert.Equal(thumbPrint.Count, newThumbPrint.Count);
for (var j = 0; j < thumbPrint.Count; j++)
{
Assert.Equal(thumbPrint[j], newThumbPrint[j]);
}
}
}
[Fact]
public async Task Build_SatelliteAssembliesFileIsPreserved()
{

View File

@ -28,10 +28,14 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.webassembly.js");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "dotnet.wasm");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "dotnet.wasm.gz");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", DotNetJsFileName);
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "RazorClassLibrary.dll");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "System.Text.Json.dll.gz"); // Verify dependencies are part of the output.
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "System.dll");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "System.dll.gz");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazorwasm.pdb");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "RazorClassLibrary.pdb");
@ -55,10 +59,14 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.boot.json");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazor.webassembly.js");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "dotnet.wasm");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "dotnet.wasm.gz");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", DotNetJsFileName);
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazorwasm.dll");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "RazorClassLibrary.dll");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "System.Text.Json.dll"); // Verify dependencies are part of the output.
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "System.Text.Json.dll.gz");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "System.dll");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "System.dll.gz");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "blazorwasm.pdb");
Assert.FileExists(result, buildOutputDirectory, "wwwroot", "_framework", "RazorClassLibrary.pdb");

View File

@ -92,7 +92,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
var buildOutputDirectory = project.BuildOutputDirectory;
// Act
var compressedFilesFolder = Path.Combine("..", "blazorwasm", project.IntermediateOutputDirectory, "brotli");
var compressedFilesFolder = Path.Combine("..", "blazorwasm", project.IntermediateOutputDirectory, "compress");
var thumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
// Assert
@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
var buildOutputDirectory = project.BuildOutputDirectory;
// Act
var compressedFilesFolder = Path.Combine("..", "blazorwasm", project.IntermediateOutputDirectory, "brotli");
var compressedFilesFolder = Path.Combine("..", "blazorwasm", project.IntermediateOutputDirectory, "compress");
var thumbPrint = FileThumbPrint.CreateFolderThumbprint(project, compressedFilesFolder);
// Assert
@ -159,6 +159,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
var extension = Path.GetExtension(file);
if (extension != ".br" && extension != ".gz")
{
Assert.FileExists(result, file + ".gz");
Assert.FileExists(result, file + ".br");
}
}

View File

@ -208,7 +208,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
// Verify compression works
Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm.br");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.br"); //
Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.br"); //
// Verify static assets are in the publish directory
Assert.FileExists(result, blazorPublishDirectory, "index.html");
@ -311,6 +311,11 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.br");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.br");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm.gz");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll.gz");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.gz");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.gz");
VerifyServiceWorkerFiles(result, blazorPublishDirectory,
serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
serviceWorkerContent: "// This is the production service worker",
@ -445,6 +450,11 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.br");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.br");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm.gz");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll.gz");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.gz");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.gz");
VerifyServiceWorkerFiles(result, blazorPublishDirectory,
serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
serviceWorkerContent: "// This is the production service worker",
@ -645,6 +655,11 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.br");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.br");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "dotnet.wasm.gz");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "blazorwasm.dll.gz");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "RazorClassLibrary.dll.gz");
Assert.FileExists(result, blazorPublishDirectory, "_framework", "System.Text.Json.dll.gz");
VerifyServiceWorkerFiles(result, blazorPublishDirectory,
serviceWorkerPath: Path.Combine("serviceworkers", "my-service-worker.js"),
serviceWorkerContent: "// This is the production service worker",

View File

@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Razor.Tasks
var input = FilesToCompress[i];
var inputFullPath = input.GetMetadata("FullPath");
var relativePath = input.GetMetadata("RelativePath");
var outputRelativePath = Path.Combine(OutputDirectory, CalculateTargetPath(relativePath));
var outputRelativePath = Path.Combine(OutputDirectory, CalculateTargetPath(relativePath, ".br"));
var outputItem = new TaskItem(outputRelativePath);
input.CopyMetadataTo(outputItem);
@ -75,7 +75,7 @@ namespace Microsoft.AspNetCore.Razor.Tasks
return builder.ToString();
}
private static string CalculateTargetPath(string relativePath)
internal static string CalculateTargetPath(string relativePath, string extension)
{
// RelativePath can be long and if used as-is to write the output, might result in long path issues on Windows.
// Instead we'll calculate a fixed length path by hashing the input file name. This uses SHA1 similar to the Hash task in MSBuild
@ -92,7 +92,7 @@ namespace Microsoft.AspNetCore.Razor.Tasks
builder.Append(InvalidPathChars.Contains(c) ? '+' : c);
}
builder.Append(".br");
builder.Append(extension);
return builder.ToString();
}
}

View File

@ -0,0 +1,70 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace Microsoft.AspNetCore.Razor.Tasks
{
public class GZipCompress : Task
{
[Required]
public ITaskItem[] FilesToCompress { get; set; }
[Output]
public ITaskItem[] CompressedFiles { get; set; }
[Required]
public string OutputDirectory { get; set; }
public override bool Execute()
{
CompressedFiles = new ITaskItem[FilesToCompress.Length];
Directory.CreateDirectory(OutputDirectory);
System.Threading.Tasks.Parallel.For(0, FilesToCompress.Length, i =>
{
var file = FilesToCompress[i];
var inputPath = file.ItemSpec;
var relativePath = file.GetMetadata("RelativePath");
var outputRelativePath = Path.Combine(
OutputDirectory,
BrotliCompress.CalculateTargetPath(relativePath, ".gz"));
var outputItem = new TaskItem(outputRelativePath);
outputItem.SetMetadata("RelativePath", relativePath + ".gz");
CompressedFiles[i] = outputItem;
if (File.Exists(outputRelativePath) && File.GetLastWriteTimeUtc(inputPath) < File.GetLastWriteTimeUtc(outputRelativePath))
{
// Incrementalism. If input source doesn't exist or it exists and is not newer than the expected output, do nothing.
Log.LogMessage(MessageImportance.Low, $"Skipping '{inputPath}' because '{outputRelativePath}' is newer than '{inputPath}'.");
return;
}
try
{
using var sourceStream = File.OpenRead(inputPath);
using var fileStream = File.Create(outputRelativePath);
using var stream = new GZipStream(fileStream, CompressionLevel.Optimal);
sourceStream.CopyTo(stream);
}
catch (Exception e)
{
Log.LogErrorFromException(e);
return;
}
});
return !Log.HasLoggedErrors;
}
}
}

View File

@ -15,6 +15,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.BlazorWriteSatelliteAssemblyFile" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.BlazorReadSatelliteAssemblyFile" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.BrotliCompress" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.GzipCompress" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<UsingTask TaskName="Microsoft.AspNetCore.Razor.Tasks.CreateBlazorTrimmerRootDescriptorFile" AssemblyFile="$(RazorSdkBuildTasksAssembly)" />
<PropertyGroup>
@ -151,6 +152,30 @@ Copyright (c) .NET Foundation. All rights reserved.
</Target>
<Target Name="_ProcessBlazorWasmOutputs" DependsOnTargets="_ResolveBlazorWasmOutputs">
<PropertyGroup>
<_BlazorBuildGZipCompressDirectory>$(IntermediateOutputPath)build-gz\</_BlazorBuildGZipCompressDirectory>
</PropertyGroup>
<!--
Compress referenced binaries using GZip during build. This skips files such as the project's assemblies
that change from build to build. Runtime assets contribute to the bulk of the download size. Compressing it
has the most benefit while avoiding any ongoing costs to the dev inner loop.
-->
<ItemGroup>
<_GzipFileToCompressForBuild
Include="@(ReferenceCopyLocalPaths)"
RelativePath="$(_BlazorOutputPath)%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(FileName)%(Extension)"
Condition="'%(Extension)' == '.dll' or '%(ReferenceCopyLocalPaths.AssetType)' == 'native'" />
</ItemGroup>
<GZipCompress
FilesToCompress="@(_GzipFileToCompressForBuild)"
OutputDirectory="$(_BlazorBuildGZipCompressDirectory)">
<Output TaskParameter="CompressedFiles" ItemName="_BlazorBuildGZipCompressedFile" />
<Output TaskParameter="CompressedFiles" ItemName="FileWrites" />
</GZipCompress>
<ItemGroup>
<_BlazorWriteSatelliteAssembly Include="@(_BlazorOutputWithTargetPath->HasMetadata('Culture'))" />
@ -238,6 +263,15 @@ Copyright (c) .NET Foundation. All rights reserved.
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</_BlazorWebAssemblyStaticWebAsset>
<_BlazorWebAssemblyStaticWebAsset Include="@(_BlazorBuildGZipCompressedFile)">
<SourceId>$(PackageId)</SourceId>
<SourceType></SourceType>
<ContentRoot>$([MSBuild]::NormalizeDirectory('$(TargetDir)wwwroot\'))</ContentRoot>
<BasePath>$(StaticWebAssetBasePath)</BasePath>
<RelativePath>$([System.String]::Copy('%(_BlazorBuildGZipCompressedFile.RelativePath)').Replace('\','/').Substring(8))</RelativePath>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</_BlazorWebAssemblyStaticWebAsset>
<StaticWebAsset Include="@(_BlazorWebAssemblyStaticWebAsset)" />
<_ExternalStaticWebAsset Include="@(_BlazorWebAssemblyStaticWebAsset)" SourceType="Generated" />
</ItemGroup>
@ -305,6 +339,20 @@ Copyright (c) .NET Foundation. All rights reserved.
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
</Copy>
<Copy
SourceFiles="@(_BlazorBuildGZipCompressedFile)"
DestinationFiles="@(_BlazorBuildGZipCompressedFile->'$(OutDir)%(RelativePath)')"
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
ErrorIfLinkFails="$(ErrorIfLinkFailsForCopyFilesToOutputDirectory)">
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
</Copy>
</Target>
<Target Name="_BlazorWasmPrepareForLink" BeforeTargets="PrepareForILLink">
@ -411,12 +459,12 @@ Copyright (c) .NET Foundation. All rights reserved.
<Target Name="_BlazorCompressPublishFiles" AfterTargets="_ProcessPublishFilesForBlazor" Condition="'$(BlazorEnableCompression)' != 'false'">
<PropertyGroup>
<_CompressedFileOutputPath>$(IntermediateOutputPath)brotli\</_CompressedFileOutputPath>
<_CompressedFileOutputPath>$(IntermediateOutputPath)compress\</_CompressedFileOutputPath>
<_BlazorWebAssemblyBrotliIncremental>true</_BlazorWebAssemblyBrotliIncremental>
</PropertyGroup>
<ItemGroup>
<_BrotliFileToCompress
<_FileToCompress
Include="@(ResolvedFileToPublish)"
Condition="$([System.String]::Copy('%(ResolvedFileToPublish.RelativePath)').Replace('\','/').StartsWith('wwwroot/'))" />
</ItemGroup>
@ -427,7 +475,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<BrotliCompress
OutputDirectory="$(_CompressedFileOutputPath)"
FilesToCompress="@(_BrotliFileToCompress)"
FilesToCompress="@(_FileToCompress)"
CompressionLevel="$(_BlazorBrotliCompressionLevel)"
SkipIfOutputIsNewer="$(_BlazorWebAssemblyBrotliIncremental)"
ToolAssembly="$(_RazorSdkToolAssembly)">
@ -436,8 +484,17 @@ Copyright (c) .NET Foundation. All rights reserved.
<Output TaskParameter="CompressedFiles" ItemName="FileWrites" />
</BrotliCompress>
<GZipCompress
OutputDirectory="$(_CompressedFileOutputPath)"
FilesToCompress="@(_FileToCompress)">
<Output TaskParameter="CompressedFiles" ItemName="_BlazorPublishGZipCompressedFile" />
<Output TaskParameter="CompressedFiles" ItemName="FileWrites" />
</GZipCompress>
<ItemGroup>
<ResolvedFileToPublish Include="@(_BrotliCompressedFile)" />
<ResolvedFileToPublish Include="@(_BlazorPublishGZipCompressedFile)" />
</ItemGroup>
</Target>