зеркало из https://github.com/dotnet/msbuild.git
Merge remote-tracking branch 'upstream/main' into project-cache-vnext
This commit is contained in:
Коммит
6222f76864
|
@ -6,7 +6,6 @@
|
|||
<add key="dotnet-public" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json" />
|
||||
<add key="dotnet-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" />
|
||||
<add key="dotnet6" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json" />
|
||||
<add key="msbuild17.7" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/darc-pub-DotNet-msbuild-Trusted-5785ed5c/nuget/v3/index.json" />
|
||||
<add key="dotnet8" value="https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet8/nuget/v3/index.json" />
|
||||
<add key="dotnet8-transport" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8-transport/nuget/v3/index.json" />
|
||||
<add key="BuildXL" value="https://pkgs.dev.azure.com/ms/BuildXL/_packaging/BuildXL/nuget/v3/index.json" />
|
||||
|
|
|
@ -68,6 +68,9 @@
|
|||
<ItemGroup>
|
||||
<InstalledVersionedExtensions Include="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\**\*.targets" />
|
||||
<InstalledVersionedExtensions Include="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\**\*.props" />
|
||||
<InstalledVersionedExtensions Include="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\**\Tracker*.dll" />
|
||||
<InstalledVersionedExtensions Include="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\**\Tracker*.exe" />
|
||||
<InstalledVersionedExtensions Include="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\**\FileTracker*.dll" />
|
||||
<SdkResolverFiles Include="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Bin\SdkResolvers\Microsoft.DotNet.MSBuildSdkResolver\**\*.*" />
|
||||
<NuGetSdkResolverManifest Include= "$(RepoRoot)src\MSBuild\SdkResolvers\VS\Microsoft.Build.NuGetSdkResolver.xml" Condition="'$(MonoBuild)' != 'true'" />
|
||||
<NuGetSdkResolverManifest Include= "$(RepoRoot)src\MSBuild\SdkResolvers\Standalone\Microsoft.Build.NuGetSdkResolver.xml" Condition="'$(MonoBuild)' == 'true'" />
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Dependencies>
|
||||
<ProductDependencies>
|
||||
<Dependency Name="Microsoft.SourceBuild.Intermediate.source-build-reference-packages" Version="8.0.0-alpha.1.23381.3">
|
||||
<Dependency Name="Microsoft.SourceBuild.Intermediate.source-build-reference-packages" Version="8.0.0-alpha.1.23408.2">
|
||||
<Uri>https://github.com/dotnet/source-build-reference-packages</Uri>
|
||||
<Sha>5a1492557c8717b428b69fd4b7ca8c91d5d18cd3</Sha>
|
||||
<Sha>41f1a158d460e11ded6cffd6340f9e671e2b0a5c</Sha>
|
||||
<SourceBuild RepoName="source-build-reference-packages" ManagedOnly="true" />
|
||||
</Dependency>
|
||||
<!-- Necessary for source-build due to being a transitive dependency of System.Reflection.MetadataLoadContext.
|
||||
|
@ -43,33 +43,28 @@
|
|||
</Dependency>
|
||||
</ProductDependencies>
|
||||
<ToolsetDependencies>
|
||||
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.23378.2">
|
||||
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="8.0.0-beta.23404.2">
|
||||
<Uri>https://github.com/dotnet/arcade</Uri>
|
||||
<Sha>54dd37d44a2adfb8b966fac466c2ece40f8b20dd</Sha>
|
||||
<Sha>1d39647dd408f7afd99cce01f26bba1d6bdeb248</Sha>
|
||||
<SourceBuild RepoName="arcade" ManagedOnly="true" />
|
||||
</Dependency>
|
||||
<Dependency Name="Microsoft.SourceLink.GitHub" Version="8.0.0-beta.23211.2" CoherentParentDependency="Microsoft.DotNet.Arcade.Sdk">
|
||||
<Uri>https://github.com/dotnet/sourcelink</Uri>
|
||||
<Sha>4cf2eb17c295905edeca76a9afe6dda42988359e</Sha>
|
||||
<SourceBuild RepoName="sourcelink" ManagedOnly="true" />
|
||||
</Dependency>
|
||||
<Dependency Name="Microsoft.DotNet.XliffTasks" Version="1.0.0-beta.23374.1" CoherentParentDependency="Microsoft.DotNet.Arcade.Sdk">
|
||||
<Dependency Name="Microsoft.DotNet.XliffTasks" Version="1.0.0-beta.23381.1" CoherentParentDependency="Microsoft.DotNet.Arcade.Sdk">
|
||||
<Uri>https://github.com/dotnet/xliff-tasks</Uri>
|
||||
<Sha>a61cdec7a7f96c654b8c92bea0167df0427cc26c</Sha>
|
||||
<Sha>d3553ca27fb1c128f302f52b73c0079e65d62ea8</Sha>
|
||||
<SourceBuild RepoName="xliff-tasks" ManagedOnly="true" />
|
||||
</Dependency>
|
||||
<Dependency Name="NuGet.Build.Tasks" Version="6.8.0-preview.1.44">
|
||||
<Dependency Name="NuGet.Build.Tasks" Version="6.8.0-preview.1.56">
|
||||
<Uri>https://github.com/nuget/nuget.client</Uri>
|
||||
<Sha>c7035e0564fc33c43bf3f17b612a052e0a01c95b</Sha>
|
||||
<Sha>a39baac1e0fc3126a767b7261beb3804a28e4a97</Sha>
|
||||
</Dependency>
|
||||
<Dependency Name="Microsoft.Net.Compilers.Toolset" Version="4.8.0-1.23378.8">
|
||||
<Dependency Name="Microsoft.Net.Compilers.Toolset" Version="4.8.0-1.23406.1">
|
||||
<Uri>https://github.com/dotnet/roslyn</Uri>
|
||||
<Sha>f5b6c715a742c56b7cc672e47385508fb4df98cc</Sha>
|
||||
<Sha>e3ede0e8fee242f6bf988f3c71a6ba5e8217faa3</Sha>
|
||||
<SourceBuild RepoName="roslyn" ManagedOnly="true" />
|
||||
</Dependency>
|
||||
<Dependency Name="Microsoft.DotNet.XUnitExtensions" Version="8.0.0-beta.23378.2">
|
||||
<Dependency Name="Microsoft.DotNet.XUnitExtensions" Version="8.0.0-beta.23404.2">
|
||||
<Uri>https://github.com/dotnet/arcade</Uri>
|
||||
<Sha>54dd37d44a2adfb8b966fac466c2ece40f8b20dd</Sha>
|
||||
<Sha>1d39647dd408f7afd99cce01f26bba1d6bdeb248</Sha>
|
||||
</Dependency>
|
||||
</ToolsetDependencies>
|
||||
</Dependencies>
|
||||
|
|
|
@ -48,11 +48,11 @@
|
|||
Otherwise, this version of dotnet will not be installed and the build will error out. -->
|
||||
<DotNetCliVersion>$([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)..\global.json')), '"dotnet": "([^"]*)"').Groups.get_Item(1))</DotNetCliVersion>
|
||||
<MicrosoftCodeAnalysisCollectionsVersion>4.2.0-1.22102.8</MicrosoftCodeAnalysisCollectionsVersion>
|
||||
<MicrosoftDotNetXUnitExtensionsVersion>8.0.0-beta.23378.2</MicrosoftDotNetXUnitExtensionsVersion>
|
||||
<MicrosoftDotNetXUnitExtensionsVersion>8.0.0-beta.23404.2</MicrosoftDotNetXUnitExtensionsVersion>
|
||||
<MicrosoftExtensionsDependencyModelVersion>7.0.0</MicrosoftExtensionsDependencyModelVersion>
|
||||
<MicrosoftIORedistVersion>6.0.0</MicrosoftIORedistVersion>
|
||||
<MicrosoftNetCompilersToolsetVersion>4.8.0-1.23378.8</MicrosoftNetCompilersToolsetVersion>
|
||||
<NuGetBuildTasksVersion>6.8.0-preview.1.44</NuGetBuildTasksVersion>
|
||||
<MicrosoftNetCompilersToolsetVersion>4.8.0-1.23406.1</MicrosoftNetCompilersToolsetVersion>
|
||||
<NuGetBuildTasksVersion>6.8.0-preview.1.56</NuGetBuildTasksVersion>
|
||||
<SystemRuntimeCompilerServicesUnsafeVersion>6.0.0</SystemRuntimeCompilerServicesUnsafeVersion>
|
||||
<SystemTextJsonVersion>7.0.3</SystemTextJsonVersion>
|
||||
<SystemThreadingTasksDataflowVersion>7.0.0</SystemThreadingTasksDataflowVersion>
|
||||
|
|
Двоичный файл не отображается.
|
@ -35,31 +35,33 @@ try {
|
|||
param(
|
||||
[string] $PackagePath # Full path to a NuGet package
|
||||
)
|
||||
|
||||
|
||||
if (!(Test-Path $PackagePath)) {
|
||||
Write-PipelineTelemetryError -Category 'Build' -Message "Input file does not exist: $PackagePath"
|
||||
ExitWithExitCode 1
|
||||
}
|
||||
|
||||
|
||||
$RelevantExtensions = @('.dll', '.exe', '.pdb')
|
||||
Write-Host -NoNewLine 'Extracting ' ([System.IO.Path]::GetFileName($PackagePath)) '...'
|
||||
|
||||
|
||||
$PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)
|
||||
$ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageId
|
||||
|
||||
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
|
||||
|
||||
[System.IO.Directory]::CreateDirectory($ExtractPath);
|
||||
|
||||
|
||||
try {
|
||||
$zip = [System.IO.Compression.ZipFile]::OpenRead($PackagePath)
|
||||
|
||||
$zip.Entries |
|
||||
Where-Object {$RelevantExtensions -contains [System.IO.Path]::GetExtension($_.Name)} |
|
||||
ForEach-Object {
|
||||
$TargetFile = Join-Path -Path $ExtractPath -ChildPath $_.Name
|
||||
|
||||
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile, $true)
|
||||
$TargetPath = Join-Path -Path $ExtractPath -ChildPath (Split-Path -Path $_.FullName)
|
||||
[System.IO.Directory]::CreateDirectory($TargetPath);
|
||||
|
||||
$TargetFile = Join-Path -Path $ExtractPath -ChildPath $_.FullName
|
||||
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile)
|
||||
}
|
||||
}
|
||||
catch {
|
||||
|
|
|
@ -118,3 +118,12 @@ steps:
|
|||
artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt)
|
||||
continueOnError: true
|
||||
condition: succeededOrFailed()
|
||||
|
||||
# Manually inject component detection so that we can ignore the source build upstream cache, which contains
|
||||
# a nupkg cache of input packages (a local feed).
|
||||
# This path must match the upstream cache path in property 'CurrentRepoSourceBuiltNupkgCacheDir'
|
||||
# in src\Microsoft.DotNet.Arcade.Sdk\tools\SourceBuild\SourceBuildArcade.targets
|
||||
- task: ComponentGovernanceComponentDetection@0
|
||||
displayName: Component Detection (Exclude upstream cache)
|
||||
inputs:
|
||||
ignoreDirectories: '$(Build.SourcesDirectory)/artifacts/source-build/self/src/artifacts/obj/source-built-upstream-cache'
|
||||
|
|
|
@ -13,12 +13,15 @@
|
|||
<PackageVersion Include="BenchmarkDotNet" Version="0.13.1" />
|
||||
<PackageVersion Update="BenchmarkDotNet" Condition="'$(BenchmarkDotNetVersion)' != ''" Version="$(BenchmarkDotNetVersion)" />
|
||||
|
||||
<PackageVersion Include="Microsoft.BuildXL.Processes" Version="0.1.0-20230727.4.2" />
|
||||
<PackageVersion Update="Microsoft.BuildXL.Processes" Condition="'$(BuildXLProcessesVersion)' != ''" Version="$(BuildXLProcessesVersion)" />
|
||||
<PackageVersion Include="FluentAssertions" Version="6.11.0" />
|
||||
<PackageVersion Update="FluentAssertions" Condition="'$(FluentAssertionsVersion)' != ''" Version="$(FluentAssertionsVersion)" />
|
||||
|
||||
<PackageVersion Include="LargeAddressAware" Version="1.0.5" />
|
||||
<PackageVersion Update="LargeAddressAware" Condition="'$(LargeAddressAwareVersion)' != ''" Version="$(LargeAddressAwareVersion)" />
|
||||
|
||||
<PackageVersion Include="Microsoft.BuildXL.Processes" Version="0.1.0-20230727.4.2" />
|
||||
<PackageVersion Update="Microsoft.BuildXL.Processes" Condition="'$(BuildXLProcessesVersion)' != ''" Version="$(BuildXLProcessesVersion)" />
|
||||
|
||||
<PackageVersion Include="Microsoft.VisualStudio.Setup.Configuration.Interop" Version="3.2.2146" PrivateAssets="All" />
|
||||
<PackageVersion Update="Microsoft.VisualStudio.Setup.Configuration.Interop" Condition="'$(MicrosoftVisualStudioSetupConfigurationInteropVersion)' != ''" Version="$(MicrosoftVisualStudioSetupConfigurationInteropVersion)" PrivateAssets="All" />
|
||||
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
"xcopy-msbuild": "17.6.0-2"
|
||||
},
|
||||
"msbuild-sdks": {
|
||||
"Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23378.2"
|
||||
"Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.23404.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,36 +181,6 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
Assert.Equal(value, deserializedValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests serializing using the DotNet serializer.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void TestSerializeDotNet()
|
||||
{
|
||||
ArgumentNullException value = new ArgumentNullException("The argument was null", new InsufficientMemoryException());
|
||||
TranslationHelpers.GetWriteTranslator().TranslateDotNet(ref value);
|
||||
|
||||
ArgumentNullException deserializedValue = null;
|
||||
TranslationHelpers.GetReadTranslator().TranslateDotNet(ref deserializedValue);
|
||||
|
||||
Assert.True(TranslationHelpers.CompareExceptions(value, deserializedValue, out string diffReason), diffReason);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests serializing using the DotNet serializer passing in null.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void TestSerializeDotNetNull()
|
||||
{
|
||||
ArgumentNullException value = null;
|
||||
TranslationHelpers.GetWriteTranslator().TranslateDotNet(ref value);
|
||||
|
||||
ArgumentNullException deserializedValue = null;
|
||||
TranslationHelpers.GetReadTranslator().TranslateDotNet(ref deserializedValue);
|
||||
|
||||
Assert.True(TranslationHelpers.CompareExceptions(value, deserializedValue, out string diffReason), diffReason);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestSerializeException()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.Build.BackEnd.Logging;
|
||||
using Microsoft.Build.Evaluation;
|
||||
using Microsoft.Build.Execution;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Shared;
|
||||
using Microsoft.Build.UnitTests;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.NetCore.Extensions;
|
||||
using static Microsoft.Build.UnitTests.ObjectModelHelpers;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Microsoft.Build.Engine.UnitTests.BackEnd
|
||||
{
|
||||
public class BuildManager_Logging_Tests : IDisposable
|
||||
{
|
||||
private string _mainProject = @"
|
||||
<Project>
|
||||
|
||||
<Target Name=`MainTarget`>
|
||||
<MSBuild Projects=`{0}` Targets=`ChildTarget` />
|
||||
</Target>
|
||||
|
||||
</Project>";
|
||||
|
||||
private string _childProjectWithCustomBuildEvent = $@"
|
||||
<Project>
|
||||
|
||||
<UsingTask TaskName=""CustomBuildEventTask"" AssemblyFile=""{Assembly.GetExecutingAssembly().Location}"" />
|
||||
<Target Name=`ChildTarget`>
|
||||
<CustomBuildEventTask />
|
||||
</Target>
|
||||
|
||||
</Project>";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The mock logger for testing.
|
||||
/// </summary>
|
||||
private readonly MockLogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// The standard build manager for each test.
|
||||
/// </summary>
|
||||
private readonly BuildManager _buildManager;
|
||||
|
||||
/// <summary>
|
||||
/// The project collection used.
|
||||
/// </summary>
|
||||
private readonly ProjectCollection _projectCollection;
|
||||
|
||||
private readonly TestEnvironment _env;
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
/// <summary>
|
||||
/// SetUp
|
||||
/// </summary>
|
||||
public BuildManager_Logging_Tests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
// Ensure that any previous tests which may have been using the default BuildManager do not conflict with us.
|
||||
BuildManager.DefaultBuildManager.Dispose();
|
||||
|
||||
_logger = new MockLogger(output);
|
||||
_buildManager = new BuildManager();
|
||||
_projectCollection = new ProjectCollection();
|
||||
|
||||
_env = TestEnvironment.Create(output);
|
||||
}
|
||||
|
||||
[DotNetOnlyTheory]
|
||||
[InlineData("1", true)]
|
||||
[InlineData("0", false)]
|
||||
[InlineData(null, true)]
|
||||
public void Build_WithCustomBuildArgs_NetCore(string envVariableValue, bool isWarningExpected)
|
||||
=> TestCustomEventWarning<BuildErrorEventArgs>(envVariableValue, isWarningExpected);
|
||||
|
||||
[WindowsFullFrameworkOnlyTheory]
|
||||
[InlineData("1", true)]
|
||||
[InlineData("0", false)]
|
||||
[InlineData(null, false)]
|
||||
public void Build_WithCustomBuildArgs_Framework(string envVariableValue, bool isWarningExpected) =>
|
||||
TestCustomEventWarning<BuildWarningEventArgs>(envVariableValue, isWarningExpected);
|
||||
|
||||
private void TestCustomEventWarning<T>(string envVariableValue, bool isWarningExpected) where T : LazyFormattedBuildEventArgs
|
||||
{
|
||||
var testFiles = _env.CreateTestProjectWithFiles(string.Empty, new[] { "main", "child1" }, string.Empty);
|
||||
|
||||
ILoggingService service = LoggingService.CreateLoggingService(LoggerMode.Synchronous, 1);
|
||||
service.RegisterLogger(_logger);
|
||||
|
||||
_env.SetEnvironmentVariable("MSBUILDCUSTOMBUILDEVENTWARNING", envVariableValue);
|
||||
_env.SetEnvironmentVariable("MSBUILDNOINPROCNODE", "1");
|
||||
|
||||
_buildManager.BeginBuild(BuildParameters);
|
||||
|
||||
try
|
||||
{
|
||||
var child1ProjectPath = testFiles.CreatedFiles[1];
|
||||
var cleanedUpChildContents = CleanupFileContents(_childProjectWithCustomBuildEvent);
|
||||
File.WriteAllText(child1ProjectPath, cleanedUpChildContents);
|
||||
|
||||
var mainProjectPath = testFiles.CreatedFiles[0];
|
||||
var cleanedUpMainContents = CleanupFileContents(string.Format(_mainProject, child1ProjectPath));
|
||||
File.WriteAllText(mainProjectPath, cleanedUpMainContents);
|
||||
|
||||
var buildRequestData = new BuildRequestData(
|
||||
mainProjectPath,
|
||||
new Dictionary<string, string>(),
|
||||
MSBuildConstants.CurrentToolsVersion,
|
||||
new[] { "MainTarget" },
|
||||
null);
|
||||
|
||||
var submission = _buildManager.PendBuildRequest(buildRequestData);
|
||||
var result = submission.Execute();
|
||||
var allEvents = _logger.AllBuildEvents;
|
||||
|
||||
if (isWarningExpected)
|
||||
{
|
||||
allEvents.OfType<T>().ShouldHaveSingleItem();
|
||||
allEvents.First(x => x is T).Message.ShouldContain(
|
||||
string.Format(ResourceUtilities.GetResourceString("DeprecatedEventSerialization"),
|
||||
"MyCustomBuildEventArgs"));
|
||||
}
|
||||
else
|
||||
{
|
||||
allEvents.OfType<T>().ShouldBeEmpty();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_buildManager.EndBuild();
|
||||
}
|
||||
}
|
||||
|
||||
private BuildParameters BuildParameters => new BuildParameters(_projectCollection)
|
||||
{
|
||||
DisableInProcNode = true,
|
||||
EnableNodeReuse = false,
|
||||
Loggers = new ILogger[] { _logger }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// TearDown
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_buildManager.Dispose();
|
||||
_projectCollection.Dispose();
|
||||
_env.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Microsoft.Build.UnitTests
|
||||
{
|
||||
public class CustomBuildEventTask : Task
|
||||
{
|
||||
public override bool Execute()
|
||||
{
|
||||
MyCustomBuildEventArgs customBuildEvent = new() { RawMessage = "A message from MyCustomBuildEventArgs" };
|
||||
BuildEngine.LogCustomEvent(customBuildEvent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class MyCustomBuildEventArgs : CustomBuildEventArgs { }
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Build.BackEnd;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Shared;
|
||||
|
@ -57,8 +58,21 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
ProjectStartedEventArgs projectStarted = new ProjectStartedEventArgs(-1, "message", "help", "ProjectFile", "targetNames", null, null, null);
|
||||
ProjectFinishedEventArgs projectFinished = new ProjectFinishedEventArgs("message", "help", "ProjectFile", true);
|
||||
ExternalProjectStartedEventArgs externalStartedEvent = new ExternalProjectStartedEventArgs("message", "help", "senderName", "projectFile", "targetNames");
|
||||
ExternalProjectFinishedEventArgs externalFinishedEvent = new("message", "help", "senderName", "projectFile", true);
|
||||
ProjectEvaluationStartedEventArgs evaluationStarted = new ProjectEvaluationStartedEventArgs();
|
||||
ProjectEvaluationFinishedEventArgs evaluationFinished = new ProjectEvaluationFinishedEventArgs();
|
||||
AssemblyLoadBuildEventArgs assemblyLoad = new(AssemblyLoadingContext.Evaluation, null, null, "path", Guid.NewGuid(), null);
|
||||
ExtendedBuildErrorEventArgs extError = new("extError", "SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender");
|
||||
ExtendedBuildWarningEventArgs extWarning = new("extWarn", "SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender");
|
||||
ExtendedBuildMessageEventArgs extMessage = new("extMsg", "SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender", MessageImportance.Normal);
|
||||
ExtendedCustomBuildEventArgs extCustom = new("extCustom", "message", "help", "sender");
|
||||
CriticalBuildMessageEventArgs criticalMessage = new("Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "Sender", DateTime.Now, "arg1");
|
||||
PropertyInitialValueSetEventArgs propInit = new("prop", "val", "propsource", "message", "help", "sender", MessageImportance.Normal);
|
||||
MetaprojectGeneratedEventArgs metaProjectGenerated = new("metaName", "path", "message");
|
||||
PropertyReassignmentEventArgs propReassign = new("prop", "prevValue", "newValue", "loc", "message", "help", "sender", MessageImportance.Normal);
|
||||
ResponseFileUsedEventArgs responseFileUsed = new("path");
|
||||
UninitializedPropertyReadEventArgs uninitializedPropertyRead = new("prop", "message", "help", "sender", MessageImportance.Normal);
|
||||
EnvironmentVariableReadEventArgs environmentVariableRead = new("env", "message", "help", "sender", MessageImportance.Normal);
|
||||
|
||||
VerifyLoggingPacket(buildFinished, LoggingEventType.BuildFinishedEvent);
|
||||
VerifyLoggingPacket(buildStarted, LoggingEventType.BuildStartedEvent);
|
||||
|
@ -76,7 +90,20 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
VerifyLoggingPacket(projectFinished, LoggingEventType.ProjectFinishedEvent);
|
||||
VerifyLoggingPacket(evaluationStarted, LoggingEventType.ProjectEvaluationStartedEvent);
|
||||
VerifyLoggingPacket(evaluationFinished, LoggingEventType.ProjectEvaluationFinishedEvent);
|
||||
VerifyLoggingPacket(externalStartedEvent, LoggingEventType.CustomEvent);
|
||||
VerifyLoggingPacket(externalStartedEvent, LoggingEventType.ExternalProjectStartedEvent);
|
||||
VerifyLoggingPacket(externalFinishedEvent, LoggingEventType.ExternalProjectFinishedEvent);
|
||||
VerifyLoggingPacket(assemblyLoad, LoggingEventType.AssemblyLoadEvent);
|
||||
VerifyLoggingPacket(extError, LoggingEventType.ExtendedBuildErrorEvent);
|
||||
VerifyLoggingPacket(extWarning, LoggingEventType.ExtendedBuildWarningEvent);
|
||||
VerifyLoggingPacket(extMessage, LoggingEventType.ExtendedBuildMessageEvent);
|
||||
VerifyLoggingPacket(extCustom, LoggingEventType.ExtendedCustomEvent);
|
||||
VerifyLoggingPacket(criticalMessage, LoggingEventType.CriticalBuildMessage);
|
||||
VerifyLoggingPacket(propInit, LoggingEventType.PropertyInitialValueSet);
|
||||
VerifyLoggingPacket(metaProjectGenerated, LoggingEventType.MetaprojectGenerated);
|
||||
VerifyLoggingPacket(propReassign, LoggingEventType.PropertyReassignment);
|
||||
VerifyLoggingPacket(responseFileUsed, LoggingEventType.ResponseFileUsedEvent);
|
||||
VerifyLoggingPacket(uninitializedPropertyRead, LoggingEventType.UninitializedPropertyRead);
|
||||
VerifyLoggingPacket(environmentVariableRead, LoggingEventType.EnvironmentVariableReadEvent);
|
||||
}
|
||||
|
||||
private static BuildEventContext CreateBuildEventContext()
|
||||
|
@ -218,6 +245,13 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
{
|
||||
BuildEventArgs[] testArgs = new BuildEventArgs[]
|
||||
{
|
||||
new ResponseFileUsedEventArgs("path"),
|
||||
new UninitializedPropertyReadEventArgs("prop", "message", "help", "sender", MessageImportance.Normal),
|
||||
new EnvironmentVariableReadEventArgs("env", "message", "help", "sender", MessageImportance.Normal) { BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6) },
|
||||
new PropertyReassignmentEventArgs("prop", "prevValue", "newValue", "loc", "message", "help", "sender", MessageImportance.Normal),
|
||||
new PropertyInitialValueSetEventArgs("prop", "val", "propsource", "message", "help", "sender", MessageImportance.Normal),
|
||||
new MetaprojectGeneratedEventArgs("metaName", "path", "message"),
|
||||
new CriticalBuildMessageEventArgs("Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "Sender", DateTime.Now, "arg1"),
|
||||
new BuildFinishedEventArgs("Message", "Keyword", true),
|
||||
new BuildStartedEventArgs("Message", "Help"),
|
||||
new BuildMessageEventArgs("Message", "help", "sender", MessageImportance.Low),
|
||||
|
@ -236,11 +270,36 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
new ProjectStartedEventArgs(-1, "message", "help", "ProjectFile", "targetNames", null, null, null),
|
||||
new ProjectFinishedEventArgs("message", "help", "ProjectFile", true),
|
||||
new ExternalProjectStartedEventArgs("message", "help", "senderName", "projectFile", "targetNames"),
|
||||
new ExternalProjectFinishedEventArgs("message", "help", "senderName", "projectFile", true),
|
||||
CreateProjectEvaluationStarted(),
|
||||
CreateProjectEvaluationFinished(),
|
||||
CreateTargetSkipped()
|
||||
new AssemblyLoadBuildEventArgs(AssemblyLoadingContext.Evaluation, "init", "aname", "path", Guid.NewGuid(), "domain", MessageImportance.Normal),
|
||||
CreateTargetSkipped(),
|
||||
new ExtendedBuildErrorEventArgs("extError", "SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender", DateTime.UtcNow, "arg1")
|
||||
{
|
||||
ExtendedData = "{'long-json':'mostly-strings'}",
|
||||
ExtendedMetadata = new Dictionary<string, string> { { "m1", "v1" }, { "m2", "v2" } },
|
||||
BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7)
|
||||
},
|
||||
new ExtendedBuildWarningEventArgs("extWarn", "SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender", DateTime.UtcNow, "arg1")
|
||||
{
|
||||
ExtendedData = "{'long-json':'mostly-strings'}",
|
||||
ExtendedMetadata = new Dictionary<string, string> { { "m1", "v1" }, { "m2", "v2" } },
|
||||
BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7)
|
||||
},
|
||||
new ExtendedBuildMessageEventArgs("extWarn", "SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender", MessageImportance.Normal, DateTime.UtcNow, "arg1")
|
||||
{
|
||||
ExtendedData = "{'long-json':'mostly-strings'}",
|
||||
ExtendedMetadata = new Dictionary<string, string> { { "m1", "v1" }, { "m2", "v2" } },
|
||||
BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7)
|
||||
},
|
||||
new ExtendedCustomBuildEventArgs("extCustom", "message", "help", "sender", DateTime.UtcNow, "arg1")
|
||||
{
|
||||
ExtendedData = "{'long-json':'mostly-strings'}",
|
||||
ExtendedMetadata = new Dictionary<string, string> { { "m1", "v1" }, { "m2", "v2" } },
|
||||
BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7)
|
||||
},
|
||||
};
|
||||
|
||||
foreach (BuildEventArgs arg in testArgs)
|
||||
{
|
||||
LogMessagePacket packet = new LogMessagePacket(new KeyValuePair<int, BuildEventArgs>(0, arg));
|
||||
|
@ -250,7 +309,17 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
|
||||
LogMessagePacket deserializedPacket = tempPacket as LogMessagePacket;
|
||||
|
||||
CompareLogMessagePackets(packet, deserializedPacket);
|
||||
packet.Should().BeEquivalentTo(deserializedPacket, options => options
|
||||
.RespectingRuntimeTypes());
|
||||
|
||||
BuildEventArgs args = packet.NodeBuildEvent?.Value;
|
||||
BuildEventArgs desArgs = deserializedPacket?.NodeBuildEvent?.Value;
|
||||
desArgs.Should().BeEquivalentTo(args, options => options
|
||||
.RespectingRuntimeTypes()
|
||||
// Since we use struct DictionaryEntry of class TaskItemData, generated DictionaryEntry.Equals compare TaskItemData by references.
|
||||
// Bellow will instruct equivalency test to not use DictionaryEntry.Equals but its public members for equivalency tests.
|
||||
.ComparingByMembers<DictionaryEntry>()
|
||||
.WithTracing(), "Roundtrip deserialization of message type {0} should be equivalent", args.GetType().Name);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
@ -273,249 +342,6 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
Assert.True(Object.ReferenceEquals(buildEvent, packet.NodeBuildEvent.Value.Value)); // "Expected buildEvent to have the same object reference as packet.BuildEvent"
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two BuildEventArgs objects for equivalence.
|
||||
/// </summary>
|
||||
private void CompareNodeBuildEventArgs(KeyValuePair<int, BuildEventArgs> leftTuple, KeyValuePair<int, BuildEventArgs> rightTuple, bool expectInvalidBuildEventContext)
|
||||
{
|
||||
BuildEventArgs left = leftTuple.Value;
|
||||
BuildEventArgs right = rightTuple.Value;
|
||||
|
||||
if (expectInvalidBuildEventContext)
|
||||
{
|
||||
Assert.Equal(BuildEventContext.Invalid, right.BuildEventContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(left.BuildEventContext, right.BuildEventContext);
|
||||
}
|
||||
|
||||
Assert.Equal(leftTuple.Key, rightTuple.Key);
|
||||
Assert.Equal(left.HelpKeyword, right.HelpKeyword);
|
||||
Assert.Equal(left.Message, right.Message);
|
||||
Assert.Equal(left.SenderName, right.SenderName);
|
||||
Assert.Equal(left.ThreadId, right.ThreadId);
|
||||
Assert.Equal(left.Timestamp, right.Timestamp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares two LogMessagePacket objects for equivalence.
|
||||
/// </summary>
|
||||
private void CompareLogMessagePackets(LogMessagePacket left, LogMessagePacket right)
|
||||
{
|
||||
Assert.Equal(left.EventType, right.EventType);
|
||||
Assert.Equal(left.NodeBuildEvent.Value.Value.GetType(), right.NodeBuildEvent.Value.Value.GetType());
|
||||
|
||||
CompareNodeBuildEventArgs(left.NodeBuildEvent.Value, right.NodeBuildEvent.Value, left.EventType == LoggingEventType.CustomEvent /* expectInvalidBuildEventContext */);
|
||||
|
||||
switch (left.EventType)
|
||||
{
|
||||
case LoggingEventType.BuildErrorEvent:
|
||||
BuildErrorEventArgs leftError = left.NodeBuildEvent.Value.Value as BuildErrorEventArgs;
|
||||
BuildErrorEventArgs rightError = right.NodeBuildEvent.Value.Value as BuildErrorEventArgs;
|
||||
Assert.NotNull(leftError);
|
||||
Assert.NotNull(rightError);
|
||||
Assert.Equal(leftError.Code, rightError.Code);
|
||||
Assert.Equal(leftError.ColumnNumber, rightError.ColumnNumber);
|
||||
Assert.Equal(leftError.EndColumnNumber, rightError.EndColumnNumber);
|
||||
Assert.Equal(leftError.EndLineNumber, rightError.EndLineNumber);
|
||||
Assert.Equal(leftError.File, rightError.File);
|
||||
Assert.Equal(leftError.LineNumber, rightError.LineNumber);
|
||||
Assert.Equal(leftError.Message, rightError.Message);
|
||||
Assert.Equal(leftError.Subcategory, rightError.Subcategory);
|
||||
break;
|
||||
|
||||
case LoggingEventType.BuildFinishedEvent:
|
||||
BuildFinishedEventArgs leftFinished = left.NodeBuildEvent.Value.Value as BuildFinishedEventArgs;
|
||||
BuildFinishedEventArgs rightFinished = right.NodeBuildEvent.Value.Value as BuildFinishedEventArgs;
|
||||
Assert.NotNull(leftFinished);
|
||||
Assert.NotNull(rightFinished);
|
||||
Assert.Equal(leftFinished.Succeeded, rightFinished.Succeeded);
|
||||
break;
|
||||
|
||||
case LoggingEventType.BuildMessageEvent:
|
||||
BuildMessageEventArgs leftMessage = left.NodeBuildEvent.Value.Value as BuildMessageEventArgs;
|
||||
BuildMessageEventArgs rightMessage = right.NodeBuildEvent.Value.Value as BuildMessageEventArgs;
|
||||
Assert.NotNull(leftMessage);
|
||||
Assert.NotNull(rightMessage);
|
||||
Assert.Equal(leftMessage.Importance, rightMessage.Importance);
|
||||
break;
|
||||
|
||||
case LoggingEventType.BuildStartedEvent:
|
||||
BuildStartedEventArgs leftBuildStart = left.NodeBuildEvent.Value.Value as BuildStartedEventArgs;
|
||||
BuildStartedEventArgs rightBuildStart = right.NodeBuildEvent.Value.Value as BuildStartedEventArgs;
|
||||
Assert.NotNull(leftBuildStart);
|
||||
Assert.NotNull(rightBuildStart);
|
||||
break;
|
||||
|
||||
case LoggingEventType.BuildWarningEvent:
|
||||
BuildWarningEventArgs leftBuildWarn = left.NodeBuildEvent.Value.Value as BuildWarningEventArgs;
|
||||
BuildWarningEventArgs rightBuildWarn = right.NodeBuildEvent.Value.Value as BuildWarningEventArgs;
|
||||
Assert.NotNull(leftBuildWarn);
|
||||
Assert.NotNull(rightBuildWarn);
|
||||
Assert.Equal(leftBuildWarn.Code, rightBuildWarn.Code);
|
||||
Assert.Equal(leftBuildWarn.ColumnNumber, rightBuildWarn.ColumnNumber);
|
||||
Assert.Equal(leftBuildWarn.EndColumnNumber, rightBuildWarn.EndColumnNumber);
|
||||
Assert.Equal(leftBuildWarn.EndLineNumber, rightBuildWarn.EndLineNumber);
|
||||
Assert.Equal(leftBuildWarn.File, rightBuildWarn.File);
|
||||
Assert.Equal(leftBuildWarn.LineNumber, rightBuildWarn.LineNumber);
|
||||
Assert.Equal(leftBuildWarn.Subcategory, rightBuildWarn.Subcategory);
|
||||
break;
|
||||
|
||||
case LoggingEventType.CustomEvent:
|
||||
ExternalProjectStartedEventArgs leftCustom = left.NodeBuildEvent.Value.Value as ExternalProjectStartedEventArgs;
|
||||
ExternalProjectStartedEventArgs rightCustom = right.NodeBuildEvent.Value.Value as ExternalProjectStartedEventArgs;
|
||||
Assert.NotNull(leftCustom);
|
||||
Assert.NotNull(rightCustom);
|
||||
Assert.Equal(leftCustom.ProjectFile, rightCustom.ProjectFile);
|
||||
Assert.Equal(leftCustom.TargetNames, rightCustom.TargetNames);
|
||||
break;
|
||||
|
||||
case LoggingEventType.ProjectFinishedEvent:
|
||||
ProjectFinishedEventArgs leftProjectFinished = left.NodeBuildEvent.Value.Value as ProjectFinishedEventArgs;
|
||||
ProjectFinishedEventArgs rightProjectFinished = right.NodeBuildEvent.Value.Value as ProjectFinishedEventArgs;
|
||||
Assert.NotNull(leftProjectFinished);
|
||||
Assert.NotNull(rightProjectFinished);
|
||||
Assert.Equal(leftProjectFinished.ProjectFile, rightProjectFinished.ProjectFile);
|
||||
Assert.Equal(leftProjectFinished.Succeeded, rightProjectFinished.Succeeded);
|
||||
break;
|
||||
|
||||
case LoggingEventType.ProjectStartedEvent:
|
||||
ProjectStartedEventArgs leftProjectStarted = left.NodeBuildEvent.Value.Value as ProjectStartedEventArgs;
|
||||
ProjectStartedEventArgs rightProjectStarted = right.NodeBuildEvent.Value.Value as ProjectStartedEventArgs;
|
||||
Assert.NotNull(leftProjectStarted);
|
||||
Assert.NotNull(rightProjectStarted);
|
||||
Assert.Equal(leftProjectStarted.ParentProjectBuildEventContext, rightProjectStarted.ParentProjectBuildEventContext);
|
||||
Assert.Equal(leftProjectStarted.ProjectFile, rightProjectStarted.ProjectFile);
|
||||
Assert.Equal(leftProjectStarted.ProjectId, rightProjectStarted.ProjectId);
|
||||
Assert.Equal(leftProjectStarted.TargetNames, rightProjectStarted.TargetNames);
|
||||
|
||||
// UNDONE: (Serialization.) We don't actually serialize the items at this time.
|
||||
// Assert.AreEqual(leftProjectStarted.Items, rightProjectStarted.Items);
|
||||
// UNDONE: (Serialization.) We don't actually serialize properties at this time.
|
||||
// Assert.AreEqual(leftProjectStarted.Properties, rightProjectStarted.Properties);
|
||||
break;
|
||||
|
||||
case LoggingEventType.ProjectEvaluationStartedEvent:
|
||||
ProjectEvaluationStartedEventArgs leftEvaluationStarted = left.NodeBuildEvent.Value.Value as ProjectEvaluationStartedEventArgs;
|
||||
ProjectEvaluationStartedEventArgs rightEvaluationStarted = right.NodeBuildEvent.Value.Value as ProjectEvaluationStartedEventArgs;
|
||||
Assert.NotNull(leftEvaluationStarted);
|
||||
Assert.NotNull(rightEvaluationStarted);
|
||||
Assert.Equal(leftEvaluationStarted.ProjectFile, rightEvaluationStarted.ProjectFile);
|
||||
break;
|
||||
|
||||
case LoggingEventType.ProjectEvaluationFinishedEvent:
|
||||
ProjectEvaluationFinishedEventArgs leftEvaluationFinished = left.NodeBuildEvent.Value.Value as ProjectEvaluationFinishedEventArgs;
|
||||
ProjectEvaluationFinishedEventArgs rightEvaluationFinished = right.NodeBuildEvent.Value.Value as ProjectEvaluationFinishedEventArgs;
|
||||
Assert.NotNull(leftEvaluationFinished);
|
||||
Assert.NotNull(rightEvaluationFinished);
|
||||
Assert.Equal(leftEvaluationFinished.ProjectFile, rightEvaluationFinished.ProjectFile);
|
||||
Assert.Equal(leftEvaluationFinished.ProfilerResult, rightEvaluationFinished.ProfilerResult);
|
||||
Assert.Equal(
|
||||
TranslationHelpers.GetPropertiesString(leftEvaluationFinished.GlobalProperties),
|
||||
TranslationHelpers.GetPropertiesString(rightEvaluationFinished.GlobalProperties));
|
||||
Assert.Equal(
|
||||
TranslationHelpers.GetPropertiesString(leftEvaluationFinished.Properties),
|
||||
TranslationHelpers.GetPropertiesString(rightEvaluationFinished.Properties));
|
||||
Assert.Equal(
|
||||
TranslationHelpers.GetMultiItemsString(leftEvaluationFinished.Items),
|
||||
TranslationHelpers.GetMultiItemsString(rightEvaluationFinished.Items));
|
||||
break;
|
||||
|
||||
case LoggingEventType.TargetFinishedEvent:
|
||||
TargetFinishedEventArgs leftTargetFinished = left.NodeBuildEvent.Value.Value as TargetFinishedEventArgs;
|
||||
TargetFinishedEventArgs rightTargetFinished = right.NodeBuildEvent.Value.Value as TargetFinishedEventArgs;
|
||||
Assert.NotNull(leftTargetFinished);
|
||||
Assert.NotNull(rightTargetFinished);
|
||||
Assert.Equal(leftTargetFinished.ProjectFile, rightTargetFinished.ProjectFile);
|
||||
Assert.Equal(leftTargetFinished.Succeeded, rightTargetFinished.Succeeded);
|
||||
Assert.Equal(leftTargetFinished.TargetFile, rightTargetFinished.TargetFile);
|
||||
Assert.Equal(leftTargetFinished.TargetName, rightTargetFinished.TargetName);
|
||||
// TODO: target output translation is a special case and is done in TranslateTargetFinishedEvent
|
||||
// Assert.Equal(leftTargetFinished.TargetOutputs, rightTargetFinished.TargetOutputs);
|
||||
break;
|
||||
|
||||
case LoggingEventType.TargetStartedEvent:
|
||||
TargetStartedEventArgs leftTargetStarted = left.NodeBuildEvent.Value.Value as TargetStartedEventArgs;
|
||||
TargetStartedEventArgs rightTargetStarted = right.NodeBuildEvent.Value.Value as TargetStartedEventArgs;
|
||||
Assert.NotNull(leftTargetStarted);
|
||||
Assert.NotNull(rightTargetStarted);
|
||||
Assert.Equal(leftTargetStarted.ProjectFile, rightTargetStarted.ProjectFile);
|
||||
Assert.Equal(leftTargetStarted.TargetFile, rightTargetStarted.TargetFile);
|
||||
Assert.Equal(leftTargetStarted.TargetName, rightTargetStarted.TargetName);
|
||||
break;
|
||||
|
||||
case LoggingEventType.TargetSkipped:
|
||||
TargetSkippedEventArgs leftTargetSkipped = left.NodeBuildEvent.Value.Value as TargetSkippedEventArgs;
|
||||
TargetSkippedEventArgs rightTargetSkipped = right.NodeBuildEvent.Value.Value as TargetSkippedEventArgs;
|
||||
Assert.Equal(leftTargetSkipped.BuildReason, rightTargetSkipped.BuildReason);
|
||||
Assert.Equal(leftTargetSkipped.SkipReason, rightTargetSkipped.SkipReason);
|
||||
Assert.Equal(leftTargetSkipped.BuildEventContext, rightTargetSkipped.BuildEventContext);
|
||||
Assert.Equal(leftTargetSkipped.OriginalBuildEventContext, rightTargetSkipped.OriginalBuildEventContext);
|
||||
Assert.Equal(leftTargetSkipped.Condition, rightTargetSkipped.Condition);
|
||||
Assert.Equal(leftTargetSkipped.EvaluatedCondition, rightTargetSkipped.EvaluatedCondition);
|
||||
Assert.Equal(leftTargetSkipped.Importance, rightTargetSkipped.Importance);
|
||||
Assert.Equal(leftTargetSkipped.OriginallySucceeded, rightTargetSkipped.OriginallySucceeded);
|
||||
Assert.Equal(leftTargetSkipped.ProjectFile, rightTargetSkipped.ProjectFile);
|
||||
Assert.Equal(leftTargetSkipped.TargetFile, rightTargetSkipped.TargetFile);
|
||||
Assert.Equal(leftTargetSkipped.TargetName, rightTargetSkipped.TargetName);
|
||||
Assert.Equal(leftTargetSkipped.ParentTarget, rightTargetSkipped.ParentTarget);
|
||||
break;
|
||||
|
||||
case LoggingEventType.TaskCommandLineEvent:
|
||||
TaskCommandLineEventArgs leftCommand = left.NodeBuildEvent.Value.Value as TaskCommandLineEventArgs;
|
||||
TaskCommandLineEventArgs rightCommand = right.NodeBuildEvent.Value.Value as TaskCommandLineEventArgs;
|
||||
Assert.NotNull(leftCommand);
|
||||
Assert.NotNull(rightCommand);
|
||||
Assert.Equal(leftCommand.CommandLine, rightCommand.CommandLine);
|
||||
Assert.Equal(leftCommand.Importance, rightCommand.Importance);
|
||||
Assert.Equal(leftCommand.TaskName, rightCommand.TaskName);
|
||||
break;
|
||||
|
||||
case LoggingEventType.TaskParameterEvent:
|
||||
var leftTaskParameter = left.NodeBuildEvent.Value.Value as TaskParameterEventArgs;
|
||||
var rightTaskParameter = right.NodeBuildEvent.Value.Value as TaskParameterEventArgs;
|
||||
Assert.NotNull(leftTaskParameter);
|
||||
Assert.NotNull(rightTaskParameter);
|
||||
Assert.Equal(leftTaskParameter.Kind, rightTaskParameter.Kind);
|
||||
Assert.Equal(leftTaskParameter.ItemType, rightTaskParameter.ItemType);
|
||||
Assert.Equal(leftTaskParameter.Items.Count, rightTaskParameter.Items.Count);
|
||||
Assert.Equal(leftTaskParameter.Message, rightTaskParameter.Message);
|
||||
Assert.Equal(leftTaskParameter.BuildEventContext, rightTaskParameter.BuildEventContext);
|
||||
Assert.Equal(leftTaskParameter.Timestamp, rightTaskParameter.Timestamp);
|
||||
Assert.Equal(leftTaskParameter.LineNumber, rightTaskParameter.LineNumber);
|
||||
Assert.Equal(leftTaskParameter.ColumnNumber, rightTaskParameter.ColumnNumber);
|
||||
break;
|
||||
|
||||
case LoggingEventType.TaskFinishedEvent:
|
||||
TaskFinishedEventArgs leftTaskFinished = left.NodeBuildEvent.Value.Value as TaskFinishedEventArgs;
|
||||
TaskFinishedEventArgs rightTaskFinished = right.NodeBuildEvent.Value.Value as TaskFinishedEventArgs;
|
||||
Assert.NotNull(leftTaskFinished);
|
||||
Assert.NotNull(rightTaskFinished);
|
||||
Assert.Equal(leftTaskFinished.ProjectFile, rightTaskFinished.ProjectFile);
|
||||
Assert.Equal(leftTaskFinished.Succeeded, rightTaskFinished.Succeeded);
|
||||
Assert.Equal(leftTaskFinished.TaskFile, rightTaskFinished.TaskFile);
|
||||
Assert.Equal(leftTaskFinished.TaskName, rightTaskFinished.TaskName);
|
||||
break;
|
||||
|
||||
case LoggingEventType.TaskStartedEvent:
|
||||
TaskStartedEventArgs leftTaskStarted = left.NodeBuildEvent.Value.Value as TaskStartedEventArgs;
|
||||
TaskStartedEventArgs rightTaskStarted = right.NodeBuildEvent.Value.Value as TaskStartedEventArgs;
|
||||
Assert.NotNull(leftTaskStarted);
|
||||
Assert.NotNull(rightTaskStarted);
|
||||
Assert.Equal(leftTaskStarted.ProjectFile, rightTaskStarted.ProjectFile);
|
||||
Assert.Equal(leftTaskStarted.TaskFile, rightTaskStarted.TaskFile);
|
||||
Assert.Equal(leftTaskStarted.TaskName, rightTaskStarted.TaskName);
|
||||
Assert.Equal(leftTaskStarted.LineNumber, rightTaskStarted.LineNumber);
|
||||
Assert.Equal(leftTaskStarted.ColumnNumber, rightTaskStarted.ColumnNumber);
|
||||
break;
|
||||
|
||||
default:
|
||||
Assert.True(false, string.Format("Unexpected logging event type {0}", left.EventType));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,53 +17,224 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
/// </summary>
|
||||
public class TaskBuilderTestTask : IGeneratedTask
|
||||
{
|
||||
/// <summary>
|
||||
/// A custom <see cref="IConvertible"/> value type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Types like this one can be used only as Output parameter types because they can be converted to string
|
||||
/// but not from string.
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
public struct CustomStruct : IConvertible
|
||||
{
|
||||
private readonly object _value;
|
||||
|
||||
/// <summary>
|
||||
/// Using <see cref="IConvertible"/> as the type of the <see cref="_value"/> field triggers a BinaryFormatter bug.
|
||||
/// </summary>
|
||||
private IConvertible Value => (IConvertible)_value;
|
||||
|
||||
public CustomStruct(IConvertible value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public TypeCode GetTypeCode() => Value.GetTypeCode();
|
||||
public bool ToBoolean(IFormatProvider provider) => Value.ToBoolean(provider);
|
||||
public byte ToByte(IFormatProvider provider) => Value.ToByte(provider);
|
||||
public char ToChar(IFormatProvider provider) => Value.ToChar(provider);
|
||||
public DateTime ToDateTime(IFormatProvider provider) => Value.ToDateTime(provider);
|
||||
public decimal ToDecimal(IFormatProvider provider) => Value.ToDecimal(provider);
|
||||
public double ToDouble(IFormatProvider provider) => Value.ToDouble(provider);
|
||||
public short ToInt16(IFormatProvider provider) => Value.ToInt16(provider);
|
||||
public int ToInt32(IFormatProvider provider) => Value.ToInt32(provider);
|
||||
public long ToInt64(IFormatProvider provider) => Value.ToInt64(provider);
|
||||
public sbyte ToSByte(IFormatProvider provider) => Value.ToSByte(provider);
|
||||
public float ToSingle(IFormatProvider provider) => Value.ToSingle(provider);
|
||||
public string ToString(IFormatProvider provider) => Value.ToString(provider);
|
||||
public object ToType(Type conversionType, IFormatProvider provider) => Value.ToType(conversionType, provider);
|
||||
public ushort ToUInt16(IFormatProvider provider) => Value.ToUInt16(provider);
|
||||
public uint ToUInt32(IFormatProvider provider) => Value.ToUInt32(provider);
|
||||
public ulong ToUInt64(IFormatProvider provider) => Value.ToUInt64(provider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="CustomStruct"/> value returned from <see cref="CustomStructOutput"/>.
|
||||
/// </summary>
|
||||
internal static readonly CustomStruct s_customStruct = new CustomStruct(42);
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="CustomStruct[]"/> value returned from <see cref="CustomStructArrayOutput"/>.
|
||||
/// </summary>
|
||||
internal static readonly CustomStruct[] s_customStructArray = new CustomStruct[] { new CustomStruct(43), new CustomStruct(44) };
|
||||
|
||||
/// <summary>
|
||||
/// The task host.
|
||||
/// </summary>
|
||||
private ITestTaskHost _testTaskHost;
|
||||
|
||||
/// <summary>
|
||||
/// The value to return from Execute
|
||||
/// The value to return from Execute.
|
||||
/// </summary>
|
||||
private bool _executeReturnValue;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the BoolOutput
|
||||
/// The value for the BoolOutput.
|
||||
/// </summary>
|
||||
private bool _boolOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the BoolArrayOutput
|
||||
/// The value for the BoolArrayOutput.
|
||||
/// </summary>
|
||||
private bool[] _boolArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the IntOutput
|
||||
/// The value for the ByteOutput.
|
||||
/// </summary>
|
||||
private byte _byteOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the ByteArrayOutput.
|
||||
/// </summary>
|
||||
private byte[] _byteArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the SByteOutput.
|
||||
/// </summary>
|
||||
private sbyte _sbyteOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the SByteArrayOutput.
|
||||
/// </summary>
|
||||
private sbyte[] _sbyteArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the DoubleOutput.
|
||||
/// </summary>
|
||||
private double _doubleOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the DoubleArrayOutput.
|
||||
/// </summary>
|
||||
private double[] _doubleArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the FloatOutput.
|
||||
/// </summary>
|
||||
private float _floatOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the FloatArrayOutput.
|
||||
/// </summary>
|
||||
private float[] _floatArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the ShortOutput.
|
||||
/// </summary>
|
||||
private short _shortOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the ShortArrayOutput.
|
||||
/// </summary>
|
||||
private short[] _shortArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the UShortOutput.
|
||||
/// </summary>
|
||||
private ushort _ushortOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the UShortArrayOutput.
|
||||
/// </summary>
|
||||
private ushort[] _ushortArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the IntOutput.
|
||||
/// </summary>
|
||||
private int _intOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the IntArrayOutput
|
||||
/// The value for the IntArrayOutput.
|
||||
/// </summary>
|
||||
private int[] _intArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the StringOutput
|
||||
/// The value for the UIntOutput.
|
||||
/// </summary>
|
||||
private uint _uintOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the UIntArrayOutput.
|
||||
/// </summary>
|
||||
private uint[] _uintArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the LongOutput.
|
||||
/// </summary>
|
||||
private long _longOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the LongArrayOutput.
|
||||
/// </summary>
|
||||
private long[] _longArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the ULongOutput.
|
||||
/// </summary>
|
||||
private ulong _ulongOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the ULongArrayOutput.
|
||||
/// </summary>
|
||||
private ulong[] _ulongArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the DecimalOutput.
|
||||
/// </summary>
|
||||
private decimal _decimalOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the DecimalArrayOutput.
|
||||
/// </summary>
|
||||
private decimal[] _decimalArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the CharOutput.
|
||||
/// </summary>
|
||||
private char _charOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the CharArrayOutput.
|
||||
/// </summary>
|
||||
private char[] _charArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the StringOutput.
|
||||
/// </summary>
|
||||
private string _stringOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the StringArrayOutput
|
||||
/// The value for the StringArrayOutput.
|
||||
/// </summary>
|
||||
private string[] _stringArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the ItemOutput
|
||||
/// The value for the DateTimeOutput.
|
||||
/// </summary>
|
||||
private DateTime _dateTimeOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the DateTimeArrayOutput.
|
||||
/// </summary>
|
||||
private DateTime[] _dateTimeArrayOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the ItemOutput.
|
||||
/// </summary>
|
||||
private ITaskItem _itemOutput;
|
||||
|
||||
/// <summary>
|
||||
/// The value for the ItemArrayOutput
|
||||
/// The value for the ItemArrayOutput.
|
||||
/// </summary>
|
||||
private ITaskItem[] _itemArrayOutput;
|
||||
|
||||
|
@ -77,7 +248,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A boolean parameter
|
||||
/// A boolean parameter.
|
||||
/// </summary>
|
||||
public bool BoolParam
|
||||
{
|
||||
|
@ -89,7 +260,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A boolean array parameter
|
||||
/// A boolean array parameter.
|
||||
/// </summary>
|
||||
public bool[] BoolArrayParam
|
||||
{
|
||||
|
@ -101,7 +272,151 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// An integer parameter
|
||||
/// A byte parameter.
|
||||
/// </summary>
|
||||
public byte ByteParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_byteOutput = value;
|
||||
_testTaskHost?.ParameterSet("ByteParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A byte array parameter.
|
||||
/// </summary>
|
||||
public byte[] ByteArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_byteArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("ByteArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An sbyte parameter.
|
||||
/// </summary>
|
||||
public sbyte SByteParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_sbyteOutput = value;
|
||||
_testTaskHost?.ParameterSet("SByteParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An sbyte array parameter.
|
||||
/// </summary>
|
||||
public sbyte[] SByteArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_sbyteArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("SByteArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A double parameter.
|
||||
/// </summary>
|
||||
public double DoubleParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_doubleOutput = value;
|
||||
_testTaskHost?.ParameterSet("DoubleParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A double array parameter.
|
||||
/// </summary>
|
||||
public double[] DoubleArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_doubleArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("DoubleArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A float parameter.
|
||||
/// </summary>
|
||||
public float FloatParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_floatOutput = value;
|
||||
_testTaskHost?.ParameterSet("FloatParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A float array parameter.
|
||||
/// </summary>
|
||||
public float[] FloatArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_floatArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("FloatArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A short parameter.
|
||||
/// </summary>
|
||||
public short ShortParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_shortOutput = value;
|
||||
_testTaskHost?.ParameterSet("ShortParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A short array parameter.
|
||||
/// </summary>
|
||||
public short[] ShortArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_shortArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("ShortArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A ushort parameter.
|
||||
/// </summary>
|
||||
public ushort UShortParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_ushortOutput = value;
|
||||
_testTaskHost?.ParameterSet("UShortParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A ushort array parameter.
|
||||
/// </summary>
|
||||
public ushort[] UShortArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_ushortArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("UShortArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An integer parameter.
|
||||
/// </summary>
|
||||
public int IntParam
|
||||
{
|
||||
|
@ -124,6 +439,126 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A uint parameter.
|
||||
/// </summary>
|
||||
public uint UIntParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_uintOutput = value;
|
||||
_testTaskHost?.ParameterSet("UIntParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A uint array parameter.
|
||||
/// </summary>
|
||||
public uint[] UIntArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_uintArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("UIntArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A long parameter.
|
||||
/// </summary>
|
||||
public long LongParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_longOutput = value;
|
||||
_testTaskHost?.ParameterSet("LongParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A long array parameter.
|
||||
/// </summary>
|
||||
public long[] LongArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_longArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("LongArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A ulong parameter.
|
||||
/// </summary>
|
||||
public ulong ULongParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_ulongOutput = value;
|
||||
_testTaskHost?.ParameterSet("ULongParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A ulong array parameter.
|
||||
/// </summary>
|
||||
public ulong[] ULongArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_ulongArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("ULongArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A decimal parameter.
|
||||
/// </summary>
|
||||
public decimal DecimalParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_decimalOutput = value;
|
||||
_testTaskHost?.ParameterSet("DecimalParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A decimal array parameter.
|
||||
/// </summary>
|
||||
public decimal[] DecimalArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_decimalArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("DecimalArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A char parameter.
|
||||
/// </summary>
|
||||
public char CharParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_charOutput = value;
|
||||
_testTaskHost?.ParameterSet("CharParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A char array parameter.
|
||||
/// </summary>
|
||||
public char[] CharArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_charArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("CharArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A string parameter.
|
||||
/// </summary>
|
||||
|
@ -148,6 +583,30 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A DateTime parameter.
|
||||
/// </summary>
|
||||
public DateTime DateTimeParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_dateTimeOutput = value;
|
||||
_testTaskHost?.ParameterSet("DateTimeParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A DateTime array parameter.
|
||||
/// </summary>
|
||||
public DateTime[] DateTimeArrayParam
|
||||
{
|
||||
set
|
||||
{
|
||||
_dateTimeArrayOutput = value;
|
||||
_testTaskHost?.ParameterSet("DateTimeArrayParam", value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An item parameter.
|
||||
/// </summary>
|
||||
|
@ -199,7 +658,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A boolean array output
|
||||
/// A boolean array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public bool[] BoolArrayOutput
|
||||
|
@ -212,7 +671,163 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// An integer output
|
||||
/// A byte output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public byte ByteOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("ByteOutput", _byteOutput);
|
||||
return _byteOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A byte array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public byte[] ByteArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("ByteArrayOutput", _byteArrayOutput);
|
||||
return _byteArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An sbyte output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public sbyte SByteOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("SByteOutput", _sbyteOutput);
|
||||
return _sbyteOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An sbyte array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public sbyte[] SByteArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("SByteArrayOutput", _sbyteArrayOutput);
|
||||
return _sbyteArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A double output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public double DoubleOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("DoubleOutput", _doubleOutput);
|
||||
return _doubleOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A double array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public double[] DoubleArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("DoubleArrayOutput", _doubleArrayOutput);
|
||||
return _doubleArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A float output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public float FloatOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("FloatOutput", _floatOutput);
|
||||
return _floatOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A float array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public float[] FloatArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("FloatArrayOutput", _floatArrayOutput);
|
||||
return _floatArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A short output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public short ShortOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("ShortOutput", _shortOutput);
|
||||
return _shortOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A short array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public short[] ShortArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("ShortArrayOutput", _shortArrayOutput);
|
||||
return _shortArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A ushort output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ushort UShortOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("UShortOutput", _ushortOutput);
|
||||
return _ushortOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A ushort array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ushort[] UShortArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("UShortArrayOutput", _ushortArrayOutput);
|
||||
return _ushortArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An integer output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public int IntOutput
|
||||
|
@ -225,7 +840,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// An integer array output
|
||||
/// An integer array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public int[] IntArrayOutput
|
||||
|
@ -238,7 +853,137 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A string output
|
||||
/// A uint output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public uint UIntOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("UIntOutput", _uintOutput);
|
||||
return _uintOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A uint array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public uint[] UIntArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("UIntArrayOutput", _uintArrayOutput);
|
||||
return _uintArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A long output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public long LongOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("LongOutput", _longOutput);
|
||||
return _longOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A long array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public long[] LongArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("LongArrayOutput", _longArrayOutput);
|
||||
return _longArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A ulong output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ulong ULongOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("ULongOutput", _ulongOutput);
|
||||
return _ulongOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A ulong array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ulong[] ULongArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("ULongArrayOutput", _ulongArrayOutput);
|
||||
return _ulongArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A decimal output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public decimal DecimalOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("DecimalOutput", _decimalOutput);
|
||||
return _decimalOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A decimal array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public decimal[] DecimalArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("DecimalArrayOutput", _decimalArrayOutput);
|
||||
return _decimalArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A char output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public char CharOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("CharOutput", _charOutput);
|
||||
return _charOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A char array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public char[] CharArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("CharArrayOutput", _charArrayOutput);
|
||||
return _charArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A string output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public string StringOutput
|
||||
|
@ -290,7 +1035,59 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A null ITaskItem output
|
||||
/// A DateTime output
|
||||
/// </summary>
|
||||
[Output]
|
||||
public DateTime DateTimeOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("DateTimeOutput", _dateTimeOutput);
|
||||
return _dateTimeOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A DateTime array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public DateTime[] DateTimeArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("DateTimeArrayOutput", _dateTimeArrayOutput);
|
||||
return _dateTimeArrayOutput;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A CustomStruct output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public CustomStruct CustomStructOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("CustomStructOutput", s_customStruct);
|
||||
return s_customStruct;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A CustomStruct array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public CustomStruct[] CustomStructArrayOutput
|
||||
{
|
||||
get
|
||||
{
|
||||
_testTaskHost?.OutputRead("CustomStructArrayOutput", s_customStructArray);
|
||||
return s_customStructArray;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A null ITaskItem output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem NullITaskItemOutput
|
||||
|
@ -303,7 +1100,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A null string array output
|
||||
/// A null string array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public string[] NullStringArrayOutput
|
||||
|
@ -316,7 +1113,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A null ITaskItem array output
|
||||
/// A null ITaskItem array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem[] NullITaskItemArrayOutput
|
||||
|
@ -329,7 +1126,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A string array output
|
||||
/// A string array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public string[] StringArrayOutput
|
||||
|
@ -342,7 +1139,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A task item output
|
||||
/// A task item output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem ItemOutput
|
||||
|
@ -355,7 +1152,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A task item array output
|
||||
/// A task item array output.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem[] ItemArrayOutput
|
||||
|
@ -368,7 +1165,7 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// A task item array output that is null
|
||||
/// A task item array output that is null.
|
||||
/// </summary>
|
||||
[Output]
|
||||
public ITaskItem[] ItemArrayNullOutput
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using Microsoft.Build.Execution;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Shared;
|
||||
using Microsoft.Build.UnitTests;
|
||||
using Microsoft.Build.UnitTests.BackEnd;
|
||||
|
||||
|
@ -58,37 +61,159 @@ namespace Microsoft.Build.Engine.UnitTests.BackEnd
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VariousParameterTypesCanBeTransmittedToAndRecievedFromTaskHost()
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void VariousParameterTypesCanBeTransmittedToAndReceivedFromTaskHost(bool testLegacyImplementation)
|
||||
{
|
||||
using TestEnvironment env = TestEnvironment.Create(_output);
|
||||
|
||||
ChangeWaves.ResetStateForTests();
|
||||
if (testLegacyImplementation)
|
||||
{
|
||||
env.SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", ChangeWaves.Wave17_6.ToString());
|
||||
BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();
|
||||
}
|
||||
|
||||
string boolParam = "True";
|
||||
string boolArrayParam = "False;True;False";
|
||||
string byteParam = "42";
|
||||
string byteArrayParam = "11;22;33";
|
||||
string sbyteParam = "-42";
|
||||
string sbyteArrayParam = "-11;-22;-33";
|
||||
string doubleParam = "3.14";
|
||||
string doubleArrayParam = "3.14;2.72";
|
||||
string floatParam = "0.5";
|
||||
string floatArrayParam = "0.6;0.7;0.8";
|
||||
string shortParam = "-100";
|
||||
string shortArrayParam = "-200;-300;999";
|
||||
string ushortParam = "100";
|
||||
string ushortArrayParam = "200;300;999";
|
||||
string intParam = "-314";
|
||||
string intArrayParam = "42;-67;98";
|
||||
string uintParam = "314";
|
||||
string uintArrayParam = "4200000;67;98";
|
||||
string longParam = "-120000000000";
|
||||
string longArrayParam = "-120000000000;0;1";
|
||||
string ulongParam = "120000000000";
|
||||
string ulongArrayParam = "120000000000;0;1";
|
||||
string decimalParam = "0.999999999999";
|
||||
string decimalArrayParam = "-0.999999999999";
|
||||
string charParam = "A";
|
||||
string charArrayParam = "A;b;2";
|
||||
string stringParam = "stringParamInput";
|
||||
string stringArrayParam = "stringArrayParamInput1;stringArrayParamInput2;stringArrayParamInput3";
|
||||
string dateTimeParam = "01/01/2001 10:15:00";
|
||||
string dateTimeArrayParam = "01/01/2001 10:15:00;02/02/2002 11:30:00;03/03/2003 12:45:00";
|
||||
|
||||
string projectContents = $@"
|
||||
<Project>
|
||||
<UsingTask TaskName=""{nameof(TaskBuilderTestTask)}"" AssemblyFile=""{typeof(TaskBuilderTestTask).Assembly.Location}"" TaskFactory=""TaskHostFactory"" />
|
||||
<Target Name='{nameof(VariousParameterTypesCanBeTransmittedToAndRecievedFromTaskHost)}'>
|
||||
<Target Name='{nameof(VariousParameterTypesCanBeTransmittedToAndReceivedFromTaskHost)}'>
|
||||
<{nameof(TaskBuilderTestTask)}
|
||||
ExecuteReturnParam=""true""
|
||||
BoolParam=""true""
|
||||
BoolArrayParam=""false;true;false""
|
||||
IntParam=""314""
|
||||
IntArrayParam=""42;67;98""
|
||||
StringParam=""stringParamInput""
|
||||
StringArrayParam=""stringArrayParamInput1;stringArrayParamInput2;stringArrayParamInput3"">
|
||||
BoolParam=""{boolParam}""
|
||||
BoolArrayParam=""{boolArrayParam}""
|
||||
ByteParam=""{byteParam}""
|
||||
ByteArrayParam=""{byteArrayParam}""
|
||||
SByteParam=""{sbyteParam}""
|
||||
SByteArrayParam=""{sbyteArrayParam}""
|
||||
DoubleParam=""{doubleParam}""
|
||||
DoubleArrayParam=""{doubleArrayParam}""
|
||||
FloatParam=""{floatParam}""
|
||||
FloatArrayParam=""{floatArrayParam}""
|
||||
ShortParam=""{shortParam}""
|
||||
ShortArrayParam=""{shortArrayParam}""
|
||||
UShortParam=""{ushortParam}""
|
||||
UShortArrayParam=""{ushortArrayParam}""
|
||||
IntParam=""{intParam}""
|
||||
IntArrayParam=""{intArrayParam}""
|
||||
UIntParam=""{uintParam}""
|
||||
UIntArrayParam=""{uintArrayParam}""
|
||||
LongParam=""{longParam}""
|
||||
LongArrayParam=""{longArrayParam}""
|
||||
ULongParam=""{ulongParam}""
|
||||
ULongArrayParam=""{ulongArrayParam}""
|
||||
DecimalParam=""{decimalParam}""
|
||||
DecimalArrayParam=""{decimalArrayParam}""
|
||||
CharParam=""{charParam}""
|
||||
CharArrayParam=""{charArrayParam}""
|
||||
StringParam=""{stringParam}""
|
||||
StringArrayParam=""{stringArrayParam}""
|
||||
DateTimeParam=""{dateTimeParam}""
|
||||
DateTimeArrayParam=""{dateTimeArrayParam}"">
|
||||
|
||||
<Output PropertyName=""BoolOutput"" TaskParameter=""BoolOutput"" />
|
||||
<Output PropertyName=""BoolArrayOutput"" TaskParameter=""BoolArrayOutput"" />
|
||||
<Output PropertyName=""ByteOutput"" TaskParameter=""ByteOutput"" />
|
||||
<Output PropertyName=""ByteArrayOutput"" TaskParameter=""ByteArrayOutput"" />
|
||||
<Output PropertyName=""SByteOutput"" TaskParameter=""SByteOutput"" />
|
||||
<Output PropertyName=""SByteArrayOutput"" TaskParameter=""SByteArrayOutput"" />
|
||||
<Output PropertyName=""DoubleOutput"" TaskParameter=""DoubleOutput"" />
|
||||
<Output PropertyName=""DoubleArrayOutput"" TaskParameter=""DoubleArrayOutput"" />
|
||||
<Output PropertyName=""FloatOutput"" TaskParameter=""FloatOutput"" />
|
||||
<Output PropertyName=""FloatArrayOutput"" TaskParameter=""FloatArrayOutput"" />
|
||||
<Output PropertyName=""ShortOutput"" TaskParameter=""ShortOutput"" />
|
||||
<Output PropertyName=""ShortArrayOutput"" TaskParameter=""ShortArrayOutput"" />
|
||||
<Output PropertyName=""UShortOutput"" TaskParameter=""UShortOutput"" />
|
||||
<Output PropertyName=""UShortArrayOutput"" TaskParameter=""UShortArrayOutput"" />
|
||||
<Output PropertyName=""IntOutput"" TaskParameter=""IntOutput"" />
|
||||
<Output PropertyName=""IntArrayOutput"" TaskParameter=""IntArrayOutput"" />
|
||||
<Output PropertyName=""EnumOutput"" TaskParameter=""EnumOutput"" />
|
||||
<Output PropertyName=""UIntOutput"" TaskParameter=""UIntOutput"" />
|
||||
<Output PropertyName=""UIntArrayOutput"" TaskParameter=""UIntArrayOutput"" />
|
||||
<Output PropertyName=""LongOutput"" TaskParameter=""LongOutput"" />
|
||||
<Output PropertyName=""LongArrayOutput"" TaskParameter=""LongArrayOutput"" />
|
||||
<Output PropertyName=""ULongOutput"" TaskParameter=""ULongOutput"" />
|
||||
<Output PropertyName=""ULongArrayOutput"" TaskParameter=""ULongArrayOutput"" />
|
||||
<Output PropertyName=""DecimalOutput"" TaskParameter=""DecimalOutput"" />
|
||||
<Output PropertyName=""DecimalArrayOutput"" TaskParameter=""DecimalArrayOutput"" />
|
||||
<Output PropertyName=""CharOutput"" TaskParameter=""CharOutput"" />
|
||||
<Output PropertyName=""CharArrayOutput"" TaskParameter=""CharArrayOutput"" />
|
||||
<Output PropertyName=""StringOutput"" TaskParameter=""StringOutput"" />
|
||||
<Output PropertyName=""StringArrayOutput"" TaskParameter=""StringArrayOutput"" />
|
||||
<Output PropertyName=""DateTimeOutput"" TaskParameter=""DateTimeOutput"" />
|
||||
<Output PropertyName=""DateTimeArrayOutput"" TaskParameter=""DateTimeArrayOutput"" />
|
||||
<Output PropertyName=""CustomStructOutput"" TaskParameter=""CustomStructOutput"" />
|
||||
<Output PropertyName=""EnumOutput"" TaskParameter=""EnumOutput"" />
|
||||
</{nameof(TaskBuilderTestTask)}>
|
||||
</Target>
|
||||
</Project>";
|
||||
TransientTestProjectWithFiles project = env.CreateTestProjectWithFiles(projectContents);
|
||||
ProjectInstance projectInstance = new(project.ProjectFile);
|
||||
projectInstance.Build(new[] { new MockLogger(env.Output) }).ShouldBeTrue();
|
||||
|
||||
projectInstance.GetPropertyValue("BoolOutput").ShouldBe(boolParam);
|
||||
projectInstance.GetPropertyValue("BoolArrayOutput").ShouldBe(boolArrayParam);
|
||||
projectInstance.GetPropertyValue("ByteOutput").ShouldBe(byteParam);
|
||||
projectInstance.GetPropertyValue("ByteArrayOutput").ShouldBe(byteArrayParam);
|
||||
projectInstance.GetPropertyValue("SByteOutput").ShouldBe(sbyteParam);
|
||||
projectInstance.GetPropertyValue("SByteArrayOutput").ShouldBe(sbyteArrayParam);
|
||||
projectInstance.GetPropertyValue("DoubleOutput").ShouldBe(doubleParam);
|
||||
projectInstance.GetPropertyValue("DoubleArrayOutput").ShouldBe(doubleArrayParam);
|
||||
projectInstance.GetPropertyValue("FloatOutput").ShouldBe(floatParam);
|
||||
projectInstance.GetPropertyValue("FloatArrayOutput").ShouldBe(floatArrayParam);
|
||||
projectInstance.GetPropertyValue("ShortOutput").ShouldBe(shortParam);
|
||||
projectInstance.GetPropertyValue("ShortArrayOutput").ShouldBe(shortArrayParam);
|
||||
projectInstance.GetPropertyValue("UShortOutput").ShouldBe(ushortParam);
|
||||
projectInstance.GetPropertyValue("UShortArrayOutput").ShouldBe(ushortArrayParam);
|
||||
projectInstance.GetPropertyValue("IntOutput").ShouldBe(intParam);
|
||||
projectInstance.GetPropertyValue("IntArrayOutput").ShouldBe(intArrayParam);
|
||||
projectInstance.GetPropertyValue("UIntOutput").ShouldBe(uintParam);
|
||||
projectInstance.GetPropertyValue("UIntArrayOutput").ShouldBe(uintArrayParam);
|
||||
projectInstance.GetPropertyValue("LongOutput").ShouldBe(longParam);
|
||||
projectInstance.GetPropertyValue("LongArrayOutput").ShouldBe(longArrayParam);
|
||||
projectInstance.GetPropertyValue("ULongOutput").ShouldBe(ulongParam);
|
||||
projectInstance.GetPropertyValue("ULongArrayOutput").ShouldBe(ulongArrayParam);
|
||||
projectInstance.GetPropertyValue("DecimalOutput").ShouldBe(decimalParam);
|
||||
projectInstance.GetPropertyValue("DecimalArrayOutput").ShouldBe(decimalArrayParam);
|
||||
projectInstance.GetPropertyValue("CharOutput").ShouldBe(charParam);
|
||||
projectInstance.GetPropertyValue("CharArrayOutput").ShouldBe(charArrayParam);
|
||||
projectInstance.GetPropertyValue("StringOutput").ShouldBe(stringParam);
|
||||
projectInstance.GetPropertyValue("StringArrayOutput").ShouldBe(stringArrayParam);
|
||||
projectInstance.GetPropertyValue("DateTimeOutput").ShouldBe(dateTimeParam);
|
||||
projectInstance.GetPropertyValue("DateTimeArrayOutput").ShouldBe(dateTimeArrayParam);
|
||||
projectInstance.GetPropertyValue("CustomStructOutput").ShouldBe(TaskBuilderTestTask.s_customStruct.ToString(CultureInfo.InvariantCulture));
|
||||
projectInstance.GetPropertyValue("EnumOutput").ShouldBe(TargetBuiltReason.BeforeTargets.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -385,6 +385,61 @@ namespace Microsoft.Build.UnitTests.BackEnd
|
|||
Assert.Equal("testCustomBuildEvent", _customLogger.LastCustom.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that extended custom events are logged properly
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void TestLogExtendedCustomEventNotSerializableMP()
|
||||
{
|
||||
_mockHost.BuildParameters.MaxNodeCount = 4;
|
||||
|
||||
// Log the custom event args. (Pretend that the task actually did this.)
|
||||
_taskHost.LogCustomEvent(new ExtendedCustomBuildEventArgs("testExtCustomBuildEvent", "ext message", null, null));
|
||||
|
||||
// Make sure our custom logger received the actual custom event and not some fake.
|
||||
Assert.True(_customLogger.LastCustom is ExtendedCustomBuildEventArgs); // "Expected custom build Event"
|
||||
Assert.Equal("ext message", _customLogger.LastCustom.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLogExtendedCustomErrorNotSerializableMP()
|
||||
{
|
||||
_mockHost.BuildParameters.MaxNodeCount = 4;
|
||||
|
||||
// Log the custom event args. (Pretend that the task actually did this.)
|
||||
_taskHost.LogErrorEvent(new ExtendedBuildErrorEventArgs("testExtCustomBuildError", null, null, null, 0, 0, 0, 0,"ext err message", null, null));
|
||||
|
||||
// Make sure our custom logger received the actual custom event and not some fake.
|
||||
Assert.True(_customLogger.LastError is ExtendedBuildErrorEventArgs); // "Expected custom build Event"
|
||||
Assert.Equal("ext err message", _customLogger.LastError.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLogExtendedCustomWarningNotSerializableMP()
|
||||
{
|
||||
_mockHost.BuildParameters.MaxNodeCount = 4;
|
||||
|
||||
// Log the custom event args. (Pretend that the task actually did this.)
|
||||
_taskHost.LogWarningEvent(new ExtendedBuildWarningEventArgs("testExtCustomBuildWarning", null, null, null, 0, 0, 0, 0, "ext warn message", null, null));
|
||||
|
||||
// Make sure our custom logger received the actual custom event and not some fake.
|
||||
Assert.True(_customLogger.LastWarning is ExtendedBuildWarningEventArgs); // "Expected custom build Event"
|
||||
Assert.Equal("ext warn message", _customLogger.LastWarning.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestLogExtendedCustomMessageNotSerializableMP()
|
||||
{
|
||||
_mockHost.BuildParameters.MaxNodeCount = 4;
|
||||
|
||||
// Log the custom event args. (Pretend that the task actually did this.)
|
||||
_taskHost.LogMessageEvent(new ExtendedBuildMessageEventArgs("testExtCustomBuildMessage", "ext message", null, null, MessageImportance.Normal));
|
||||
|
||||
// Make sure our custom logger received the actual custom event and not some fake.
|
||||
Assert.True(_customLogger.LastMessage is ExtendedBuildMessageEventArgs); // "Expected custom build Event"
|
||||
Assert.Equal("ext message", _customLogger.LastMessage.Message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that errors are logged properly
|
||||
/// </summary>
|
||||
|
|
|
@ -13,6 +13,7 @@ using Microsoft.Build.Framework.Profiler;
|
|||
using Microsoft.Build.Logging;
|
||||
using Microsoft.Build.Shared;
|
||||
using Microsoft.Build.UnitTests.BackEnd;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
|
||||
#nullable disable
|
||||
|
@ -262,6 +263,40 @@ namespace Microsoft.Build.UnitTests
|
|||
e => string.Join(", ", e.RawArguments ?? Array.Empty<object>()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void RoundtripExtendedErrorEventArgs_SerializedAsError(bool useArguments)
|
||||
{
|
||||
var args = new ExtendedBuildErrorEventArgs(
|
||||
"extendedDataType",
|
||||
"Subcategory",
|
||||
"Code",
|
||||
"File",
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
"Message with arguments: '{0}'",
|
||||
"Help",
|
||||
"SenderName",
|
||||
DateTime.Parse("9/1/2021 12:02:07 PM"),
|
||||
useArguments ? new object[] { "argument0" } : null);
|
||||
|
||||
// For now we don't serialize extended data into binary log
|
||||
Roundtrip<BuildErrorEventArgs>(args,
|
||||
e => e.Code,
|
||||
e => e.ColumnNumber.ToString(),
|
||||
e => e.EndColumnNumber.ToString(),
|
||||
e => e.EndLineNumber.ToString(),
|
||||
e => e.File,
|
||||
e => e.LineNumber.ToString(),
|
||||
e => e.Message,
|
||||
e => e.ProjectFile,
|
||||
e => e.Subcategory,
|
||||
e => string.Join(", ", e.RawArguments ?? Array.Empty<object>()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
|
@ -294,6 +329,40 @@ namespace Microsoft.Build.UnitTests
|
|||
e => string.Join(", ", e.RawArguments ?? Array.Empty<object>()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void RoundtripExtendedWarningEventArgs_SerializedAsWarning(bool useArguments)
|
||||
{
|
||||
var args = new ExtendedBuildWarningEventArgs(
|
||||
"extendedDataType",
|
||||
"Subcategory",
|
||||
"Code",
|
||||
"File",
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
"Message with arguments: '{0}'",
|
||||
"Help",
|
||||
"SenderName",
|
||||
DateTime.Parse("9/1/2021 12:02:07 PM"),
|
||||
useArguments ? new object[] { "argument0" } : null);
|
||||
|
||||
// For now we don't serialize extended data into binary log
|
||||
Roundtrip<BuildWarningEventArgs>(args,
|
||||
e => e.Code,
|
||||
e => e.ColumnNumber.ToString(),
|
||||
e => e.EndColumnNumber.ToString(),
|
||||
e => e.EndLineNumber.ToString(),
|
||||
e => e.File,
|
||||
e => e.LineNumber.ToString(),
|
||||
e => e.Message,
|
||||
e => e.ProjectFile,
|
||||
e => e.Subcategory,
|
||||
e => string.Join(", ", e.RawArguments ?? Array.Empty<object>()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
|
@ -328,6 +397,122 @@ namespace Microsoft.Build.UnitTests
|
|||
e => string.Join(", ", e.RawArguments ?? Array.Empty<object>()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void RoundtripExtendedBuildMessageEventArgs_SerializedAsMessage(bool useArguments)
|
||||
{
|
||||
var args = new ExtendedBuildMessageEventArgs(
|
||||
"extendedDataType",
|
||||
"Subcategory",
|
||||
"Code",
|
||||
"File",
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
"Message",
|
||||
"Help",
|
||||
"SenderName",
|
||||
MessageImportance.High,
|
||||
DateTime.Parse("12/12/2015 06:11:56 PM"),
|
||||
useArguments ? new object[] { "argument0" } : null);
|
||||
|
||||
Roundtrip<BuildMessageEventArgs>(args,
|
||||
e => e.Code,
|
||||
e => e.ColumnNumber.ToString(),
|
||||
e => e.EndColumnNumber.ToString(),
|
||||
e => e.EndLineNumber.ToString(),
|
||||
e => e.File,
|
||||
e => e.LineNumber.ToString(),
|
||||
e => e.Message,
|
||||
e => e.Importance.ToString(),
|
||||
e => e.ProjectFile,
|
||||
e => e.Subcategory,
|
||||
e => string.Join(", ", e.RawArguments ?? Array.Empty<object>()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RoundtripAssemblyLoadBuild()
|
||||
{
|
||||
string assemblyName = Guid.NewGuid().ToString();
|
||||
string assemblyPath = Guid.NewGuid().ToString();
|
||||
Guid mvid = Guid.NewGuid();
|
||||
string loadingInitiator = Guid.NewGuid().ToString();
|
||||
string appDomainName = Guid.NewGuid().ToString();
|
||||
AssemblyLoadingContext context =
|
||||
(AssemblyLoadingContext)(new Random().Next(Enum.GetNames(typeof(AssemblyLoadingContext)).Length));
|
||||
|
||||
AssemblyLoadBuildEventArgs args = new(context, loadingInitiator, assemblyName, assemblyPath, mvid, appDomainName);
|
||||
|
||||
Roundtrip(args,
|
||||
e => e.Code,
|
||||
e => e.ColumnNumber.ToString(),
|
||||
e => e.EndColumnNumber.ToString(),
|
||||
e => e.EndLineNumber.ToString(),
|
||||
e => e.File,
|
||||
e => e.LineNumber.ToString(),
|
||||
e => e.Message,
|
||||
e => e.Importance.ToString(),
|
||||
e => e.ProjectFile,
|
||||
e => e.Subcategory,
|
||||
e => e.LoadingContext.ToString(),
|
||||
e => e.AssemblyName,
|
||||
e => e.AssemblyPath,
|
||||
e => e.MVID.ToString(),
|
||||
e => e.AppDomainDescriptor,
|
||||
e => string.Join(", ", e.RawArguments ?? Array.Empty<object>()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void ExtendedCustomBuildEventArgs_SerializedAsMessage(bool withOptionalData)
|
||||
{
|
||||
ExtendedCustomBuildEventArgs args = new(
|
||||
type: "TypeOfExtendedCustom",
|
||||
message: withOptionalData ? "a message with args {0} {1}" : null,
|
||||
helpKeyword: withOptionalData ? "MSBT123" : null,
|
||||
senderName: withOptionalData ? $"UnitTest {Guid.NewGuid()}" : null,
|
||||
eventTimestamp: withOptionalData ? DateTime.Parse("3/1/2017 11:11:56 AM") : DateTime.Now,
|
||||
messageArgs: withOptionalData ? new object[] { "arg0val", "arg1val" } : null)
|
||||
{
|
||||
ExtendedData = withOptionalData ? "{'long-json':'mostly-strings'}" : null,
|
||||
ExtendedMetadata = withOptionalData ? new Dictionary<string, string> { { "m1", "v1" }, { "m2", "v2" } } : null,
|
||||
BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null,
|
||||
};
|
||||
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
var binaryWriter = new BinaryWriter(memoryStream);
|
||||
var buildEventArgsWriter = new BuildEventArgsWriter(binaryWriter);
|
||||
buildEventArgsWriter.Write(args);
|
||||
|
||||
memoryStream.Position = 0;
|
||||
var binaryReader = new BinaryReader(memoryStream);
|
||||
|
||||
using var buildEventArgsReader = new BuildEventArgsReader(binaryReader, BinaryLogger.FileFormatVersion);
|
||||
var deserialized = buildEventArgsReader.Read();
|
||||
BuildMessageEventArgs desArgs = (BuildMessageEventArgs)deserialized;
|
||||
|
||||
desArgs.ShouldBeOfType(typeof(BuildMessageEventArgs));
|
||||
|
||||
desArgs.Message.ShouldBe(args.Message);
|
||||
desArgs.HelpKeyword.ShouldBe(args.HelpKeyword);
|
||||
desArgs.SenderName.ShouldBe(args.SenderName);
|
||||
desArgs.Importance.ShouldBe(MessageImportance.Normal);
|
||||
desArgs.Timestamp.ShouldBe(args.Timestamp);
|
||||
|
||||
if (withOptionalData)
|
||||
{
|
||||
desArgs.BuildEventContext.ShouldBe(args.BuildEventContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
desArgs.BuildEventContext.ShouldBe(BuildEventContext.Invalid);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RoundtripResponseFileUsedEventArgs()
|
||||
{
|
||||
|
@ -689,7 +874,7 @@ namespace Microsoft.Build.UnitTests
|
|||
Assert.Equal(length, memoryStream.Position);
|
||||
|
||||
Assert.NotNull(deserializedArgs);
|
||||
Assert.Equal(args.GetType(), deserializedArgs.GetType());
|
||||
Assert.Equal(typeof(T), deserializedArgs.GetType());
|
||||
|
||||
foreach (var field in fieldsToCompare)
|
||||
{
|
||||
|
|
|
@ -695,8 +695,9 @@ namespace Microsoft.Build.Graph.UnitTests
|
|||
var globalProperties = currentSolutionConfiguration != null
|
||||
? new Dictionary<string, string>
|
||||
{
|
||||
["Configuration"] = currentSolutionConfiguration.ConfigurationName,
|
||||
["Platform"] = currentSolutionConfiguration.PlatformName
|
||||
// Intentionally use mismatched casing to ensure it's properly normalized.
|
||||
["Configuration"] = currentSolutionConfiguration.ConfigurationName.ToUpperInvariant(),
|
||||
["Platform"] = currentSolutionConfiguration.PlatformName.ToUpperInvariant()
|
||||
}
|
||||
: new Dictionary<string, string>();
|
||||
|
||||
|
@ -706,6 +707,9 @@ namespace Microsoft.Build.Graph.UnitTests
|
|||
globalProperties),
|
||||
_env.CreateProjectCollection().Collection);
|
||||
|
||||
// Exactly 1 node per project
|
||||
graph.ProjectNodes.Count.ShouldBe(graph.ProjectNodes.Select(GetProjectPath).Distinct().Count());
|
||||
|
||||
// in the solution, all nodes are entry points
|
||||
graphFromSolution.EntryPointNodes.Select(GetProjectPath)
|
||||
.ShouldBeSetEquivalentTo(graph.ProjectNodes.Select(GetProjectPath));
|
||||
|
@ -724,19 +728,9 @@ namespace Microsoft.Build.Graph.UnitTests
|
|||
|
||||
foreach (var node in graphFromSolution.ProjectNodes)
|
||||
{
|
||||
// Project references get duplicated, once as entry points from the solution (handled in the if block) and once as nodes
|
||||
// produced by ProjectReference items (handled in the else block).
|
||||
if (node.ReferencingProjects.Count == 0)
|
||||
{
|
||||
var expectedProjectConfiguration = actualProjectConfigurations[GetProjectNumber(node).ToString()][expectedCurrentConfiguration];
|
||||
GetConfiguration(node).ShouldBe(expectedProjectConfiguration.ConfigurationName);
|
||||
GetPlatform(node).ShouldBe(expectedProjectConfiguration.PlatformName);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetConfiguration(node).ShouldBe(GetConfiguration(node.ReferencingProjects.First()));
|
||||
GetPlatform(node).ShouldBe(GetPlatform(node.ReferencingProjects.First()));
|
||||
}
|
||||
var expectedProjectConfiguration = actualProjectConfigurations[GetProjectNumber(node).ToString()][expectedCurrentConfiguration];
|
||||
GetConfiguration(node).ShouldBe(expectedProjectConfiguration.ConfigurationName);
|
||||
GetPlatform(node).ShouldBe(expectedProjectConfiguration.PlatformName);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.IO.Compression" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" />
|
||||
|
||||
<PackageReference Include="FluentAssertions" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" />
|
||||
<PackageReference Include="Shouldly" />
|
||||
<PackageReference Include="System.Net.Http" />
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.Build.Evaluation;
|
||||
using Microsoft.Build.Framework.Profiler;
|
||||
using Microsoft.Build.UnitTests.BackEnd;
|
||||
using Xunit;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Microsoft.Build.UnitTests
|
||||
{
|
||||
// Although this tests the ProfilerResult API from Microsoft.Build.Framework, it uses the
|
||||
// construction APIs in Microsoft.Build in the test, so this test is in the Microsoft.Build tests
|
||||
public class ProjectEvaluationFinishedEventArgs_Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Roundtrip serialization tests for <see cref="ProfilerResult"/>
|
||||
/// </summary>
|
||||
[MemberData(nameof(GetProfilerResults))]
|
||||
[Theory]
|
||||
public void ProfilerResultRoundTrip(ProfilerResult profilerResult)
|
||||
{
|
||||
var writeTranslator = TranslationHelpers.GetWriteTranslator();
|
||||
ProfilerResult deserializedResult = default;
|
||||
|
||||
writeTranslator.TranslateDotNet(ref profilerResult);
|
||||
|
||||
var readTranslator = TranslationHelpers.GetReadTranslator();
|
||||
|
||||
readTranslator.TranslateDotNet(ref deserializedResult);
|
||||
|
||||
Assert.Equal(deserializedResult, profilerResult);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetProfilerResults()
|
||||
{
|
||||
yield return new object[] { new ProfilerResult(new Dictionary<EvaluationLocation, ProfiledLocation>()) };
|
||||
|
||||
yield return new object[] { new ProfilerResult(new Dictionary<EvaluationLocation, ProfiledLocation>
|
||||
{
|
||||
{new EvaluationLocation(0, null, EvaluationPass.TotalEvaluation, "1", "myFile", 42, "elementName", "description", EvaluationLocationKind.Condition), new ProfiledLocation(TimeSpan.MaxValue, TimeSpan.MinValue, 2) },
|
||||
{new EvaluationLocation(1, 0, EvaluationPass.Targets, "1", null, null, null, null, EvaluationLocationKind.Glob), new ProfiledLocation(TimeSpan.MaxValue, TimeSpan.MinValue, 2) },
|
||||
{new EvaluationLocation(2, 0, EvaluationPass.LazyItems, "2", null, null, null, null, EvaluationLocationKind.Element), new ProfiledLocation(TimeSpan.Zero, TimeSpan.Zero, 0) }
|
||||
}) };
|
||||
|
||||
var element = new ProjectRootElement(
|
||||
XmlReader.Create(new MemoryStream(Encoding.UTF8.GetBytes(
|
||||
"<Project />"))),
|
||||
new ProjectRootElementCache(false), false, false);
|
||||
|
||||
yield return new object[] { new ProfilerResult(new Dictionary<EvaluationLocation, ProfiledLocation>
|
||||
{
|
||||
{EvaluationLocation.CreateLocationForCondition(null, EvaluationPass.UsingTasks, "1", "myFile", 42, "conditionCase"), new ProfiledLocation(TimeSpan.MaxValue, TimeSpan.MinValue, 2) },
|
||||
{EvaluationLocation.CreateLocationForProject(null, EvaluationPass.InitialProperties, "1", "myFile", 42, element),
|
||||
new ProfiledLocation(TimeSpan.MaxValue, TimeSpan.MinValue, 2) },
|
||||
{EvaluationLocation.CreateLocationForGlob(null, EvaluationPass.InitialProperties, "1", "myFile", 42, "glob description"),
|
||||
new ProfiledLocation(TimeSpan.MaxValue, TimeSpan.MinValue, 2) }
|
||||
}) };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ namespace Microsoft.Build.BackEnd
|
|||
/// Constructor for deserialization
|
||||
/// </summary>
|
||||
private LogMessagePacket(ITranslator translator)
|
||||
: base(translator)
|
||||
: base(translator, new TargetFinishedTranslator(TranslateTargetFinishedEvent))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -901,9 +901,60 @@ namespace Microsoft.Build.BackEnd.Logging
|
|||
|
||||
LogMessagePacket loggingPacket = (LogMessagePacket)packet;
|
||||
InjectNonSerializedData(loggingPacket);
|
||||
|
||||
WarnOnDeprecatedCustomArgsSerialization(loggingPacket);
|
||||
|
||||
ProcessLoggingEvent(loggingPacket.NodeBuildEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializing unknown CustomEvent which has to use unsecure BinaryFormatter by TranslateDotNet.
|
||||
/// Since BinaryFormatter is going to be deprecated, log warning so users can use new Extended*EventArgs instead of custom
|
||||
/// EventArgs derived from existing EventArgs.
|
||||
/// </summary>
|
||||
private void WarnOnDeprecatedCustomArgsSerialization(LogMessagePacket loggingPacket)
|
||||
{
|
||||
if (loggingPacket.EventType == LoggingEventType.CustomEvent
|
||||
&& ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_8)
|
||||
&& Traits.Instance.EscapeHatches.EnableWarningOnCustomBuildEvent)
|
||||
{
|
||||
BuildEventArgs buildEvent = loggingPacket.NodeBuildEvent.Value.Value;
|
||||
BuildEventContext buildEventContext = buildEvent?.BuildEventContext ?? BuildEventContext.Invalid;
|
||||
|
||||
string message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(
|
||||
out string warningCode,
|
||||
out string helpKeyword,
|
||||
"DeprecatedEventSerialization",
|
||||
buildEvent?.GetType().Name ?? string.Empty);
|
||||
|
||||
BuildWarningEventArgs warning = new(
|
||||
null,
|
||||
warningCode,
|
||||
BuildEventFileInfo.Empty.File,
|
||||
BuildEventFileInfo.Empty.Line,
|
||||
BuildEventFileInfo.Empty.Column,
|
||||
BuildEventFileInfo.Empty.EndLine,
|
||||
BuildEventFileInfo.Empty.EndColumn,
|
||||
message,
|
||||
helpKeyword,
|
||||
"MSBuild");
|
||||
|
||||
warning.BuildEventContext = buildEventContext;
|
||||
if (warning.ProjectFile == null && buildEventContext.ProjectContextId != BuildEventContext.InvalidProjectContextId)
|
||||
{
|
||||
warning.ProjectFile = buildEvent switch
|
||||
{
|
||||
BuildMessageEventArgs buildMessageEvent => buildMessageEvent.ProjectFile,
|
||||
BuildErrorEventArgs buildErrorEvent => buildErrorEvent.ProjectFile,
|
||||
BuildWarningEventArgs buildWarningEvent => buildWarningEvent.ProjectFile,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
ProcessLoggingEvent(warning);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register an instantiated logger which implements the ILogger interface. This logger will be registered to a specific event
|
||||
/// source (the central logger event source) which will receive all logging messages for a given build.
|
||||
|
@ -1438,42 +1489,93 @@ namespace Microsoft.Build.BackEnd.Logging
|
|||
{
|
||||
if (ShouldTreatWarningAsMessage(warningEvent))
|
||||
{
|
||||
buildEventArgs = new BuildMessageEventArgs(
|
||||
warningEvent.Subcategory,
|
||||
warningEvent.Code,
|
||||
warningEvent.File,
|
||||
warningEvent.LineNumber,
|
||||
warningEvent.ColumnNumber,
|
||||
warningEvent.EndLineNumber,
|
||||
warningEvent.EndColumnNumber,
|
||||
warningEvent.Message,
|
||||
warningEvent.HelpKeyword,
|
||||
warningEvent.SenderName,
|
||||
MessageImportance.Low,
|
||||
warningEvent.Timestamp)
|
||||
if (buildEventArgs is ExtendedBuildWarningEventArgs extWarningEvent)
|
||||
{
|
||||
BuildEventContext = warningEvent.BuildEventContext,
|
||||
ProjectFile = warningEvent.ProjectFile,
|
||||
};
|
||||
buildEventArgs = new ExtendedBuildMessageEventArgs(
|
||||
extWarningEvent.ExtendedType,
|
||||
extWarningEvent.Subcategory,
|
||||
extWarningEvent.Code,
|
||||
extWarningEvent.File,
|
||||
extWarningEvent.LineNumber,
|
||||
extWarningEvent.ColumnNumber,
|
||||
extWarningEvent.EndLineNumber,
|
||||
extWarningEvent.EndColumnNumber,
|
||||
extWarningEvent.Message,
|
||||
extWarningEvent.HelpKeyword,
|
||||
extWarningEvent.SenderName,
|
||||
MessageImportance.Low,
|
||||
extWarningEvent.Timestamp)
|
||||
{
|
||||
BuildEventContext = warningEvent.BuildEventContext,
|
||||
ProjectFile = warningEvent.ProjectFile,
|
||||
ExtendedMetadata = extWarningEvent.ExtendedMetadata,
|
||||
ExtendedData = extWarningEvent.ExtendedData,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
buildEventArgs = new BuildMessageEventArgs(
|
||||
warningEvent.Subcategory,
|
||||
warningEvent.Code,
|
||||
warningEvent.File,
|
||||
warningEvent.LineNumber,
|
||||
warningEvent.ColumnNumber,
|
||||
warningEvent.EndLineNumber,
|
||||
warningEvent.EndColumnNumber,
|
||||
warningEvent.Message,
|
||||
warningEvent.HelpKeyword,
|
||||
warningEvent.SenderName,
|
||||
MessageImportance.Low,
|
||||
warningEvent.Timestamp)
|
||||
{
|
||||
BuildEventContext = warningEvent.BuildEventContext,
|
||||
ProjectFile = warningEvent.ProjectFile,
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (ShouldTreatWarningAsError(warningEvent))
|
||||
{
|
||||
buildEventArgs = new BuildErrorEventArgs(
|
||||
warningEvent.Subcategory,
|
||||
warningEvent.Code,
|
||||
warningEvent.File,
|
||||
warningEvent.LineNumber,
|
||||
warningEvent.ColumnNumber,
|
||||
warningEvent.EndLineNumber,
|
||||
warningEvent.EndColumnNumber,
|
||||
warningEvent.Message,
|
||||
warningEvent.HelpKeyword,
|
||||
warningEvent.SenderName,
|
||||
warningEvent.Timestamp)
|
||||
if (warningEvent is ExtendedBuildWarningEventArgs extWarningEvent)
|
||||
{
|
||||
BuildEventContext = warningEvent.BuildEventContext,
|
||||
ProjectFile = warningEvent.ProjectFile,
|
||||
};
|
||||
buildEventArgs = new ExtendedBuildErrorEventArgs(
|
||||
extWarningEvent.ExtendedType,
|
||||
extWarningEvent.Subcategory,
|
||||
extWarningEvent.Code,
|
||||
extWarningEvent.File,
|
||||
extWarningEvent.LineNumber,
|
||||
extWarningEvent.ColumnNumber,
|
||||
extWarningEvent.EndLineNumber,
|
||||
extWarningEvent.EndColumnNumber,
|
||||
extWarningEvent.Message,
|
||||
extWarningEvent.HelpKeyword,
|
||||
extWarningEvent.SenderName,
|
||||
extWarningEvent.Timestamp)
|
||||
{
|
||||
BuildEventContext = warningEvent.BuildEventContext,
|
||||
ProjectFile = warningEvent.ProjectFile,
|
||||
ExtendedMetadata = extWarningEvent.ExtendedMetadata,
|
||||
ExtendedData = extWarningEvent.ExtendedData,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
buildEventArgs = new BuildErrorEventArgs(
|
||||
warningEvent.Subcategory,
|
||||
warningEvent.Code,
|
||||
warningEvent.File,
|
||||
warningEvent.LineNumber,
|
||||
warningEvent.ColumnNumber,
|
||||
warningEvent.EndLineNumber,
|
||||
warningEvent.EndColumnNumber,
|
||||
warningEvent.Message,
|
||||
warningEvent.HelpKeyword,
|
||||
warningEvent.SenderName,
|
||||
warningEvent.Timestamp)
|
||||
{
|
||||
BuildEventContext = warningEvent.BuildEventContext,
|
||||
ProjectFile = warningEvent.ProjectFile,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1110,7 +1110,9 @@ namespace Microsoft.Build.BackEnd
|
|||
internal bool IsEventSerializable(BuildEventArgs e)
|
||||
{
|
||||
#pragma warning disable SYSLIB0050
|
||||
if (!e.GetType().GetTypeInfo().IsSerializable)
|
||||
// Types which are not serializable and are not IExtendedBuildEventArgs as
|
||||
// those always implement custom serialization by WriteToStream and CreateFromStream.
|
||||
if (!e.GetType().GetTypeInfo().IsSerializable && e is not IExtendedBuildEventArgs)
|
||||
#pragma warning restore SYSLIB0050
|
||||
{
|
||||
_taskLoggingContext.LogWarning(null, new BuildEventFileInfo(string.Empty), "ExpectedEventToBeSerializable", e.GetType().Name);
|
||||
|
|
|
@ -581,7 +581,28 @@ namespace Microsoft.Build.Execution
|
|||
{
|
||||
if (_nodeEndpoint.LinkStatus == LinkStatus.Active)
|
||||
{
|
||||
#if RUNTIME_TYPE_NETCORE
|
||||
if (packet is LogMessagePacketBase logMessage
|
||||
&& logMessage.EventType == LoggingEventType.CustomEvent
|
||||
&& ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_8)
|
||||
&& Traits.Instance.EscapeHatches.EnableWarningOnCustomBuildEvent)
|
||||
{
|
||||
BuildEventArgs buildEvent = logMessage.NodeBuildEvent.Value.Value;
|
||||
|
||||
// Serializing unknown CustomEvent which has to use unsecure BinaryFormatter by TranslateDotNet<T>
|
||||
// Since BinaryFormatter is deprecated in dotnet 8+, log error so users discover root cause easier
|
||||
// then by reading CommTrace where it would be otherwise logged as critical infra error.
|
||||
_loggingService.LogError(_loggingContext?.BuildEventContext ?? BuildEventContext.Invalid, null, BuildEventFileInfo.Empty,
|
||||
"DeprecatedEventSerialization",
|
||||
buildEvent?.GetType().Name ?? string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
_nodeEndpoint.SendData(packet);
|
||||
}
|
||||
#else
|
||||
_nodeEndpoint.SendData(packet);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -258,7 +258,7 @@ namespace Microsoft.Build.Graph
|
|||
ProjectGraphEntryPoint solutionEntryPoint = entryPoints.Single();
|
||||
ImmutableDictionary<string, string>.Builder solutionGlobalPropertiesBuilder = ImmutableDictionary.CreateBuilder(
|
||||
keyComparer: StringComparer.OrdinalIgnoreCase,
|
||||
valueComparer: StringComparer.OrdinalIgnoreCase);
|
||||
valueComparer: StringComparer.Ordinal);
|
||||
|
||||
if (solutionEntryPoint.GlobalProperties != null)
|
||||
{
|
||||
|
@ -279,9 +279,11 @@ namespace Microsoft.Build.Graph
|
|||
|
||||
IReadOnlyCollection<ProjectInSolution> projectsInSolution = GetBuildableProjects(solution);
|
||||
|
||||
SolutionConfigurationInSolution currentSolutionConfiguration = SelectSolutionConfiguration(solution, solutionEntryPoint.GlobalProperties);
|
||||
|
||||
// Mimic behavior of SolutionProjectGenerator
|
||||
SolutionConfigurationInSolution currentSolutionConfiguration = SelectSolutionConfiguration(solution, solutionEntryPoint.GlobalProperties);
|
||||
solutionGlobalPropertiesBuilder["Configuration"] = currentSolutionConfiguration.ConfigurationName;
|
||||
solutionGlobalPropertiesBuilder["Platform"] = currentSolutionConfiguration.PlatformName;
|
||||
|
||||
string solutionConfigurationXml = SolutionProjectGenerator.GetSolutionConfiguration(solution, currentSolutionConfiguration);
|
||||
solutionGlobalPropertiesBuilder["CurrentSolutionConfigurationContents"] = solutionConfigurationXml;
|
||||
solutionGlobalPropertiesBuilder["BuildingSolutionFile"] = "true";
|
||||
|
|
|
@ -338,7 +338,9 @@ namespace Microsoft.Build.BackEnd
|
|||
internal bool IsEventSerializable(BuildEventArgs e)
|
||||
{
|
||||
#pragma warning disable SYSLIB0050
|
||||
if (!e.GetType().GetTypeInfo().IsSerializable)
|
||||
// Types which are not serializable and are not IExtendedBuildEventArgs as
|
||||
// those always implement custom serialization by WriteToStream and CreateFromStream.
|
||||
if (!e.GetType().GetTypeInfo().IsSerializable && e is not IExtendedBuildEventArgs)
|
||||
#pragma warning restore SYSLIB0050
|
||||
{
|
||||
_loggingContext.LogWarning(null, new BuildEventFileInfo(string.Empty), "ExpectedEventToBeSerializable", e.GetType().Name);
|
||||
|
|
|
@ -1479,7 +1479,7 @@ namespace Microsoft.Build.Execution
|
|||
initialized = factory.Initialize(RegisteredName, ParameterGroupAndTaskBody.UsingTaskParameters, ParameterGroupAndTaskBody.InlineTaskXmlBody, taskFactoryLoggingHost);
|
||||
|
||||
// TaskFactoryParameters will always be null unless specifically created to have runtime and architecture parameters.
|
||||
if (TaskFactoryParameters != null)
|
||||
if (initialized && TaskFactoryParameters != null)
|
||||
{
|
||||
targetLoggingContext.LogWarning(
|
||||
null,
|
||||
|
@ -1493,7 +1493,7 @@ namespace Microsoft.Build.Execution
|
|||
}
|
||||
|
||||
// Throw an error if the ITaskFactory did not set the TaskType property. If the property is null, it can cause NullReferenceExceptions in our code
|
||||
if (factory.TaskType == null)
|
||||
if (initialized && factory.TaskType == null)
|
||||
{
|
||||
throw new InvalidOperationException(AssemblyResources.GetString("TaskFactoryTaskTypeIsNotSet"));
|
||||
}
|
||||
|
|
|
@ -156,6 +156,7 @@ namespace Microsoft.Build.Logging
|
|||
TaskCommandLine
|
||||
TaskParameter
|
||||
UninitializedPropertyRead
|
||||
ExtendedMessage
|
||||
BuildStatus
|
||||
TaskStarted
|
||||
TaskFinished
|
||||
|
@ -168,11 +169,13 @@ namespace Microsoft.Build.Logging
|
|||
ProjectEvaluationStarted
|
||||
ProjectEvaluationFinished
|
||||
BuildError
|
||||
ExtendedBuildError
|
||||
BuildWarning
|
||||
ExtendedBuildWarning
|
||||
CustomBuild
|
||||
ExternalProjectStarted
|
||||
ExternalProjectFinished
|
||||
|
||||
ExtendedCustomBuild
|
||||
*/
|
||||
|
||||
private void WriteCore(BuildEventArgs e)
|
||||
|
|
|
@ -31,7 +31,6 @@ namespace Microsoft.Build.Framework.UnitTests
|
|||
AssemblyLoadBuildEventArgs argDeserialized = new();
|
||||
int packetVersion = (Environment.Version.Major * 10) + Environment.Version.Minor;
|
||||
argDeserialized.CreateFromStream(br, packetVersion);
|
||||
|
||||
argDeserialized.LoadingInitiator.ShouldBe(loadingInitiator);
|
||||
argDeserialized.AssemblyName.ShouldBe(assemblyName);
|
||||
argDeserialized.AssemblyPath.ShouldBe(assemblyPath);
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.Build.Framework.UnitTests;
|
||||
|
||||
public class ExtendedBuildEventArgs_Tests
|
||||
{
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
[Theory]
|
||||
public void ExtendedCustomBuildEventArgs_SerializationDeserialization(bool withOptionalData)
|
||||
{
|
||||
ExtendedCustomBuildEventArgs arg = new(
|
||||
type: "TypeOfExtendedCustom",
|
||||
message: withOptionalData ? "a message with args {0} {1}" : null,
|
||||
helpKeyword: withOptionalData ? "MSBT123" : null,
|
||||
senderName: withOptionalData ? $"UnitTest {Guid.NewGuid()}" : null,
|
||||
eventTimestamp: withOptionalData ? DateTime.Parse("3/1/2017 11:11:56 AM") : DateTime.Now,
|
||||
messageArgs: withOptionalData ? new object[] { "arg0val", "arg1val" } : null)
|
||||
{
|
||||
ExtendedData = withOptionalData ? "{'long-json':'mostly-strings'}" : null,
|
||||
ExtendedMetadata = withOptionalData ? new Dictionary<string, string?> { {"m1", "v1" }, { "m2", "v2" } } : null,
|
||||
BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null,
|
||||
};
|
||||
|
||||
using MemoryStream stream = new MemoryStream();
|
||||
using BinaryWriter bw = new BinaryWriter(stream);
|
||||
arg.WriteToStream(bw);
|
||||
|
||||
stream.Position = 0;
|
||||
using BinaryReader br = new BinaryReader(stream);
|
||||
ExtendedCustomBuildEventArgs argDeserialized = new();
|
||||
argDeserialized.CreateFromStream(br, 80);
|
||||
|
||||
argDeserialized.Should().BeEquivalentTo(arg);
|
||||
}
|
||||
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
[Theory]
|
||||
public void ExtendedErrorEventArgs_SerializationDeserialization(bool withOptionalData)
|
||||
{
|
||||
ExtendedBuildErrorEventArgs arg = new(
|
||||
type: "TypeOfExtendedCustom",
|
||||
subcategory: withOptionalData ? "sub-type" : null,
|
||||
code: withOptionalData ? "a-code" : null,
|
||||
file: withOptionalData ? ".\\dev\\my.csproj" : null,
|
||||
lineNumber: withOptionalData ? 1 : default,
|
||||
columnNumber: withOptionalData ? 2 : default,
|
||||
endLineNumber: withOptionalData ? 3 : default,
|
||||
endColumnNumber: withOptionalData ? 4 : default,
|
||||
message: withOptionalData ? "a message with args {0} {1}" : null,
|
||||
helpKeyword: withOptionalData ? "MSBT123" : null,
|
||||
senderName: withOptionalData ? $"UnitTest {Guid.NewGuid()}" : null,
|
||||
helpLink: withOptionalData ? "(001)2234456" : null,
|
||||
eventTimestamp: withOptionalData ? DateTime.Parse("3/1/2017 11:11:56 AM") : DateTime.Now,
|
||||
messageArgs: withOptionalData ? new object[] { "arg0val", "arg1val" } : null)
|
||||
{
|
||||
ExtendedData = withOptionalData ? "{'long-json':'mostly-strings'}" : null,
|
||||
ExtendedMetadata = withOptionalData ? new Dictionary<string, string?> { { "m1", "v1" }, { "m2", "v2" } } : null,
|
||||
BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null,
|
||||
};
|
||||
|
||||
using MemoryStream stream = new MemoryStream();
|
||||
using BinaryWriter bw = new BinaryWriter(stream);
|
||||
arg.WriteToStream(bw);
|
||||
|
||||
stream.Position = 0;
|
||||
using BinaryReader br = new BinaryReader(stream);
|
||||
ExtendedBuildErrorEventArgs argDeserialized = new();
|
||||
argDeserialized.CreateFromStream(br, 80);
|
||||
|
||||
argDeserialized.Should().BeEquivalentTo(arg);
|
||||
}
|
||||
|
||||
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
[Theory]
|
||||
public void ExtendedWarningEventArgs_SerializationDeserialization(bool withOptionalData)
|
||||
{
|
||||
ExtendedBuildWarningEventArgs arg = new(
|
||||
type: "TypeOfExtendedCustom",
|
||||
subcategory: withOptionalData ? "sub-type" : null,
|
||||
code: withOptionalData ? "a-code" : null,
|
||||
file: withOptionalData ? ".\\dev\\my.csproj" : null,
|
||||
lineNumber: withOptionalData ? 1 : default,
|
||||
columnNumber: withOptionalData ? 2 : default,
|
||||
endLineNumber: withOptionalData ? 3 : default,
|
||||
endColumnNumber: withOptionalData ? 4 : default,
|
||||
message: withOptionalData ? "a message with args {0} {1}" : null,
|
||||
helpKeyword: withOptionalData ? "MSBT123" : null,
|
||||
senderName: withOptionalData ? $"UnitTest {Guid.NewGuid()}" : null,
|
||||
helpLink: withOptionalData ? "(001)2234456" : null,
|
||||
eventTimestamp: withOptionalData ? DateTime.Parse("3/1/2017 11:11:56 AM") : DateTime.Now,
|
||||
messageArgs: withOptionalData ? new object[] { "arg0val", "arg1val" } : null)
|
||||
{
|
||||
ExtendedData = withOptionalData ? "{'long-json':'mostly-strings'}" : null,
|
||||
ExtendedMetadata = withOptionalData ? new Dictionary<string, string?> { { "m1", "v1" }, { "m2", "v2" } } : null,
|
||||
BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null,
|
||||
};
|
||||
|
||||
using MemoryStream stream = new MemoryStream();
|
||||
using BinaryWriter bw = new BinaryWriter(stream);
|
||||
arg.WriteToStream(bw);
|
||||
|
||||
stream.Position = 0;
|
||||
using BinaryReader br = new BinaryReader(stream);
|
||||
ExtendedBuildWarningEventArgs argDeserialized = new();
|
||||
argDeserialized.CreateFromStream(br, 80);
|
||||
|
||||
argDeserialized.Should().BeEquivalentTo(arg);
|
||||
}
|
||||
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
[Theory]
|
||||
public void ExtendedMessageEventArgs_SerializationDeserialization(bool withOptionalData)
|
||||
{
|
||||
ExtendedBuildMessageEventArgs arg = new(
|
||||
type: "TypeOfExtendedCustom",
|
||||
subcategory: withOptionalData ? "sub-type" : null,
|
||||
code: withOptionalData ? "a-code" : null,
|
||||
file: withOptionalData ? ".\\dev\\my.csproj" : null,
|
||||
lineNumber: withOptionalData ? 1 : default,
|
||||
columnNumber: withOptionalData ? 2 : default,
|
||||
endLineNumber: withOptionalData ? 3 : default,
|
||||
endColumnNumber: withOptionalData ? 4 : default,
|
||||
message: withOptionalData ? "a message with args {0} {1}" : null,
|
||||
helpKeyword: withOptionalData ? "MSBT123" : null,
|
||||
senderName: withOptionalData ? $"UnitTest {Guid.NewGuid()}" : null,
|
||||
importance: withOptionalData ? MessageImportance.Normal : default,
|
||||
eventTimestamp: withOptionalData ? DateTime.Parse("3/1/2017 11:11:56 AM") : DateTime.Now,
|
||||
messageArgs: withOptionalData ? new object[] { "arg0val", "arg1val" } : null)
|
||||
{
|
||||
ExtendedData = withOptionalData ? "{'long-json':'mostly-strings'}" : null,
|
||||
ExtendedMetadata = withOptionalData ? new Dictionary<string, string?> { { "m1", "v1" }, { "m2", "v2" } } : null,
|
||||
BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null,
|
||||
};
|
||||
|
||||
using MemoryStream stream = new MemoryStream();
|
||||
using BinaryWriter bw = new BinaryWriter(stream);
|
||||
arg.WriteToStream(bw);
|
||||
|
||||
stream.Position = 0;
|
||||
using BinaryReader br = new BinaryReader(stream);
|
||||
ExtendedBuildMessageEventArgs argDeserialized = new();
|
||||
argDeserialized.CreateFromStream(br, 80);
|
||||
|
||||
argDeserialized.Should().BeEquivalentTo(arg);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendedCustomBuildEventArgs_Ctors()
|
||||
{
|
||||
var ea = new ExtendedCustomBuildEventArgs();
|
||||
ea = new ExtendedCustomBuildEventArgs("type");
|
||||
ea = new ExtendedCustomBuildEventArgs("type", "Message {0}", "Help", "sender");
|
||||
ea = new ExtendedCustomBuildEventArgs("type", "Message {0}", "Help", "sender", DateTime.Now);
|
||||
ea = new ExtendedCustomBuildEventArgs("type", "Message {0}", "Help", "sender", DateTime.Now, "arg1");
|
||||
ea = new ExtendedCustomBuildEventArgs("type");
|
||||
ea = new ExtendedCustomBuildEventArgs("type", null, null, null);
|
||||
ea = new ExtendedCustomBuildEventArgs("type", null, null, null, default(DateTime));
|
||||
ea = new ExtendedCustomBuildEventArgs("type", null, null, null, default(DateTime), null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendedBuildErrorEventArgs_Ctors()
|
||||
{
|
||||
var ea = new ExtendedBuildErrorEventArgs();
|
||||
ea = new ExtendedBuildErrorEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "sender");
|
||||
ea = new ExtendedBuildErrorEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "sender", DateTime.Now);
|
||||
ea = new ExtendedBuildErrorEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "sender", DateTime.Now, "Message");
|
||||
ea = new ExtendedBuildErrorEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "sender", "HelpLink", DateTime.Now, "Message");
|
||||
ea = new ExtendedBuildErrorEventArgs("type", null, null, null, 1, 2, 3, 4, null, null, null);
|
||||
ea = new ExtendedBuildErrorEventArgs("type", null, null, null, 1, 2, 3, 4, null, null, null, DateTime.Now);
|
||||
ea = new ExtendedBuildErrorEventArgs("type", null, null, null, 1, 2, 3, 4, null, null, null, null, DateTime.Now, null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendedBuildWarningEventArgs_Ctors()
|
||||
{
|
||||
var ea = new ExtendedBuildWarningEventArgs();
|
||||
ea = new ExtendedBuildWarningEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "sender");
|
||||
ea = new ExtendedBuildWarningEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "sender", DateTime.Now);
|
||||
ea = new ExtendedBuildWarningEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "sender", DateTime.Now, "Message");
|
||||
ea = new ExtendedBuildWarningEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "sender", "HelpLink", DateTime.Now, "Message");
|
||||
ea = new ExtendedBuildWarningEventArgs("type", null, null, null, 1, 2, 3, 4, null, null, null);
|
||||
ea = new ExtendedBuildWarningEventArgs("type", null, null, null, 1, 2, 3, 4, null, null, null, DateTime.Now);
|
||||
ea = new ExtendedBuildWarningEventArgs("type", null, null, null, 1, 2, 3, 4, null, null, null, null, DateTime.Now, null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendedBuildMessageEventArgs_Ctors()
|
||||
{
|
||||
var ea = new ExtendedBuildMessageEventArgs();
|
||||
ea = new ExtendedBuildMessageEventArgs("type");
|
||||
ea = new ExtendedBuildMessageEventArgs("type", "Message", "HelpKeyword", "sender", MessageImportance.High);
|
||||
ea = new ExtendedBuildMessageEventArgs("type", "Message", "HelpKeyword", "sender", MessageImportance.High, DateTime.Now);
|
||||
ea = new ExtendedBuildMessageEventArgs("type", "Message", "HelpKeyword", "sender", MessageImportance.High, DateTime.Now, "arg1");
|
||||
ea = new ExtendedBuildMessageEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "sender", MessageImportance.High);
|
||||
ea = new ExtendedBuildMessageEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "sender", MessageImportance.High, DateTime.Now);
|
||||
ea = new ExtendedBuildMessageEventArgs("type", "Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "sender", MessageImportance.High, DateTime.Now, "Message");
|
||||
ea = new ExtendedBuildMessageEventArgs("type");
|
||||
ea = new ExtendedBuildMessageEventArgs("type", null, null, null, default);
|
||||
ea = new ExtendedBuildMessageEventArgs("type", null, null, null, default, DateTime.Now);
|
||||
ea = new ExtendedBuildMessageEventArgs("type", null, null, null, default, default, null);
|
||||
ea = new ExtendedBuildMessageEventArgs("type", null, null, null, 1, 2, 3, 4, null, null, null, default);
|
||||
ea = new ExtendedBuildMessageEventArgs("type", null, null, null, 1, 2, 3, 4, null, null, null, default, DateTime.Now);
|
||||
ea = new ExtendedBuildMessageEventArgs("type", null, null, null, 1, 2, 3, 4, null, null, null, default, DateTime.Now, null);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" />
|
||||
<PackageReference Include="Microsoft.IO.Redist" Condition="'$(FeatureMSIORedist)' == 'true'" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Setup.Configuration.Interop" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" />
|
||||
<PackageReference Include="Shouldly" />
|
||||
|
|
|
@ -119,6 +119,26 @@ namespace Microsoft.Build.BackEnd
|
|||
value = _reader.ReadBoolean();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates an <see langword="bool"/> array.
|
||||
/// </summary>
|
||||
/// <param name="array">The array to be translated.</param>
|
||||
public void Translate(ref bool[] array)
|
||||
{
|
||||
if (!TranslateNullable(array))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int count = _reader.ReadInt32();
|
||||
array = new bool[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
array[i] = _reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates a byte.
|
||||
/// </summary>
|
||||
|
@ -891,6 +911,26 @@ namespace Microsoft.Build.BackEnd
|
|||
_writer.Write(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates an <see langword="bool"/> array.
|
||||
/// </summary>
|
||||
/// <param name="array">The array to be translated.</param>
|
||||
public void Translate(ref bool[] array)
|
||||
{
|
||||
if (!TranslateNullable(array))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int count = array.Length;
|
||||
_writer.Write(count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_writer.Write(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates a byte.
|
||||
/// </summary>
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Shared;
|
||||
|
||||
namespace Microsoft.Build.Framework;
|
||||
|
||||
/// <summary>
|
||||
/// Generic custom error events including extended data for event enriching.
|
||||
/// Extended data are implemented by <see cref="IExtendedBuildEventArgs"/>
|
||||
/// </summary>
|
||||
public sealed class ExtendedBuildErrorEventArgs : BuildErrorEventArgs, IExtendedBuildEventArgs
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ExtendedType { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, string?>? ExtendedMetadata { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string? ExtendedData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor. Used for deserialization.
|
||||
/// </summary>
|
||||
internal ExtendedBuildErrorEventArgs() : this("undefined") { }
|
||||
|
||||
/// <summary>
|
||||
/// This constructor specifies only type of extended data.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
public ExtendedBuildErrorEventArgs(string type) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor allows all event data to be initialized
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="subcategory">event sub-category</param>
|
||||
/// <param name="code">event code</param>
|
||||
/// <param name="file">file associated with the event</param>
|
||||
/// <param name="lineNumber">line number (0 if not applicable)</param>
|
||||
/// <param name="columnNumber">column number (0 if not applicable)</param>
|
||||
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
|
||||
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
public ExtendedBuildErrorEventArgs(string type, string? subcategory, string? code, string? file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber,
|
||||
string? message, string? helpKeyword, string? senderName)
|
||||
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor which allows a timestamp to be set
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="subcategory">event sub-category</param>
|
||||
/// <param name="code">event code</param>
|
||||
/// <param name="file">file associated with the event</param>
|
||||
/// <param name="lineNumber">line number (0 if not applicable)</param>
|
||||
/// <param name="columnNumber">column number (0 if not applicable)</param>
|
||||
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
|
||||
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
public ExtendedBuildErrorEventArgs(string type, string? subcategory, string? code, string? file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber,
|
||||
string? message, string? helpKeyword, string? senderName, DateTime eventTimestamp)
|
||||
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, eventTimestamp) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor which allows a timestamp to be set
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="subcategory">event sub-category</param>
|
||||
/// <param name="code">event code</param>
|
||||
/// <param name="file">file associated with the event</param>
|
||||
/// <param name="lineNumber">line number (0 if not applicable)</param>
|
||||
/// <param name="columnNumber">column number (0 if not applicable)</param>
|
||||
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
|
||||
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
/// <param name="messageArgs">message arguments</param>
|
||||
public ExtendedBuildErrorEventArgs(string type, string? subcategory, string? code, string? file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber,
|
||||
string? message, string? helpKeyword, string? senderName, DateTime eventTimestamp, params object[]? messageArgs)
|
||||
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, eventTimestamp, messageArgs) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor which allows a timestamp to be set
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="subcategory">event sub-category</param>
|
||||
/// <param name="code">event code</param>
|
||||
/// <param name="file">file associated with the event</param>
|
||||
/// <param name="lineNumber">line number (0 if not applicable)</param>
|
||||
/// <param name="columnNumber">column number (0 if not applicable)</param>
|
||||
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
|
||||
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="helpLink">A link pointing to more information about the error </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
/// <param name="messageArgs">message arguments</param>
|
||||
public ExtendedBuildErrorEventArgs(string type, string? subcategory, string? code, string? file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber,
|
||||
string? message, string? helpKeyword, string? senderName, string? helpLink, DateTime eventTimestamp, params object[]? messageArgs)
|
||||
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, helpLink, eventTimestamp, messageArgs) => ExtendedType = type;
|
||||
|
||||
internal override void WriteToStream(BinaryWriter writer)
|
||||
{
|
||||
base.WriteToStream(writer);
|
||||
writer.WriteExtendedBuildEventData(this);
|
||||
}
|
||||
|
||||
internal override void CreateFromStream(BinaryReader reader, int version)
|
||||
{
|
||||
base.CreateFromStream(reader, version);
|
||||
reader.ReadExtendedBuildEventData(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Shared;
|
||||
|
||||
namespace Microsoft.Build.Framework;
|
||||
|
||||
/// <summary>
|
||||
/// Generic custom build events including extended data for event enriching.
|
||||
/// Extended data are implemented by <see cref="IExtendedBuildEventArgs"/>
|
||||
/// </summary>
|
||||
public sealed class ExtendedBuildMessageEventArgs : BuildMessageEventArgs, IExtendedBuildEventArgs
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ExtendedType { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, string?>? ExtendedMetadata { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string? ExtendedData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor. Used for deserialization.
|
||||
/// </summary>
|
||||
internal ExtendedBuildMessageEventArgs() : this("undefined") { }
|
||||
|
||||
/// <summary>
|
||||
/// This constructor specifies only type of extended data.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
public ExtendedBuildMessageEventArgs(string type) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor allows all event data to be initialized
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="importance">importance of the message</param>
|
||||
public ExtendedBuildMessageEventArgs(string type, string? message, string? helpKeyword, string? senderName, MessageImportance importance)
|
||||
: base(message, helpKeyword, senderName, importance) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor allows a timestamp to be set
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="importance">importance of the message</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
public ExtendedBuildMessageEventArgs(string type, string? message, string? helpKeyword, string? senderName, MessageImportance importance, DateTime eventTimestamp)
|
||||
: base(message, helpKeyword, senderName, importance, eventTimestamp) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor allows a timestamp to be set
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="importance">importance of the message</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
/// <param name="messageArgs">message arguments</param>
|
||||
public ExtendedBuildMessageEventArgs(string type, string? message, string? helpKeyword, string? senderName, MessageImportance importance, DateTime eventTimestamp, params object[]? messageArgs)
|
||||
: base(message, helpKeyword, senderName, importance, eventTimestamp, messageArgs) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor allows all event data to be initialized
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="subcategory">event sub-category</param>
|
||||
/// <param name="code">event code</param>
|
||||
/// <param name="file">file associated with the event</param>
|
||||
/// <param name="lineNumber">line number (0 if not applicable)</param>
|
||||
/// <param name="columnNumber">column number (0 if not applicable)</param>
|
||||
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
|
||||
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="importance">importance of the message</param>
|
||||
public ExtendedBuildMessageEventArgs(string type, string? subcategory, string? code, string? file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber,
|
||||
string? message, string? helpKeyword, string? senderName, MessageImportance importance)
|
||||
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, importance) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor which allows a timestamp to be set
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="subcategory">event sub-category</param>
|
||||
/// <param name="code">event code</param>
|
||||
/// <param name="file">file associated with the event</param>
|
||||
/// <param name="lineNumber">line number (0 if not applicable)</param>
|
||||
/// <param name="columnNumber">column number (0 if not applicable)</param>
|
||||
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
|
||||
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="importance">importance of the message</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
public ExtendedBuildMessageEventArgs(string type, string? subcategory, string? code, string? file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber,
|
||||
string? message, string? helpKeyword, string? senderName, MessageImportance importance, DateTime eventTimestamp)
|
||||
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, importance, eventTimestamp) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor which allows a timestamp to be set
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="subcategory">event sub-category</param>
|
||||
/// <param name="code">event code</param>
|
||||
/// <param name="file">file associated with the event</param>
|
||||
/// <param name="lineNumber">line number (0 if not applicable)</param>
|
||||
/// <param name="columnNumber">column number (0 if not applicable)</param>
|
||||
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
|
||||
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="importance">importance of the message</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
/// <param name="messageArgs">message arguments</param>
|
||||
public ExtendedBuildMessageEventArgs(string type, string? subcategory, string? code, string? file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber,
|
||||
string? message, string? helpKeyword, string? senderName, MessageImportance importance, DateTime eventTimestamp, params object[]? messageArgs)
|
||||
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, importance, eventTimestamp, messageArgs) => ExtendedType = type;
|
||||
|
||||
internal override void WriteToStream(BinaryWriter writer)
|
||||
{
|
||||
base.WriteToStream(writer);
|
||||
writer.WriteExtendedBuildEventData(this);
|
||||
}
|
||||
|
||||
internal override void CreateFromStream(BinaryReader reader, int version)
|
||||
{
|
||||
base.CreateFromStream(reader, version);
|
||||
reader.ReadExtendedBuildEventData(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Shared;
|
||||
|
||||
namespace Microsoft.Build.Framework;
|
||||
|
||||
/// <summary>
|
||||
/// Generic custom warning events including extended data for event enriching.
|
||||
/// Extended data are implemented by <see cref="IExtendedBuildEventArgs"/>
|
||||
/// </summary>
|
||||
public sealed class ExtendedBuildWarningEventArgs : BuildWarningEventArgs, IExtendedBuildEventArgs
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ExtendedType { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, string?>? ExtendedMetadata { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string? ExtendedData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor. Used for deserialization.
|
||||
/// </summary>
|
||||
internal ExtendedBuildWarningEventArgs() : this("undefined") { }
|
||||
|
||||
/// <summary>
|
||||
/// This constructor specifies only type of extended data.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
public ExtendedBuildWarningEventArgs(string type) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor allows all event data to be initialized
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="subcategory">event sub-category</param>
|
||||
/// <param name="code">event code</param>
|
||||
/// <param name="file">file associated with the event</param>
|
||||
/// <param name="lineNumber">line number (0 if not applicable)</param>
|
||||
/// <param name="columnNumber">column number (0 if not applicable)</param>
|
||||
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
|
||||
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
public ExtendedBuildWarningEventArgs(string type, string? subcategory, string? code, string? file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber,
|
||||
string? message, string? helpKeyword, string? senderName)
|
||||
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor which allows a timestamp to be set
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="subcategory">event sub-category</param>
|
||||
/// <param name="code">event code</param>
|
||||
/// <param name="file">file associated with the event</param>
|
||||
/// <param name="lineNumber">line number (0 if not applicable)</param>
|
||||
/// <param name="columnNumber">column number (0 if not applicable)</param>
|
||||
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
|
||||
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
public ExtendedBuildWarningEventArgs(string type, string? subcategory, string? code, string? file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber,
|
||||
string? message, string? helpKeyword, string? senderName, DateTime eventTimestamp)
|
||||
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, eventTimestamp) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor which allows a timestamp to be set
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="subcategory">event sub-category</param>
|
||||
/// <param name="code">event code</param>
|
||||
/// <param name="file">file associated with the event</param>
|
||||
/// <param name="lineNumber">line number (0 if not applicable)</param>
|
||||
/// <param name="columnNumber">column number (0 if not applicable)</param>
|
||||
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
|
||||
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
/// <param name="messageArgs">message arguments</param>
|
||||
public ExtendedBuildWarningEventArgs(string type, string? subcategory, string? code, string? file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber,
|
||||
string? message, string? helpKeyword, string? senderName, DateTime eventTimestamp, params object[]? messageArgs)
|
||||
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, eventTimestamp, messageArgs) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor which allows a timestamp to be set
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="subcategory">event sub-category</param>
|
||||
/// <param name="code">event code</param>
|
||||
/// <param name="file">file associated with the event</param>
|
||||
/// <param name="lineNumber">line number (0 if not applicable)</param>
|
||||
/// <param name="columnNumber">column number (0 if not applicable)</param>
|
||||
/// <param name="endLineNumber">end line number (0 if not applicable)</param>
|
||||
/// <param name="endColumnNumber">end column number (0 if not applicable)</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="helpLink">A link pointing to more information about the error </param>
|
||||
/// <param name="senderName">name of event sender</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
/// <param name="messageArgs">message arguments</param>
|
||||
public ExtendedBuildWarningEventArgs(string type, string? subcategory, string? code, string? file, int lineNumber, int columnNumber, int endLineNumber, int endColumnNumber,
|
||||
string? message, string? helpKeyword, string? senderName, string? helpLink, DateTime eventTimestamp, params object[]? messageArgs)
|
||||
: base(subcategory, code, file, lineNumber, columnNumber, endLineNumber, endColumnNumber, message, helpKeyword, senderName, helpLink, eventTimestamp, messageArgs) => ExtendedType = type;
|
||||
|
||||
internal override void WriteToStream(BinaryWriter writer)
|
||||
{
|
||||
base.WriteToStream(writer);
|
||||
writer.WriteExtendedBuildEventData(this);
|
||||
}
|
||||
|
||||
internal override void CreateFromStream(BinaryReader reader, int version)
|
||||
{
|
||||
base.CreateFromStream(reader, version);
|
||||
reader.ReadExtendedBuildEventData(this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Shared;
|
||||
|
||||
namespace Microsoft.Build.Framework;
|
||||
|
||||
/// <summary>
|
||||
/// Generic custom event.
|
||||
/// Extended data are implemented by <see cref="IExtendedBuildEventArgs"/>
|
||||
/// </summary>
|
||||
public sealed class ExtendedCustomBuildEventArgs : CustomBuildEventArgs, IExtendedBuildEventArgs
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string ExtendedType { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, string?>? ExtendedMetadata { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string? ExtendedData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This constructor allows event data to be initialized.
|
||||
/// </summary>
|
||||
/// <seealso cref="IExtendedBuildEventArgs.ExtendedType"/>
|
||||
internal ExtendedCustomBuildEventArgs() : this("undefined") {}
|
||||
|
||||
/// <summary>
|
||||
/// This constructor allows event data to be initialized.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <seealso cref="IExtendedBuildEventArgs.ExtendedType"/>
|
||||
public ExtendedCustomBuildEventArgs(string type) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor allows event data to be initialized.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of sender</param>
|
||||
public ExtendedCustomBuildEventArgs(string type, string? message, string? helpKeyword, string? senderName) : base(message, helpKeyword, senderName) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor allows event data to be initialized including timestamp.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of sender</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
public ExtendedCustomBuildEventArgs(string type, string? message, string? helpKeyword, string? senderName, DateTime eventTimestamp) : base(message, helpKeyword, senderName, eventTimestamp) => ExtendedType = type;
|
||||
|
||||
/// <summary>
|
||||
/// This constructor allows event data to be initialized including timestamp.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of <see cref="IExtendedBuildEventArgs.ExtendedType"/>.</param>
|
||||
/// <param name="message">text message</param>
|
||||
/// <param name="helpKeyword">help keyword </param>
|
||||
/// <param name="senderName">name of sender</param>
|
||||
/// <param name="eventTimestamp">Timestamp when event was created</param>
|
||||
/// <param name="messageArgs">Message arguments</param>
|
||||
public ExtendedCustomBuildEventArgs(string type, string? message, string? helpKeyword, string? senderName, DateTime eventTimestamp, params object[]? messageArgs) : base(message, helpKeyword, senderName, eventTimestamp, messageArgs) => ExtendedType = type;
|
||||
|
||||
internal override void WriteToStream(BinaryWriter writer)
|
||||
{
|
||||
base.WriteToStream(writer);
|
||||
writer.WriteExtendedBuildEventData(this);
|
||||
}
|
||||
|
||||
internal override void CreateFromStream(BinaryReader reader, int version)
|
||||
{
|
||||
base.CreateFromStream(reader, version);
|
||||
reader.ReadExtendedBuildEventData(this);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Shared;
|
||||
|
||||
#nullable disable
|
||||
|
||||
|
@ -16,6 +18,8 @@ namespace Microsoft.Build.Framework
|
|||
// immutable; adding new fields in the next version of the type
|
||||
// without following certain special FX guidelines, can break both
|
||||
// forward and backward compatibility
|
||||
// NOTE: Although this class has been modified and do not longer relay on [Serializable]
|
||||
// and BinaryFormatter. We have left it [Serializable] for backward compatibility reasons.
|
||||
[Serializable]
|
||||
public class ExternalProjectFinishedEventArgs : CustomBuildEventArgs
|
||||
{
|
||||
|
@ -93,5 +97,19 @@ namespace Microsoft.Build.Framework
|
|||
return succeeded;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void WriteToStream(BinaryWriter writer)
|
||||
{
|
||||
base.WriteToStream(writer);
|
||||
writer.WriteOptionalString(projectFile);
|
||||
writer.Write(succeeded);
|
||||
}
|
||||
|
||||
internal override void CreateFromStream(BinaryReader reader, int version)
|
||||
{
|
||||
base.CreateFromStream(reader, version);
|
||||
projectFile = reader.ReadOptionalString();
|
||||
succeeded = reader.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Shared;
|
||||
|
||||
#nullable disable
|
||||
|
||||
|
@ -16,6 +18,8 @@ namespace Microsoft.Build.Framework
|
|||
// immutable; adding new fields in the next version of the type
|
||||
// without following certain special FX guidelines, can break both
|
||||
// forward and backward compatibility
|
||||
// NOTE: Although this class has been modified and do not longer relay on [Serializable]
|
||||
// and BinaryFormatter. We have left it [Serializable] for backward compatibility reasons.
|
||||
[Serializable]
|
||||
public class ExternalProjectStartedEventArgs : CustomBuildEventArgs
|
||||
{
|
||||
|
@ -95,5 +99,19 @@ namespace Microsoft.Build.Framework
|
|||
return targetNames;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void WriteToStream(BinaryWriter writer)
|
||||
{
|
||||
base.WriteToStream(writer);
|
||||
writer.WriteOptionalString(projectFile);
|
||||
writer.WriteOptionalString(targetNames);
|
||||
}
|
||||
|
||||
internal override void CreateFromStream(BinaryReader reader, int version)
|
||||
{
|
||||
base.CreateFromStream(reader, version);
|
||||
projectFile = reader.ReadOptionalString();
|
||||
targetNames = reader.ReadOptionalString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Build.Framework;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for Extended EventArgs to allow enriching particular events with extended data.
|
||||
/// Deriving from EventArgs will be deprecated soon and using Extended EventArgs is recommended for custom Event Args.
|
||||
/// </summary>
|
||||
public interface IExtendedBuildEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique string identifying type of extended data so receiver side knows how to interpret, deserialize and handle <see cref="ExtendedData"/>.
|
||||
/// </summary>
|
||||
string ExtendedType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Metadata of <see cref="ExtendedData"/>.
|
||||
/// Example usage:
|
||||
/// - data which needed in custom code to properly routing this message without interpreting/deserializing <see cref="ExtendedData"/>.
|
||||
/// - simple extended data can be transferred in form of dictionary key-value per one extended property.
|
||||
/// </summary>
|
||||
Dictionary<string, string?>? ExtendedMetadata { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Transparent data as string.
|
||||
/// Custom code is responsible to serialize and deserialize this string to structured data - if needed.
|
||||
/// Custom code can use any serialization they deem safe - e.g. json for textual data, base64 for binary data...
|
||||
/// </summary>
|
||||
string? ExtendedData { get; set; }
|
||||
}
|
|
@ -107,6 +107,12 @@ namespace Microsoft.Build.BackEnd
|
|||
/// <param name="value">The value to be translated.</param>
|
||||
void Translate(ref bool value);
|
||||
|
||||
/// <summary>
|
||||
/// Translates an <see langword="bool"/> array.
|
||||
/// </summary>
|
||||
/// <param name="array">The array to be translated.</param>
|
||||
void Translate(ref bool[] array);
|
||||
|
||||
/// <summary>
|
||||
/// Translates a byte.
|
||||
/// </summary>
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using Microsoft.Build.Shared;
|
||||
using System.IO;
|
||||
|
||||
#nullable disable
|
||||
|
||||
|
@ -27,5 +29,19 @@ namespace Microsoft.Build.Framework
|
|||
this.metaprojectXml = metaprojectXml;
|
||||
this.ProjectFile = metaprojectPath;
|
||||
}
|
||||
|
||||
internal override void WriteToStream(BinaryWriter writer)
|
||||
{
|
||||
base.WriteToStream(writer);
|
||||
|
||||
writer.WriteOptionalString(metaprojectXml);
|
||||
}
|
||||
|
||||
internal override void CreateFromStream(BinaryReader reader, int version)
|
||||
{
|
||||
base.CreateFromStream(reader, version);
|
||||
|
||||
metaprojectXml = reader.ReadOptionalString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Shared;
|
||||
|
||||
#nullable disable
|
||||
|
||||
|
@ -56,5 +58,23 @@ namespace Microsoft.Build.Framework
|
|||
/// The source of the property.
|
||||
/// </summary>
|
||||
public string PropertySource { get; set; }
|
||||
|
||||
internal override void WriteToStream(BinaryWriter writer)
|
||||
{
|
||||
base.WriteToStream(writer);
|
||||
|
||||
writer.WriteOptionalString(PropertyName);
|
||||
writer.WriteOptionalString(PropertyValue);
|
||||
writer.WriteOptionalString(PropertySource);
|
||||
}
|
||||
|
||||
internal override void CreateFromStream(BinaryReader reader, int version)
|
||||
{
|
||||
base.CreateFromStream(reader, version);
|
||||
|
||||
PropertyName = reader.ReadOptionalString();
|
||||
PropertyValue = reader.ReadOptionalString();
|
||||
PropertySource = reader.ReadOptionalString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Shared;
|
||||
|
||||
#nullable disable
|
||||
|
||||
|
@ -79,5 +81,25 @@ namespace Microsoft.Build.Framework
|
|||
return RawMessage;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void WriteToStream(BinaryWriter writer)
|
||||
{
|
||||
base.WriteToStream(writer);
|
||||
|
||||
writer.WriteOptionalString(PropertyName);
|
||||
writer.WriteOptionalString(NewValue);
|
||||
writer.WriteOptionalString(PreviousValue);
|
||||
writer.WriteOptionalString(Location);
|
||||
}
|
||||
|
||||
internal override void CreateFromStream(BinaryReader reader, int version)
|
||||
{
|
||||
base.CreateFromStream(reader, version);
|
||||
|
||||
PropertyName = reader.ReadOptionalString();
|
||||
NewValue = reader.ReadOptionalString();
|
||||
PreviousValue = reader.ReadOptionalString();
|
||||
Location = reader.ReadOptionalString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -372,6 +372,29 @@ namespace Microsoft.Build.Framework
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows displaying the deprecation warning for BinaryFormatter in your current environment.
|
||||
/// </summary>
|
||||
public bool EnableWarningOnCustomBuildEvent
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = Environment.GetEnvironmentVariable("MSBUILDCUSTOMBUILDEVENTWARNING");
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
// If variable is not set explicitly, for .NETCORE warning appears.
|
||||
#if RUNTIME_TYPE_NETCORE
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
return value == "1";
|
||||
}
|
||||
}
|
||||
|
||||
private static bool? ParseNullableBoolFromEnvironmentVariable(string environmentVariable)
|
||||
{
|
||||
var value = Environment.GetEnvironmentVariable(environmentVariable);
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Build.Shared;
|
||||
|
||||
#nullable disable
|
||||
|
||||
|
@ -42,5 +44,18 @@ namespace Microsoft.Build.Framework
|
|||
/// The name of the uninitialized property that was read.
|
||||
/// </summary>
|
||||
public string PropertyName { get; set; }
|
||||
|
||||
internal override void WriteToStream(BinaryWriter writer)
|
||||
{
|
||||
base.WriteToStream(writer);
|
||||
|
||||
writer.WriteOptionalString(PropertyName);
|
||||
}
|
||||
internal override void CreateFromStream(BinaryReader reader, int version)
|
||||
{
|
||||
base.CreateFromStream(reader, version);
|
||||
|
||||
PropertyName = reader.ReadOptionalString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@
|
|||
|
||||
<!-- Xsds are not TF or arch-specific so copy once them in the outer build -->
|
||||
<Target Name="CopyXsds" BeforeTargets="Build" Condition="'$(IsInnerBuild)' != 'true'">
|
||||
<Copy SourceFiles="@(XsdsForVS)" DestinationFiles="@(XsdsForVS->'$([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'xsd'))%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="$(SkipCopyUnchangedFiles)" />
|
||||
<Copy SourceFiles="@(XsdsForVS)" DestinationFiles="@(XsdsForVS->'$([MSBuild]::NormalizeDirectory('$(ArtifactsDir)', 'xsd'))%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
|
||||
<!-- Include MSBuild.deps.json and MSBuild.runtimeconfig.json in ContentWithTargetPath so they will be copied to the output folder of projects
|
||||
|
|
|
@ -1179,7 +1179,9 @@ namespace Microsoft.Build.CommandLine
|
|||
if (_nodeEndpoint?.LinkStatus == LinkStatus.Active)
|
||||
{
|
||||
#pragma warning disable SYSLIB0050
|
||||
if (!e.GetType().GetTypeInfo().IsSerializable)
|
||||
// Types which are not serializable and are not IExtendedBuildEventArgs as
|
||||
// those always implement custom serialization by WriteToStream and CreateFromStream.
|
||||
if (!e.GetType().GetTypeInfo().IsSerializable && e is not IExtendedBuildEventArgs)
|
||||
#pragma warning disable SYSLIB0050
|
||||
{
|
||||
// log a warning and bail. This will end up re-calling SendBuildEvent, but we know for a fact
|
||||
|
@ -1188,7 +1190,8 @@ namespace Microsoft.Build.CommandLine
|
|||
return;
|
||||
}
|
||||
|
||||
_nodeEndpoint.SendData(new LogMessagePacket(new KeyValuePair<int, BuildEventArgs>(_currentConfiguration.NodeId, e)));
|
||||
LogMessagePacket logMessage = new LogMessagePacket(new KeyValuePair<int, BuildEventArgs>(_currentConfiguration.NodeId, e));
|
||||
_nodeEndpoint.SendData(logMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1413,7 +1413,7 @@ Když se nastaví na MessageUponIsolationViolation (nebo jeho krátký
|
|||
</trans-unit>
|
||||
<trans-unit id="NameInvalid">
|
||||
<source>MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</source>
|
||||
<target state="new">MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</target>
|
||||
<target state="translated">MSBUILD : error MSB5016: Název {0} obsahuje neplatný znak {1}.</target>
|
||||
<note>
|
||||
{StrBegin="MSBUILD : error MSB5016: "}
|
||||
</note>
|
||||
|
|
|
@ -1400,7 +1400,7 @@ Dieses Protokollierungsformat ist standardmäßig aktiviert.
|
|||
</trans-unit>
|
||||
<trans-unit id="NameInvalid">
|
||||
<source>MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</source>
|
||||
<target state="new">MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</target>
|
||||
<target state="translated">MSBUILD : error MSB5016: Der Name "{0}" enthält ein ungültiges Zeichen "{1}".</target>
|
||||
<note>
|
||||
{StrBegin="MSBUILD : error MSB5016: "}
|
||||
</note>
|
||||
|
|
|
@ -1407,7 +1407,7 @@
|
|||
</trans-unit>
|
||||
<trans-unit id="NameInvalid">
|
||||
<source>MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</source>
|
||||
<target state="new">MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</target>
|
||||
<target state="translated">MSBUILD : error MSB5016: El nombre "{0}" contiene un carácter no válido "{1}".</target>
|
||||
<note>
|
||||
{StrBegin="MSBUILD : error MSB5016: "}
|
||||
</note>
|
||||
|
|
|
@ -1400,7 +1400,7 @@ Remarque : verbosité des enregistreurs d’événements de fichiers
|
|||
</trans-unit>
|
||||
<trans-unit id="NameInvalid">
|
||||
<source>MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</source>
|
||||
<target state="new">MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</target>
|
||||
<target state="translated">MSBUILD : error MSB5016: le nom «{0}» contient un caractère non valide «{1}».</target>
|
||||
<note>
|
||||
{StrBegin="MSBUILD : error MSB5016: "}
|
||||
</note>
|
||||
|
|
|
@ -1400,7 +1400,7 @@
|
|||
</trans-unit>
|
||||
<trans-unit id="NameInvalid">
|
||||
<source>MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</source>
|
||||
<target state="new">MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</target>
|
||||
<target state="translated">MSBUILD : error MSB5016: "{0}" 이름에 잘못된 문자 "{1}"이(가) 사용되었습니다.</target>
|
||||
<note>
|
||||
{StrBegin="MSBUILD : error MSB5016: "}
|
||||
</note>
|
||||
|
|
|
@ -1401,7 +1401,7 @@ arquivo de resposta.
|
|||
</trans-unit>
|
||||
<trans-unit id="NameInvalid">
|
||||
<source>MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</source>
|
||||
<target state="new">MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</target>
|
||||
<target state="translated">MSBUILD : error MSB5016: O nome "{0}" contém um caractere inválido "{1}".</target>
|
||||
<note>
|
||||
{StrBegin="MSBUILD : error MSB5016: "}
|
||||
</note>
|
||||
|
|
|
@ -1404,7 +1404,7 @@
|
|||
</trans-unit>
|
||||
<trans-unit id="NameInvalid">
|
||||
<source>MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</source>
|
||||
<target state="new">MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</target>
|
||||
<target state="translated">MSBUILD : error MSB5016: "{0}" adı "{1}" geçersiz karakterini içeriyor.</target>
|
||||
<note>
|
||||
{StrBegin="MSBUILD : error MSB5016: "}
|
||||
</note>
|
||||
|
|
|
@ -1400,7 +1400,7 @@
|
|||
</trans-unit>
|
||||
<trans-unit id="NameInvalid">
|
||||
<source>MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</source>
|
||||
<target state="new">MSBUILD : error MSB5016: The name "{0}" contains an invalid character "{1}".</target>
|
||||
<target state="translated">MSBUILD : error MSB5016: 名称“{0}”包含无效字符“{1}”。</target>
|
||||
<note>
|
||||
{StrBegin="MSBUILD : error MSB5016: "}
|
||||
</note>
|
||||
|
|
|
@ -61,6 +61,9 @@
|
|||
<Compile Include="..\Framework\ITaskItem2.cs">
|
||||
<Link>ITaskItem2.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Framework\IExtendedBuildEventArgs.cs">
|
||||
<Link>IExtendedBuildEventArgs.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Framework\AssemblyUtilities.cs" />
|
||||
<Compile Include="..\Framework\ResponseFileUsedEventArgs.cs" />
|
||||
<Compile Include="..\Shared\BufferedReadStream.cs" />
|
||||
|
|
|
@ -18,6 +18,6 @@
|
|||
|
||||
<!-- This is only needed for a test in the MSBuild repo; it is unrelated to the PortableTask sample itself. -->
|
||||
<Target Name="CopyMSBuildUtilitiesToNewFolder" BeforeTargets="CopyFilesToOutputDirectory">
|
||||
<Copy SourceFiles="$(PkgMicrosoft_Build_Utilities_Core)\lib\net46\Microsoft.Build.Utilities.Core.dll" DestinationFiles="$(OutDir)\OldMSBuild\Microsoft.Build.Utilities.Core.dll" />
|
||||
<Copy SourceFiles="$(PkgMicrosoft_Build_Utilities_Core)\lib\net46\Microsoft.Build.Utilities.Core.dll" DestinationFiles="$(OutDir)\OldMSBuild\Microsoft.Build.Utilities.Core.dll" SkipUnchangedFiles="true"/>
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
@ -99,5 +99,30 @@ namespace Microsoft.Build.Shared
|
|||
{
|
||||
return new Guid(reader.ReadBytes(sizeof(Guid)));
|
||||
}
|
||||
|
||||
public static void ReadExtendedBuildEventData(this BinaryReader reader, IExtendedBuildEventArgs data)
|
||||
{
|
||||
data.ExtendedType = reader.ReadString();
|
||||
data.ExtendedData = reader.ReadOptionalString();
|
||||
|
||||
bool haveMetadata = reader.ReadBoolean();
|
||||
if (haveMetadata)
|
||||
{
|
||||
data.ExtendedMetadata = new();
|
||||
|
||||
int count = reader.Read7BitEncodedInt();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
string key = reader.ReadString();
|
||||
string? value = reader.ReadOptionalString();
|
||||
|
||||
data.ExtendedMetadata.Add(key, value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data.ExtendedMetadata = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.Build.Framework;
|
||||
|
@ -111,5 +112,22 @@ namespace Microsoft.Build.Shared
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void WriteExtendedBuildEventData(this BinaryWriter writer, IExtendedBuildEventArgs data)
|
||||
{
|
||||
writer.Write(data.ExtendedType);
|
||||
writer.WriteOptionalString(data.ExtendedData);
|
||||
|
||||
writer.Write(data.ExtendedMetadata != null);
|
||||
if (data.ExtendedMetadata != null)
|
||||
{
|
||||
writer.Write7BitEncodedInt(data.ExtendedMetadata.Count);
|
||||
foreach (KeyValuePair<string, string?> kvp in data.ExtendedMetadata)
|
||||
{
|
||||
writer.Write(kvp.Key);
|
||||
writer.WriteOptionalString(kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,6 +145,61 @@ namespace Microsoft.Build.Shared
|
|||
/// Event is an AssemblyLoadBuildEventArgs
|
||||
/// </summary>
|
||||
AssemblyLoadEvent = 21,
|
||||
|
||||
/// <summary>
|
||||
/// Event is <see cref="ExternalProjectStartedEventArgs"/>
|
||||
/// </summary>
|
||||
ExternalProjectStartedEvent = 22,
|
||||
|
||||
/// <summary>
|
||||
/// Event is <see cref="ExternalProjectFinishedEventArgs"/>
|
||||
/// </summary>
|
||||
ExternalProjectFinishedEvent = 23,
|
||||
|
||||
/// <summary>
|
||||
/// Event is <see cref="ExtendedCustomBuildEventArgs"/>
|
||||
/// </summary>
|
||||
ExtendedCustomEvent = 24,
|
||||
|
||||
/// <summary>
|
||||
/// Event is <see cref="ExtendedBuildErrorEventArgs"/>
|
||||
/// </summary>
|
||||
ExtendedBuildErrorEvent = 25,
|
||||
|
||||
/// <summary>
|
||||
/// Event is <see cref="ExtendedBuildWarningEventArgs"/>
|
||||
/// </summary>
|
||||
ExtendedBuildWarningEvent = 26,
|
||||
|
||||
/// <summary>
|
||||
/// Event is <see cref="ExtendedBuildMessageEventArgs"/>
|
||||
/// </summary>
|
||||
ExtendedBuildMessageEvent = 27,
|
||||
|
||||
/// <summary>
|
||||
/// Event is <see cref="CriticalBuildMessageEventArgs"/>
|
||||
/// </summary>
|
||||
CriticalBuildMessage = 28,
|
||||
|
||||
/// <summary>
|
||||
/// Event is <see cref="MetaprojectGeneratedEventArgs"/>
|
||||
/// </summary>
|
||||
MetaprojectGenerated = 29,
|
||||
|
||||
/// <summary>
|
||||
/// Event is <see cref="PropertyInitialValueSetEventArgs"/>
|
||||
/// </summary>
|
||||
PropertyInitialValueSet = 30,
|
||||
|
||||
/// <summary>
|
||||
/// Event is <see cref="PropertyReassignmentEventArgs"/>
|
||||
/// </summary>
|
||||
PropertyReassignment = 31,
|
||||
|
||||
/// <summary>
|
||||
/// Event is <see cref="UninitializedPropertyReadEventArgs"/>
|
||||
/// </summary>
|
||||
UninitializedPropertyRead = 32
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -230,8 +285,9 @@ namespace Microsoft.Build.Shared
|
|||
/// <summary>
|
||||
/// Constructor for deserialization
|
||||
/// </summary>
|
||||
protected LogMessagePacketBase(ITranslator translator)
|
||||
protected LogMessagePacketBase(ITranslator translator, TargetFinishedTranslator targetFinishedTranslator = null)
|
||||
{
|
||||
_targetFinishedTranslator = targetFinishedTranslator;
|
||||
Translate(translator);
|
||||
}
|
||||
|
||||
|
@ -339,7 +395,8 @@ namespace Microsoft.Build.Shared
|
|||
#if !TASKHOST && !MSBUILDENTRYPOINTEXE
|
||||
if (_buildEvent is ProjectEvaluationStartedEventArgs
|
||||
or ProjectEvaluationFinishedEventArgs
|
||||
or EnvironmentVariableReadEventArgs)
|
||||
or EnvironmentVariableReadEventArgs
|
||||
or ResponseFileUsedEventArgs)
|
||||
{
|
||||
// switch to serialization methods that we provide in this file
|
||||
// and don't use the WriteToStream inherited from LazyFormattedBuildEventArgs
|
||||
|
@ -536,6 +593,17 @@ namespace Microsoft.Build.Shared
|
|||
LoggingEventType.ProjectImportedEvent => new ProjectImportedEventArgs(),
|
||||
LoggingEventType.TargetSkipped => new TargetSkippedEventArgs(),
|
||||
LoggingEventType.Telemetry => new TelemetryEventArgs(),
|
||||
LoggingEventType.ExtendedCustomEvent => new ExtendedCustomBuildEventArgs(),
|
||||
LoggingEventType.ExtendedBuildErrorEvent => new ExtendedBuildErrorEventArgs(),
|
||||
LoggingEventType.ExtendedBuildWarningEvent => new ExtendedBuildWarningEventArgs(),
|
||||
LoggingEventType.ExtendedBuildMessageEvent => new ExtendedBuildMessageEventArgs(),
|
||||
LoggingEventType.ExternalProjectStartedEvent => new ExternalProjectStartedEventArgs(null, null, null, null, null),
|
||||
LoggingEventType.ExternalProjectFinishedEvent => new ExternalProjectFinishedEventArgs(null, null, null, null, false),
|
||||
LoggingEventType.CriticalBuildMessage => new CriticalBuildMessageEventArgs(null, null, null, -1, -1, -1, -1, null, null, null),
|
||||
LoggingEventType.MetaprojectGenerated => new MetaprojectGeneratedEventArgs(null, null, null),
|
||||
LoggingEventType.PropertyInitialValueSet => new PropertyInitialValueSetEventArgs(),
|
||||
LoggingEventType.PropertyReassignment => new PropertyReassignmentEventArgs(),
|
||||
LoggingEventType.UninitializedPropertyRead => new UninitializedPropertyReadEventArgs(),
|
||||
#endif
|
||||
_ => throw new InternalErrorException("Should not get to the default of GetBuildEventArgFromId ID: " + _eventType)
|
||||
};
|
||||
|
@ -573,6 +641,15 @@ namespace Microsoft.Build.Shared
|
|||
{
|
||||
return LoggingEventType.ProjectStartedEvent;
|
||||
}
|
||||
else if (eventType == typeof(ExternalProjectStartedEventArgs))
|
||||
{
|
||||
return LoggingEventType.ExternalProjectStartedEvent;
|
||||
}
|
||||
else if (eventType == typeof(ExternalProjectFinishedEventArgs))
|
||||
{
|
||||
return LoggingEventType.ExternalProjectFinishedEvent;
|
||||
}
|
||||
|
||||
#if !TASKHOST
|
||||
else if (eventType == typeof(ProjectEvaluationFinishedEventArgs))
|
||||
{
|
||||
|
@ -598,6 +675,42 @@ namespace Microsoft.Build.Shared
|
|||
{
|
||||
return LoggingEventType.AssemblyLoadEvent;
|
||||
}
|
||||
else if (eventType == typeof(ExtendedCustomBuildEventArgs))
|
||||
{
|
||||
return LoggingEventType.ExtendedCustomEvent;
|
||||
}
|
||||
else if (eventType == typeof(ExtendedBuildErrorEventArgs))
|
||||
{
|
||||
return LoggingEventType.ExtendedBuildErrorEvent;
|
||||
}
|
||||
else if (eventType == typeof(ExtendedBuildWarningEventArgs))
|
||||
{
|
||||
return LoggingEventType.ExtendedBuildWarningEvent;
|
||||
}
|
||||
else if (eventType == typeof(ExtendedBuildMessageEventArgs))
|
||||
{
|
||||
return LoggingEventType.ExtendedBuildMessageEvent;
|
||||
}
|
||||
else if (eventType == typeof(CriticalBuildMessageEventArgs))
|
||||
{
|
||||
return LoggingEventType.CriticalBuildMessage;
|
||||
}
|
||||
else if (eventType == typeof(MetaprojectGeneratedEventArgs))
|
||||
{
|
||||
return LoggingEventType.MetaprojectGenerated;
|
||||
}
|
||||
else if (eventType == typeof(PropertyInitialValueSetEventArgs))
|
||||
{
|
||||
return LoggingEventType.PropertyInitialValueSet;
|
||||
}
|
||||
else if (eventType == typeof(PropertyReassignmentEventArgs))
|
||||
{
|
||||
return LoggingEventType.PropertyReassignment;
|
||||
}
|
||||
else if (eventType == typeof(UninitializedPropertyReadEventArgs))
|
||||
{
|
||||
return LoggingEventType.UninitializedPropertyRead;
|
||||
}
|
||||
#endif
|
||||
else if (eventType == typeof(TargetStartedEventArgs))
|
||||
{
|
||||
|
@ -690,12 +803,6 @@ namespace Microsoft.Build.Shared
|
|||
case LoggingEventType.BuildWarningEvent:
|
||||
WriteBuildWarningEventToStream((BuildWarningEventArgs)buildEvent, translator);
|
||||
break;
|
||||
case LoggingEventType.ProjectStartedEvent:
|
||||
WriteExternalProjectStartedEventToStream((ExternalProjectStartedEventArgs)buildEvent, translator);
|
||||
break;
|
||||
case LoggingEventType.ProjectFinishedEvent:
|
||||
WriteExternalProjectFinishedEventToStream((ExternalProjectFinishedEventArgs)buildEvent, translator);
|
||||
break;
|
||||
case LoggingEventType.EnvironmentVariableReadEvent:
|
||||
WriteEnvironmentVariableReadEventArgs((EnvironmentVariableReadEventArgs)buildEvent, translator);
|
||||
break;
|
||||
|
@ -712,37 +819,20 @@ namespace Microsoft.Build.Shared
|
|||
private void WriteEnvironmentVariableReadEventArgs(EnvironmentVariableReadEventArgs environmentVariableReadEventArgs, ITranslator translator)
|
||||
{
|
||||
string name = environmentVariableReadEventArgs.EnvironmentVariableName;
|
||||
MessageImportance importance = environmentVariableReadEventArgs.Importance;
|
||||
|
||||
translator.Translate(ref name);
|
||||
BuildEventContext context = environmentVariableReadEventArgs.BuildEventContext;
|
||||
translator.TranslateEnum(ref importance, (int)importance);
|
||||
|
||||
#if !CLR2COMPATIBILITY
|
||||
DateTime timestamp = environmentVariableReadEventArgs.RawTimestamp;
|
||||
BuildEventContext context = environmentVariableReadEventArgs.BuildEventContext;
|
||||
|
||||
translator.Translate(ref timestamp);
|
||||
translator.Translate(ref context);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serialize ExternalProjectFinished Event Argument to the stream
|
||||
/// </summary>
|
||||
private void WriteExternalProjectFinishedEventToStream(ExternalProjectFinishedEventArgs externalProjectFinishedEventArgs, ITranslator translator)
|
||||
{
|
||||
string projectFile = externalProjectFinishedEventArgs.ProjectFile;
|
||||
translator.Translate(ref projectFile);
|
||||
|
||||
bool succeeded = externalProjectFinishedEventArgs.Succeeded;
|
||||
translator.Translate(ref succeeded);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ExternalProjectStartedEvent
|
||||
/// </summary>
|
||||
private void WriteExternalProjectStartedEventToStream(ExternalProjectStartedEventArgs externalProjectStartedEventArgs, ITranslator translator)
|
||||
{
|
||||
string projectFile = externalProjectStartedEventArgs.ProjectFile;
|
||||
translator.Translate(ref projectFile);
|
||||
|
||||
string targetNames = externalProjectStartedEventArgs.TargetNames;
|
||||
translator.Translate(ref targetNames);
|
||||
}
|
||||
|
||||
#region Writes to Stream
|
||||
|
||||
/// <summary>
|
||||
|
@ -829,7 +919,13 @@ namespace Microsoft.Build.Shared
|
|||
private void WriteResponseFileUsedEventToStream(ResponseFileUsedEventArgs responseFileUsedEventArgs, ITranslator translator)
|
||||
{
|
||||
string filePath = responseFileUsedEventArgs.ResponseFilePath;
|
||||
|
||||
translator.Translate(ref filePath);
|
||||
|
||||
#if !CLR2COMPATIBILITY
|
||||
DateTime timestamp = responseFileUsedEventArgs.RawTimestamp;
|
||||
translator.Translate(ref timestamp);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !TASKHOST && !MSBUILDENTRYPOINTEXE
|
||||
|
@ -1066,8 +1162,6 @@ namespace Microsoft.Build.Shared
|
|||
{
|
||||
LoggingEventType.TaskCommandLineEvent => ReadTaskCommandLineEventFromStream(translator, message, helpKeyword, senderName),
|
||||
LoggingEventType.BuildErrorEvent => ReadTaskBuildErrorEventFromStream(translator, message, helpKeyword, senderName),
|
||||
LoggingEventType.ProjectStartedEvent => ReadExternalProjectStartedEventFromStream(translator, message, helpKeyword, senderName),
|
||||
LoggingEventType.ProjectFinishedEvent => ReadExternalProjectFinishedEventFromStream(translator, message, helpKeyword, senderName),
|
||||
LoggingEventType.BuildMessageEvent => ReadBuildMessageEventFromStream(translator, message, helpKeyword, senderName),
|
||||
LoggingEventType.ResponseFileUsedEvent => ReadResponseFileUsedEventFromStream(translator, message, helpKeyword, senderName),
|
||||
LoggingEventType.BuildWarningEvent => ReadBuildWarningEventFromStream(translator, message, helpKeyword, senderName),
|
||||
|
@ -1082,60 +1176,24 @@ namespace Microsoft.Build.Shared
|
|||
private EnvironmentVariableReadEventArgs ReadEnvironmentVariableReadEventFromStream(ITranslator translator, string message, string helpKeyword, string senderName)
|
||||
{
|
||||
string environmentVariableName = null;
|
||||
MessageImportance importance = default;
|
||||
|
||||
translator.Translate(ref environmentVariableName);
|
||||
BuildEventContext context = null;
|
||||
translator.TranslateEnum(ref importance, (int)importance);
|
||||
|
||||
EnvironmentVariableReadEventArgs args = new(environmentVariableName, message, helpKeyword, senderName, importance);
|
||||
|
||||
#if !CLR2COMPATIBILITY
|
||||
DateTime timestamp = default;
|
||||
BuildEventContext context = null;
|
||||
translator.Translate(ref timestamp);
|
||||
translator.Translate(ref context);
|
||||
#endif
|
||||
EnvironmentVariableReadEventArgs args = new(environmentVariableName, message);
|
||||
args.RawTimestamp = timestamp;
|
||||
args.BuildEventContext = context;
|
||||
#endif
|
||||
return args;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read and reconstruct a ProjectFinishedEventArgs from the stream
|
||||
/// </summary>
|
||||
private ExternalProjectFinishedEventArgs ReadExternalProjectFinishedEventFromStream(ITranslator translator, string message, string helpKeyword, string senderName)
|
||||
{
|
||||
string projectFile = null;
|
||||
translator.Translate(ref projectFile);
|
||||
|
||||
bool succeeded = true;
|
||||
translator.Translate(ref succeeded);
|
||||
|
||||
ExternalProjectFinishedEventArgs buildEvent =
|
||||
new ExternalProjectFinishedEventArgs(
|
||||
message,
|
||||
helpKeyword,
|
||||
senderName,
|
||||
projectFile,
|
||||
succeeded);
|
||||
|
||||
return buildEvent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read and reconstruct a ProjectStartedEventArgs from the stream
|
||||
/// </summary>
|
||||
private ExternalProjectStartedEventArgs ReadExternalProjectStartedEventFromStream(ITranslator translator, string message, string helpKeyword, string senderName)
|
||||
{
|
||||
string projectFile = null;
|
||||
translator.Translate(ref projectFile);
|
||||
|
||||
string targetNames = null;
|
||||
translator.Translate(ref targetNames);
|
||||
|
||||
ExternalProjectStartedEventArgs buildEvent =
|
||||
new ExternalProjectStartedEventArgs(
|
||||
message,
|
||||
helpKeyword,
|
||||
senderName,
|
||||
projectFile,
|
||||
targetNames);
|
||||
|
||||
return buildEvent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read and reconstruct a BuildWarningEventArgs from the stream
|
||||
/// </summary>
|
||||
|
@ -1256,6 +1314,14 @@ namespace Microsoft.Build.Shared
|
|||
string responseFilePath = String.Empty;
|
||||
translator.Translate(ref responseFilePath);
|
||||
ResponseFileUsedEventArgs buildEvent = new ResponseFileUsedEventArgs(responseFilePath);
|
||||
|
||||
#if !CLR2COMPATIBILITY
|
||||
DateTime timestamp = default;
|
||||
translator.Translate(ref timestamp);
|
||||
buildEvent.RawTimestamp = timestamp;
|
||||
#endif
|
||||
|
||||
|
||||
return buildEvent;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,9 @@
|
|||
<data name="ExpectedEventToBeSerializable" Visibility="Public">
|
||||
<value>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</value>
|
||||
</data>
|
||||
<data name="DeprecatedEventSerialization" Visibility="Public">
|
||||
<value>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</value>
|
||||
</data>
|
||||
<data name="FileLocation" Visibility="Public">
|
||||
<value>{0} ({1},{2})</value>
|
||||
<comment>A file location to be embedded in a string.</comment>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: Bylo nalezeno konfliktní sestavení pro sestavení úlohy {0} v umístění {1}.</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">Očekávalo se, že typ události {0} bude možné serializovat pomocí serializátoru .NET. Událost nebylo možné serializovat a byla ignorována.</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: Eine mit der Aufgabenassembly "{0}" in Konflikt stehende Assembly wurde in "{1}" gefunden.</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">Es wurde erwartet, dass der Ereignistyp "{0}" mithilfe des .NET-Serialisierers serialisierbar ist. Das Ereignis war nicht serialisierbar und wurde ignoriert.</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: Se detectó un ensamblado conflictivo para el ensamblado de tarea "{0}" en "{1}".</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">Se esperaba que el tipo de evento "{0}" fuera serializable con el serializador .NET. El evento no era serializable y se ha omitido.</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: un assembly en conflit avec l'assembly de tâche "{0}" a été trouvé sur "{1}".</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">Le type d'événement "{0}" devait être sérialisable à l'aide du sérialiseur .NET. L'événement n'était pas sérialisable et a été ignoré.</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: rilevato un assembly in conflitto per l'assembly dell'attività "{0}" in "{1}".</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">È previsto un tipo di evento "{0}" serializzabile con il serializzatore .NET. L'evento non era serializzabile ed è stato ignorato.</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: タスク アセンブリ "{0}" に対して競合しているアセンブリが "{1}" で見つかりました。</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">イベントの種類 "{0}" は .NET シリアライザーを使用してシリアル化可能であることが想定されていましたが、シリアル化可能でなかったため無視されました。</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: 작업 어셈블리 "{0}"과(와) 충돌하는 어셈블리가 "{1}"에 있습니다.</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">이벤트 유형 "{0}"은(는) .NET serializer를 사용하여 serialize할 수 있어야 합니다. 이 이벤트는 serialize할 수 없으므로 무시되었습니다.</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: Zestaw, który wywołuje konflikt z zestawem zadania „{0}”, został znaleziony w „{1}”.</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">Oczekiwano, że zdarzenie typu „{0}” będzie uszeregowane przy użyciu serializatora platformy .NET. Zdarzenie nie może podlegać szeregowaniu, dlatego zostało zignorowane.</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: Foi encontrado um assembly conflitante no assembly da tarefa "{0}" em "{1}".</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">Era esperado que o tipo de evento "{0}" fosse serializável usando o serializador .NET. O evento não era serializável e foi ignorado.</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: в "{1}" обнаружена сборка, конфликтующая со сборкой задачи "{0}".</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">Необходимо, чтобы тип события "{0}" был сериализуемым с помощью сериализатора .NET. Событие не было сериализуемым и было пропущено.</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: "{0}" görev derlemesi için "{1}" konumunda çakışan derleme bulundu.</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">"{0}" olay türünün .NET serileştiricisi kullanılarak serileştirilebilir olması bekleniyordu. Olay serileştirilebilir değildi ve yoksayıldı.</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: 在“{1}”处发现了与任务程序集“{0}”冲突的程序集。</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">事件类型“{0}”应可以使用 .NET 序列化程序进行序列化。此事件不可序列化,已忽略它。</target>
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
<target state="translated">MSB4008: 已在 "{1}" 中發現工作組件 "{0}" 的衝突組件。</target>
|
||||
<note>{StrBegin="MSB4008: "}UE: This message is shown when the type/class of a task cannot be resolved uniquely from a single assembly.</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="DeprecatedEventSerialization">
|
||||
<source>Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</source>
|
||||
<target state="new">Usage of unsecure BinaryFormatter during serialization of custom event type '{0}'. This will be deprecated soon. Please use Extended*EventArgs instead. More info: https://aka.ms/msbuild/eventargs</target>
|
||||
<note />
|
||||
</trans-unit>
|
||||
<trans-unit id="ExpectedEventToBeSerializable">
|
||||
<source>Event type "{0}" was expected to be serializable using the .NET serializer. The event was not serializable and has been ignored.</source>
|
||||
<target state="translated">事件類型 "{0}" 應該可以使用 .NET 序列化程式序列化。此事件不可序列化,已略過。</target>
|
||||
|
|
|
@ -24,47 +24,37 @@ namespace Microsoft.Build.BackEnd
|
|||
internal enum TaskParameterType
|
||||
{
|
||||
/// <summary>
|
||||
/// Parameter is null
|
||||
/// Parameter is null.
|
||||
/// </summary>
|
||||
Null,
|
||||
|
||||
/// <summary>
|
||||
/// Parameter is a string
|
||||
/// Parameter is of a type described by a <see cref="TypeCode"/>.
|
||||
/// </summary>
|
||||
String,
|
||||
PrimitiveType,
|
||||
|
||||
/// <summary>
|
||||
/// Parameter is an array of strings
|
||||
/// Parameter is an array of a type described by a <see cref="TypeCode"/>.
|
||||
/// </summary>
|
||||
StringArray,
|
||||
PrimitiveTypeArray,
|
||||
|
||||
/// <summary>
|
||||
/// Parameter is <c>true</c> or <c>false</c>.
|
||||
/// </summary>
|
||||
Bool,
|
||||
|
||||
/// <summary>
|
||||
/// Parameter is an <see langword="int"/>.
|
||||
/// </summary>
|
||||
Int,
|
||||
|
||||
/// <summary>
|
||||
/// Parameter is a value type. Note: Must be serializable
|
||||
/// Parameter is a value type. Note: Must be <see cref="IConvertible"/>.
|
||||
/// </summary>
|
||||
ValueType,
|
||||
|
||||
/// <summary>
|
||||
/// Parameter is an array of value types. Note: Must be serializable.
|
||||
/// Parameter is an array of value types. Note: Must be <see cref="IConvertible"/>.
|
||||
/// </summary>
|
||||
ValueTypeArray,
|
||||
|
||||
/// <summary>
|
||||
/// Parameter is an ITaskItem
|
||||
/// Parameter is an ITaskItem.
|
||||
/// </summary>
|
||||
ITaskItem,
|
||||
|
||||
/// <summary>
|
||||
/// Parameter is an array of ITaskItems
|
||||
/// Parameter is an array of ITaskItems.
|
||||
/// </summary>
|
||||
ITaskItemArray,
|
||||
|
||||
|
@ -72,7 +62,7 @@ namespace Microsoft.Build.BackEnd
|
|||
/// An invalid parameter -- the value of this parameter contains the exception
|
||||
/// that is thrown when trying to access it.
|
||||
/// </summary>
|
||||
Invalid
|
||||
Invalid,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -86,10 +76,15 @@ namespace Microsoft.Build.BackEnd
|
|||
ITranslatable
|
||||
{
|
||||
/// <summary>
|
||||
/// The TaskParameterType of the wrapped parameter
|
||||
/// The TaskParameterType of the wrapped parameter.
|
||||
/// </summary>
|
||||
private TaskParameterType _parameterType;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TypeCode"/> of the wrapped parameter if it's a primitive type.
|
||||
/// </summary>
|
||||
private TypeCode _parameterTypeCode;
|
||||
|
||||
/// <summary>
|
||||
/// The actual task parameter that we're wrapping
|
||||
/// </summary>
|
||||
|
@ -124,9 +119,11 @@ namespace Microsoft.Build.BackEnd
|
|||
|
||||
if (wrappedParameterType.IsArray)
|
||||
{
|
||||
if (wrappedParameterType == typeof(string[]))
|
||||
TypeCode typeCode = Type.GetTypeCode(wrappedParameterType.GetElementType());
|
||||
if (typeCode != TypeCode.Object && typeCode != TypeCode.DBNull)
|
||||
{
|
||||
_parameterType = TaskParameterType.StringArray;
|
||||
_parameterType = TaskParameterType.PrimitiveTypeArray;
|
||||
_parameterTypeCode = typeCode;
|
||||
_wrappedParameter = wrappedParameter;
|
||||
}
|
||||
else if (typeof(ITaskItem[]).GetTypeInfo().IsAssignableFrom(wrappedParameterType.GetTypeInfo()))
|
||||
|
@ -158,9 +155,21 @@ namespace Microsoft.Build.BackEnd
|
|||
else
|
||||
{
|
||||
// scalar parameter
|
||||
if (wrappedParameterType == typeof(string))
|
||||
// Preserve enums as strings: the enum type itself may not
|
||||
// be loaded on the other side of the serialization, but
|
||||
// we would convert to string anyway after pulling the
|
||||
// task output into a property or item.
|
||||
if (wrappedParameterType.IsEnum)
|
||||
{
|
||||
_parameterType = TaskParameterType.String;
|
||||
wrappedParameter = (string)Convert.ChangeType(wrappedParameter, typeof(string), CultureInfo.InvariantCulture);
|
||||
wrappedParameterType = typeof(string);
|
||||
}
|
||||
|
||||
TypeCode typeCode = Type.GetTypeCode(wrappedParameterType);
|
||||
if (typeCode != TypeCode.Object && typeCode != TypeCode.DBNull)
|
||||
{
|
||||
_parameterType = TaskParameterType.PrimitiveType;
|
||||
_parameterTypeCode = typeCode;
|
||||
_wrappedParameter = wrappedParameter;
|
||||
}
|
||||
else if (typeof(ITaskItem).IsAssignableFrom(wrappedParameterType))
|
||||
|
@ -168,28 +177,6 @@ namespace Microsoft.Build.BackEnd
|
|||
_parameterType = TaskParameterType.ITaskItem;
|
||||
_wrappedParameter = CreateNewTaskItemFrom((ITaskItem)wrappedParameter);
|
||||
}
|
||||
// Preserve enums as strings: the enum type itself may not
|
||||
// be loaded on the other side of the serialization, but
|
||||
// we would convert to string anyway after pulling the
|
||||
// task output into a property or item.
|
||||
else if (wrappedParameterType.IsEnum)
|
||||
{
|
||||
_parameterType = TaskParameterType.String;
|
||||
_wrappedParameter = (string)Convert.ChangeType(wrappedParameter, typeof(string), CultureInfo.InvariantCulture);
|
||||
}
|
||||
// Also stringify known common value types, to avoid calling
|
||||
// TranslateDotNet when they'll just be stringified on the
|
||||
// output side
|
||||
else if (wrappedParameterType == typeof(bool))
|
||||
{
|
||||
_parameterType = TaskParameterType.Bool;
|
||||
_wrappedParameter = wrappedParameter;
|
||||
}
|
||||
else if (wrappedParameterType == typeof(int))
|
||||
{
|
||||
_parameterType = TaskParameterType.Int;
|
||||
_wrappedParameter = wrappedParameter;
|
||||
}
|
||||
else if (wrappedParameterType.GetTypeInfo().IsValueType)
|
||||
{
|
||||
_parameterType = TaskParameterType.ValueType;
|
||||
|
@ -203,31 +190,26 @@ namespace Microsoft.Build.BackEnd
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for deserialization
|
||||
/// Constructor for deserialization.
|
||||
/// </summary>
|
||||
private TaskParameter()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The TaskParameterType of the wrapped parameter
|
||||
/// The TaskParameterType of the wrapped parameter.
|
||||
/// </summary>
|
||||
public TaskParameterType ParameterType
|
||||
{
|
||||
[DebuggerStepThrough]
|
||||
get
|
||||
{ return _parameterType; }
|
||||
}
|
||||
public TaskParameterType ParameterType => _parameterType;
|
||||
|
||||
/// <summary>
|
||||
/// The actual task parameter that we're wrapping
|
||||
/// The <see cref="TypeCode"/> of the wrapper parameter if it's a primitive or array of primitives.
|
||||
/// </summary>
|
||||
public object WrappedParameter
|
||||
{
|
||||
[DebuggerStepThrough]
|
||||
get
|
||||
{ return _wrappedParameter; }
|
||||
}
|
||||
public TypeCode ParameterTypeCode => _parameterTypeCode;
|
||||
|
||||
/// <summary>
|
||||
/// The actual task parameter that we're wrapping.
|
||||
/// </summary>
|
||||
public object WrappedParameter => _wrappedParameter;
|
||||
|
||||
/// <summary>
|
||||
/// TaskParameter's ToString should just pass through to whatever it's wrapping.
|
||||
|
@ -242,44 +224,38 @@ namespace Microsoft.Build.BackEnd
|
|||
/// </summary>
|
||||
public void Translate(ITranslator translator)
|
||||
{
|
||||
translator.TranslateEnum<TaskParameterType>(ref _parameterType, (int)_parameterType);
|
||||
translator.TranslateEnum(ref _parameterType, (int)_parameterType);
|
||||
|
||||
switch (_parameterType)
|
||||
{
|
||||
case TaskParameterType.Null:
|
||||
_wrappedParameter = null;
|
||||
break;
|
||||
case TaskParameterType.String:
|
||||
string stringParam = (string)_wrappedParameter;
|
||||
translator.Translate(ref stringParam);
|
||||
_wrappedParameter = stringParam;
|
||||
case TaskParameterType.PrimitiveType:
|
||||
TranslatePrimitiveType(translator);
|
||||
break;
|
||||
case TaskParameterType.StringArray:
|
||||
string[] stringArrayParam = (string[])_wrappedParameter;
|
||||
translator.Translate(ref stringArrayParam);
|
||||
_wrappedParameter = stringArrayParam;
|
||||
break;
|
||||
case TaskParameterType.Bool:
|
||||
bool boolParam = _wrappedParameter switch
|
||||
{
|
||||
bool hadValue => hadValue,
|
||||
_ => default,
|
||||
};
|
||||
translator.Translate(ref boolParam);
|
||||
_wrappedParameter = boolParam;
|
||||
break;
|
||||
case TaskParameterType.Int:
|
||||
int intParam = _wrappedParameter switch
|
||||
{
|
||||
int hadValue => hadValue,
|
||||
_ => default,
|
||||
};
|
||||
translator.Translate(ref intParam);
|
||||
_wrappedParameter = intParam;
|
||||
case TaskParameterType.PrimitiveTypeArray:
|
||||
TranslatePrimitiveTypeArray(translator);
|
||||
break;
|
||||
case TaskParameterType.ValueType:
|
||||
if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_8))
|
||||
{
|
||||
TranslateValueType(translator);
|
||||
}
|
||||
else
|
||||
{
|
||||
translator.TranslateDotNet(ref _wrappedParameter);
|
||||
}
|
||||
break;
|
||||
case TaskParameterType.ValueTypeArray:
|
||||
translator.TranslateDotNet(ref _wrappedParameter);
|
||||
if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_8))
|
||||
{
|
||||
TranslateValueTypeArray(translator);
|
||||
}
|
||||
else
|
||||
{
|
||||
translator.TranslateDotNet(ref _wrappedParameter);
|
||||
}
|
||||
break;
|
||||
case TaskParameterType.ITaskItem:
|
||||
TranslateITaskItem(translator);
|
||||
|
@ -537,6 +513,223 @@ namespace Microsoft.Build.BackEnd
|
|||
return haveRef;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes or deserializes a primitive type value wrapped by this <see cref="TaskParameter"/>.
|
||||
/// </summary>
|
||||
private void TranslatePrimitiveType(ITranslator translator)
|
||||
{
|
||||
translator.TranslateEnum(ref _parameterTypeCode, (int)_parameterTypeCode);
|
||||
|
||||
switch (_parameterTypeCode)
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
bool boolParam = _wrappedParameter is bool wrappedBool ? wrappedBool : default;
|
||||
translator.Translate(ref boolParam);
|
||||
_wrappedParameter = boolParam;
|
||||
break;
|
||||
|
||||
case TypeCode.Byte:
|
||||
byte byteParam = _wrappedParameter is byte wrappedByte ? wrappedByte : default;
|
||||
translator.Translate(ref byteParam);
|
||||
_wrappedParameter = byteParam;
|
||||
break;
|
||||
|
||||
case TypeCode.Int16:
|
||||
short shortParam = _wrappedParameter is short wrappedShort ? wrappedShort : default;
|
||||
translator.Translate(ref shortParam);
|
||||
_wrappedParameter = shortParam;
|
||||
break;
|
||||
|
||||
case TypeCode.UInt16:
|
||||
ushort ushortParam = _wrappedParameter is ushort wrappedUShort ? wrappedUShort : default;
|
||||
translator.Translate(ref ushortParam);
|
||||
_wrappedParameter = ushortParam;
|
||||
break;
|
||||
|
||||
case TypeCode.Int64:
|
||||
long longParam = _wrappedParameter is long wrappedLong ? wrappedLong : default;
|
||||
translator.Translate(ref longParam);
|
||||
_wrappedParameter = longParam;
|
||||
break;
|
||||
|
||||
case TypeCode.Double:
|
||||
double doubleParam = _wrappedParameter is double wrappedDouble ? wrappedDouble : default;
|
||||
translator.Translate(ref doubleParam);
|
||||
_wrappedParameter = doubleParam;
|
||||
break;
|
||||
|
||||
case TypeCode.String:
|
||||
string stringParam = (string)_wrappedParameter;
|
||||
translator.Translate(ref stringParam);
|
||||
_wrappedParameter = stringParam;
|
||||
break;
|
||||
|
||||
case TypeCode.DateTime:
|
||||
DateTime dateTimeParam = _wrappedParameter is DateTime wrappedDateTime ? wrappedDateTime : default;
|
||||
translator.Translate(ref dateTimeParam);
|
||||
_wrappedParameter = dateTimeParam;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Fall back to converting to/from string for types that don't have ITranslator support.
|
||||
string stringValue = null;
|
||||
if (translator.Mode == TranslationDirection.WriteToStream)
|
||||
{
|
||||
stringValue = (string)Convert.ChangeType(_wrappedParameter, typeof(string), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
translator.Translate(ref stringValue);
|
||||
|
||||
if (translator.Mode == TranslationDirection.ReadFromStream)
|
||||
{
|
||||
_wrappedParameter = Convert.ChangeType(stringValue, _parameterTypeCode, CultureInfo.InvariantCulture);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes or deserializes an array of primitive type values wrapped by this <see cref="TaskParameter"/>.
|
||||
/// </summary>
|
||||
private void TranslatePrimitiveTypeArray(ITranslator translator)
|
||||
{
|
||||
translator.TranslateEnum(ref _parameterTypeCode, (int)_parameterTypeCode);
|
||||
|
||||
switch (_parameterTypeCode)
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
bool[] boolArrayParam = (bool[])_wrappedParameter;
|
||||
translator.Translate(ref boolArrayParam);
|
||||
_wrappedParameter = boolArrayParam;
|
||||
break;
|
||||
|
||||
case TypeCode.Int32:
|
||||
int[] intArrayParam = (int[])_wrappedParameter;
|
||||
translator.Translate(ref intArrayParam);
|
||||
_wrappedParameter = intArrayParam;
|
||||
break;
|
||||
|
||||
case TypeCode.String:
|
||||
string[] stringArrayParam = (string[])_wrappedParameter;
|
||||
translator.Translate(ref stringArrayParam);
|
||||
_wrappedParameter = stringArrayParam;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Fall back to converting to/from string for types that don't have ITranslator support.
|
||||
if (translator.Mode == TranslationDirection.WriteToStream)
|
||||
{
|
||||
Array array = (Array)_wrappedParameter;
|
||||
int length = array.Length;
|
||||
|
||||
translator.Translate(ref length);
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
string valueString = Convert.ToString(array.GetValue(i), CultureInfo.InvariantCulture);
|
||||
translator.Translate(ref valueString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Type elementType = _parameterTypeCode switch
|
||||
{
|
||||
TypeCode.Char => typeof(char),
|
||||
TypeCode.SByte => typeof(sbyte),
|
||||
TypeCode.Byte => typeof(byte),
|
||||
TypeCode.Int16 => typeof(short),
|
||||
TypeCode.UInt16 => typeof(ushort),
|
||||
TypeCode.UInt32 => typeof(uint),
|
||||
TypeCode.Int64 => typeof(long),
|
||||
TypeCode.UInt64 => typeof(ulong),
|
||||
TypeCode.Single => typeof(float),
|
||||
TypeCode.Double => typeof(double),
|
||||
TypeCode.Decimal => typeof(decimal),
|
||||
TypeCode.DateTime => typeof(DateTime),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
int length = 0;
|
||||
translator.Translate(ref length);
|
||||
|
||||
Array array = Array.CreateInstance(elementType, length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
string valueString = null;
|
||||
translator.Translate(ref valueString);
|
||||
array.SetValue(Convert.ChangeType(valueString, _parameterTypeCode, CultureInfo.InvariantCulture), i);
|
||||
}
|
||||
_wrappedParameter = array;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes or deserializes the value type instance wrapped by this <see cref="TaskParameter"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The value type is converted to/from string using the <see cref="Convert"/> class. Note that we require
|
||||
/// task parameter types to be <see cref="IConvertible"/> so this conversion is guaranteed to work for parameters
|
||||
/// that have made it this far.
|
||||
/// </remarks>
|
||||
private void TranslateValueType(ITranslator translator)
|
||||
{
|
||||
string valueString = null;
|
||||
if (translator.Mode == TranslationDirection.WriteToStream)
|
||||
{
|
||||
valueString = (string)Convert.ChangeType(_wrappedParameter, typeof(string), CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
translator.Translate(ref valueString);
|
||||
|
||||
if (translator.Mode == TranslationDirection.ReadFromStream)
|
||||
{
|
||||
// We don't know how to convert the string back to the original value type. This is fine because output
|
||||
// task parameters are anyway converted to strings by the engine (see TaskExecutionHost.GetValueOutputs)
|
||||
// and input task parameters of custom value types are not supported.
|
||||
_wrappedParameter = valueString;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes or deserializes the value type array instance wrapped by this <see cref="TaskParameter"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The array is assumed to be non-null.
|
||||
/// </remarks>
|
||||
private void TranslateValueTypeArray(ITranslator translator)
|
||||
{
|
||||
if (translator.Mode == TranslationDirection.WriteToStream)
|
||||
{
|
||||
Array array = (Array)_wrappedParameter;
|
||||
int length = array.Length;
|
||||
|
||||
translator.Translate(ref length);
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
string valueString = Convert.ToString(array.GetValue(i), CultureInfo.InvariantCulture);
|
||||
translator.Translate(ref valueString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int length = 0;
|
||||
translator.Translate(ref length);
|
||||
|
||||
string[] stringArray = new string[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
translator.Translate(ref stringArray[i]);
|
||||
}
|
||||
|
||||
// We don't know how to convert the string array back to the original value type array.
|
||||
// This is fine because the engine would eventually convert it to strings anyway.
|
||||
_wrappedParameter = stringArray;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Super simple ITaskItem derivative that we can use as a container for read items.
|
||||
/// </summary>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
using Microsoft.Build.BackEnd;
|
||||
using Microsoft.Build.Framework;
|
||||
|
@ -39,96 +40,124 @@ namespace Microsoft.Build.UnitTests
|
|||
Assert.Equal(TaskParameterType.Null, t2.ParameterType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that construction and serialization with a string parameter is OK.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void StringParameter()
|
||||
[Theory]
|
||||
[InlineData(typeof(bool), (int)TypeCode.Boolean, "True")]
|
||||
[InlineData(typeof(byte), (int)TypeCode.Byte, "127")]
|
||||
[InlineData(typeof(sbyte), (int)TypeCode.SByte, "-127")]
|
||||
[InlineData(typeof(double), (int)TypeCode.Double, "3.14")]
|
||||
[InlineData(typeof(float), (int)TypeCode.Single, "3.14")]
|
||||
[InlineData(typeof(short), (int)TypeCode.Int16, "-20000")]
|
||||
[InlineData(typeof(ushort), (int)TypeCode.UInt16, "30000")]
|
||||
[InlineData(typeof(int), (int)TypeCode.Int32, "-1")]
|
||||
[InlineData(typeof(uint), (int)TypeCode.UInt32, "1")]
|
||||
[InlineData(typeof(long), (int)TypeCode.Int64, "-1000000000000")]
|
||||
[InlineData(typeof(ulong), (int)TypeCode.UInt64, "1000000000000")]
|
||||
[InlineData(typeof(decimal), (int)TypeCode.Decimal, "29.99")]
|
||||
[InlineData(typeof(char), (int)TypeCode.Char, "q")]
|
||||
[InlineData(typeof(string), (int)TypeCode.String, "foo")]
|
||||
[InlineData(typeof(DateTime), (int)TypeCode.DateTime, "1/1/2000 12:12:12")]
|
||||
public void PrimitiveParameter(Type type, int expectedTypeCodeAsInt, string testValueAsString)
|
||||
{
|
||||
TaskParameter t = new TaskParameter("foo");
|
||||
TypeCode expectedTypeCode = (TypeCode)expectedTypeCodeAsInt;
|
||||
|
||||
Assert.Equal("foo", t.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.String, t.ParameterType);
|
||||
object value = Convert.ChangeType(testValueAsString, type, CultureInfo.InvariantCulture);
|
||||
TaskParameter t = new TaskParameter(value);
|
||||
|
||||
Assert.Equal(value, t.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.PrimitiveType, t.ParameterType);
|
||||
Assert.Equal(expectedTypeCode, t.ParameterTypeCode);
|
||||
|
||||
((ITranslatable)t).Translate(TranslationHelpers.GetWriteTranslator());
|
||||
TaskParameter t2 = TaskParameter.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
|
||||
|
||||
Assert.Equal("foo", t2.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.String, t2.ParameterType);
|
||||
Assert.Equal(value, t2.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.PrimitiveType, t2.ParameterType);
|
||||
Assert.Equal(expectedTypeCode, t2.ParameterTypeCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that construction and serialization with a string array parameter is OK.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void StringArrayParameter()
|
||||
[Theory]
|
||||
[InlineData(typeof(bool), (int)TypeCode.Boolean, "True;False;True")]
|
||||
[InlineData(typeof(byte), (int)TypeCode.Byte, "127;100;0")]
|
||||
[InlineData(typeof(sbyte), (int)TypeCode.SByte, "-127;-126;12")]
|
||||
[InlineData(typeof(double), (int)TypeCode.Double, "3.14;3.15")]
|
||||
[InlineData(typeof(float), (int)TypeCode.Single, "3.14;3.15")]
|
||||
[InlineData(typeof(short), (int)TypeCode.Int16, "-20000;0;-1")]
|
||||
[InlineData(typeof(ushort), (int)TypeCode.UInt16, "30000;20000;10")]
|
||||
[InlineData(typeof(int), (int)TypeCode.Int32, "-1;-2")]
|
||||
[InlineData(typeof(uint), (int)TypeCode.UInt32, "1;5;6")]
|
||||
[InlineData(typeof(long), (int)TypeCode.Int64, "-1000000000000;0")]
|
||||
[InlineData(typeof(ulong), (int)TypeCode.UInt64, "1000000000000;0")]
|
||||
[InlineData(typeof(decimal), (int)TypeCode.Decimal, "29.99;0.88")]
|
||||
[InlineData(typeof(char), (int)TypeCode.Char, "q;r;c")]
|
||||
[InlineData(typeof(string), (int)TypeCode.String, "foo;bar")]
|
||||
[InlineData(typeof(DateTime), (int)TypeCode.DateTime, "1/1/2000 12:12:12;2/2/2000 13:13:13")]
|
||||
public void PrimitiveArrayParameter(Type type, int expectedTypeCodeAsInt, string testValueAsString)
|
||||
{
|
||||
TaskParameter t = new TaskParameter(new string[] { "foo", "bar" });
|
||||
TypeCode expectedTypeCode = (TypeCode)expectedTypeCodeAsInt;
|
||||
|
||||
Assert.Equal(TaskParameterType.StringArray, t.ParameterType);
|
||||
string[] values = testValueAsString.Split(';');
|
||||
Array array = Array.CreateInstance(type, values.Length);
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
object value = Convert.ChangeType(values[i], type, CultureInfo.InvariantCulture);
|
||||
array.SetValue(value, i);
|
||||
}
|
||||
|
||||
string[] wrappedParameter = t.WrappedParameter as string[];
|
||||
Assert.NotNull(wrappedParameter);
|
||||
Assert.Equal(2, wrappedParameter.Length);
|
||||
Assert.Equal("foo", wrappedParameter[0]);
|
||||
Assert.Equal("bar", wrappedParameter[1]);
|
||||
TaskParameter t = new TaskParameter(array);
|
||||
|
||||
Assert.Equal(array, t.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.PrimitiveTypeArray, t.ParameterType);
|
||||
Assert.Equal(expectedTypeCode, t.ParameterTypeCode);
|
||||
|
||||
((ITranslatable)t).Translate(TranslationHelpers.GetWriteTranslator());
|
||||
TaskParameter t2 = TaskParameter.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
|
||||
|
||||
Assert.Equal(TaskParameterType.StringArray, t2.ParameterType);
|
||||
|
||||
string[] wrappedParameter2 = t2.WrappedParameter as string[];
|
||||
Assert.NotNull(wrappedParameter2);
|
||||
Assert.Equal(2, wrappedParameter2.Length);
|
||||
Assert.Equal("foo", wrappedParameter2[0]);
|
||||
Assert.Equal("bar", wrappedParameter2[1]);
|
||||
Assert.Equal(array, t2.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.PrimitiveTypeArray, t2.ParameterType);
|
||||
Assert.Equal(expectedTypeCode, t2.ParameterTypeCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that construction and serialization with a value type (integer) parameter is OK.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IntParameter()
|
||||
public void ValueTypeParameter()
|
||||
{
|
||||
TaskParameter t = new TaskParameter(1);
|
||||
TaskBuilderTestTask.CustomStruct value = new TaskBuilderTestTask.CustomStruct(3.14);
|
||||
TaskParameter t = new TaskParameter(value);
|
||||
|
||||
Assert.Equal(1, t.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.Int, t.ParameterType);
|
||||
Assert.Equal(value, t.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.ValueType, t.ParameterType);
|
||||
|
||||
((ITranslatable)t).Translate(TranslationHelpers.GetWriteTranslator());
|
||||
TaskParameter t2 = TaskParameter.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
|
||||
|
||||
Assert.Equal(1, t2.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.Int, t2.ParameterType);
|
||||
// Custom IConvertible structs are deserialized into strings.
|
||||
Assert.Equal(value.ToString(CultureInfo.InvariantCulture), t2.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.ValueType, t2.ParameterType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that construction and serialization with a parameter that is an array of value types (ints) is OK.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IntArrayParameter()
|
||||
public void ValueTypeArrayParameter()
|
||||
{
|
||||
TaskParameter t = new TaskParameter(new int[] { 2, 15 });
|
||||
TaskBuilderTestTask.CustomStruct[] value = new TaskBuilderTestTask.CustomStruct[]
|
||||
{
|
||||
new TaskBuilderTestTask.CustomStruct(3.14),
|
||||
new TaskBuilderTestTask.CustomStruct(2.72),
|
||||
};
|
||||
TaskParameter t = new TaskParameter(value);
|
||||
|
||||
Assert.Equal(value, t.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.ValueTypeArray, t.ParameterType);
|
||||
|
||||
int[] wrappedParameter = t.WrappedParameter as int[];
|
||||
Assert.NotNull(wrappedParameter);
|
||||
Assert.Equal(2, wrappedParameter.Length);
|
||||
Assert.Equal(2, wrappedParameter[0]);
|
||||
Assert.Equal(15, wrappedParameter[1]);
|
||||
|
||||
((ITranslatable)t).Translate(TranslationHelpers.GetWriteTranslator());
|
||||
TaskParameter t2 = TaskParameter.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
|
||||
|
||||
// Custom IConvertible structs are deserialized into strings.
|
||||
Assert.True(t2.WrappedParameter is string[]);
|
||||
Assert.Equal(TaskParameterType.ValueTypeArray, t2.ParameterType);
|
||||
|
||||
int[] wrappedParameter2 = t2.WrappedParameter as int[];
|
||||
Assert.NotNull(wrappedParameter2);
|
||||
Assert.Equal(2, wrappedParameter2.Length);
|
||||
Assert.Equal(2, wrappedParameter2[0]);
|
||||
Assert.Equal(15, wrappedParameter2[1]);
|
||||
string[] stringArray = (string[])t2.WrappedParameter;
|
||||
Assert.Equal(2, stringArray.Length);
|
||||
Assert.Equal(value[0].ToString(CultureInfo.InvariantCulture), stringArray[0]);
|
||||
Assert.Equal(value[1].ToString(CultureInfo.InvariantCulture), stringArray[1]);
|
||||
}
|
||||
|
||||
private enum TestEnumForParameter
|
||||
|
@ -143,55 +172,15 @@ namespace Microsoft.Build.UnitTests
|
|||
TaskParameter t = new TaskParameter(TestEnumForParameter.SomethingElse);
|
||||
|
||||
Assert.Equal("SomethingElse", t.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.String, t.ParameterType);
|
||||
Assert.Equal(TaskParameterType.PrimitiveType, t.ParameterType);
|
||||
Assert.Equal(TypeCode.String, t.ParameterTypeCode);
|
||||
|
||||
((ITranslatable)t).Translate(TranslationHelpers.GetWriteTranslator());
|
||||
TaskParameter t2 = TaskParameter.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
|
||||
|
||||
Assert.Equal("SomethingElse", t2.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.String, t2.ParameterType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BoolParameter()
|
||||
{
|
||||
TaskParameter t = new TaskParameter(true);
|
||||
|
||||
Assert.Equal(true, t.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.Bool, t.ParameterType);
|
||||
|
||||
((ITranslatable)t).Translate(TranslationHelpers.GetWriteTranslator());
|
||||
TaskParameter t2 = TaskParameter.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
|
||||
|
||||
Assert.Equal(true, t2.WrappedParameter);
|
||||
Assert.Equal(TaskParameterType.Bool, t2.ParameterType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that construction and serialization with a parameter that is an array of value types (ints) is OK.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void BoolArrayParameter()
|
||||
{
|
||||
TaskParameter t = new TaskParameter(new bool[] { false, true });
|
||||
|
||||
Assert.Equal(TaskParameterType.ValueTypeArray, t.ParameterType);
|
||||
|
||||
bool[] wrappedParameter = t.WrappedParameter as bool[];
|
||||
Assert.NotNull(wrappedParameter);
|
||||
Assert.Equal(2, wrappedParameter.Length);
|
||||
Assert.False(wrappedParameter[0]);
|
||||
Assert.True(wrappedParameter[1]);
|
||||
|
||||
((ITranslatable)t).Translate(TranslationHelpers.GetWriteTranslator());
|
||||
TaskParameter t2 = TaskParameter.FactoryForDeserialization(TranslationHelpers.GetReadTranslator());
|
||||
|
||||
Assert.Equal(TaskParameterType.ValueTypeArray, t2.ParameterType);
|
||||
|
||||
bool[] wrappedParameter2 = Assert.IsType<bool[]>(t2.WrappedParameter);
|
||||
Assert.Equal(2, wrappedParameter2.Length);
|
||||
Assert.False(wrappedParameter2[0]);
|
||||
Assert.True(wrappedParameter2[1]);
|
||||
Assert.Equal(TaskParameterType.PrimitiveType, t2.ParameterType);
|
||||
Assert.Equal(TypeCode.String, t2.ParameterTypeCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Files that have inline expected results that include trailing whitespace
|
||||
[RoslynCodeTaskFactory_Tests.cs]
|
||||
trim_trailing_whitespace = false
|
|
@ -450,6 +450,9 @@ End Namespace
|
|||
TryLoadTaskBodyAndExpectSuccess("<Code Language=\"vb\">code</Code>", expectedCodeLanguage: "VB");
|
||||
TryLoadTaskBodyAndExpectSuccess("<Code Language=\"visualbasic\">code</Code>", expectedCodeLanguage: "VB");
|
||||
TryLoadTaskBodyAndExpectSuccess("<Code Language=\"ViSuAl BaSic\">code</Code>", expectedCodeLanguage: "VB");
|
||||
|
||||
// Default when the Language attribute is not present.
|
||||
TryLoadTaskBodyAndExpectSuccess("<Code>code</Code>", expectedCodeLanguage: "CS");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -474,6 +477,31 @@ End Namespace
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CSharpClass()
|
||||
{
|
||||
const string taskClassSourceCode = @"namespace InlineTask
|
||||
{
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
public class HelloWorld : Task
|
||||
{
|
||||
public override bool Execute()
|
||||
{
|
||||
Log.LogMessage(""Hello, world!"");
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
TryLoadTaskBodyAndExpectSuccess(
|
||||
$"<Code Type=\"Class\">{taskClassSourceCode}</Code>",
|
||||
expectedSourceCode: taskClassSourceCode,
|
||||
expectedCodeType: RoslynCodeTaskFactoryCodeType.Class,
|
||||
expectedCodeLanguage: "CS");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CSharpFragment()
|
||||
{
|
||||
|
@ -690,6 +718,36 @@ namespace InlineCode {{
|
|||
expectedCodeType: RoslynCodeTaskFactoryCodeType.Method);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CSharpClassSourceCodeFromFile()
|
||||
{
|
||||
const string taskClassSourceCode = @"namespace InlineTask
|
||||
{
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
public class HelloWorld : Task
|
||||
{
|
||||
public override bool Execute()
|
||||
{
|
||||
Log.LogMessage(""Hello, world!"");
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
}
|
||||
}
|
||||
";
|
||||
|
||||
using (TestEnvironment env = TestEnvironment.Create())
|
||||
{
|
||||
TransientTestFile file = env.CreateFile(fileName: "CSharpClassSourceCodeFromFile.tmp", contents: taskClassSourceCode);
|
||||
|
||||
TryLoadTaskBodyAndExpectSuccess(
|
||||
$"<Code Source=\"{file.Path}\" />",
|
||||
expectedSourceCode: taskClassSourceCode,
|
||||
expectedCodeType: RoslynCodeTaskFactoryCodeType.Class,
|
||||
expectedCodeLanguage: "CS");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CSharpFragmentSourceCodeFromFile()
|
||||
{
|
||||
|
@ -969,6 +1027,47 @@ namespace InlineCode {{
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MismatchedTaskNameAndTaskClassName()
|
||||
{
|
||||
const string taskName = "SayHello";
|
||||
const string className = "HelloWorld";
|
||||
taskName.ShouldNotBe(className, "The test is misconfigured.");
|
||||
string errorMessage = string.Format(ResourceUtilities.GetResourceString("CodeTaskFactory.CouldNotFindTaskInAssembly"), taskName);
|
||||
|
||||
const string projectContent = @"<Project>
|
||||
<UsingTask TaskName=""" + taskName + @""" TaskFactory=""RoslynCodeTaskFactory"" AssemblyFile=""$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll"">
|
||||
<Task>
|
||||
<Code Type=""Class"">
|
||||
namespace InlineTask
|
||||
{
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
public class " + className + @" : Task
|
||||
{
|
||||
public override bool Execute()
|
||||
{
|
||||
Log.LogMessage(""Hello, world!"");
|
||||
return !Log.HasLoggedErrors;
|
||||
}
|
||||
}
|
||||
}
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
<Target Name=""Build"">
|
||||
<" + taskName + @" />
|
||||
</Target>
|
||||
</Project>";
|
||||
|
||||
using (TestEnvironment env = TestEnvironment.Create())
|
||||
{
|
||||
TransientTestProjectWithFiles proj = env.CreateTestProjectWithFiles(projectContent);
|
||||
var logger = proj.BuildProjectExpectFailure();
|
||||
logger.AssertLogContains(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
private void TryLoadTaskBodyAndExpectFailure(string taskBody, string expectedErrorMessage)
|
||||
{
|
||||
if (expectedErrorMessage == null)
|
||||
|
|
|
@ -238,6 +238,57 @@ namespace Microsoft.Build.Tasks.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Question WriteLines to return true when Lines are empty.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void QuestionWriteLinesWhenLinesAreEmpty()
|
||||
{
|
||||
// Test the combination of:
|
||||
// 1) File exists
|
||||
// 2) Overwrite
|
||||
// 3) WriteOnlyWhenDifferent
|
||||
|
||||
var fileExists = FileUtilities.GetTemporaryFile();
|
||||
var fileNotExists = FileUtilities.GetTemporaryFileName();
|
||||
try
|
||||
{
|
||||
TestWriteLines(fileExists, fileNotExists, Overwrite: true, WriteOnlyWhenDifferent: true);
|
||||
TestWriteLines(fileExists, fileNotExists, Overwrite: false, WriteOnlyWhenDifferent: true);
|
||||
TestWriteLines(fileExists, fileNotExists, Overwrite: true, WriteOnlyWhenDifferent: false);
|
||||
TestWriteLines(fileExists, fileNotExists, Overwrite: false, WriteOnlyWhenDifferent: false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(fileExists);
|
||||
}
|
||||
|
||||
void TestWriteLines(string fileExists, string fileNotExists, bool Overwrite, bool WriteOnlyWhenDifferent)
|
||||
{
|
||||
var test1 = new WriteLinesToFile
|
||||
{
|
||||
Overwrite = Overwrite,
|
||||
BuildEngine = new MockEngine(_output),
|
||||
File = new TaskItem(fileExists),
|
||||
WriteOnlyWhenDifferent = WriteOnlyWhenDifferent,
|
||||
FailIfNotIncremental = true,
|
||||
// Tests Lines = null.
|
||||
};
|
||||
test1.Execute().ShouldBeTrue();
|
||||
|
||||
var test2 = new WriteLinesToFile
|
||||
{
|
||||
Overwrite = Overwrite,
|
||||
BuildEngine = new MockEngine(_output),
|
||||
File = new TaskItem(fileNotExists),
|
||||
WriteOnlyWhenDifferent = WriteOnlyWhenDifferent,
|
||||
FailIfNotIncremental = true,
|
||||
Lines = Array.Empty<ITaskItem>(), // Test empty.
|
||||
};
|
||||
test2.Execute().ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should create directory structure when target <see cref="WriteLinesToFile.File"/> does not exist.
|
||||
/// </summary>
|
||||
|
|
|
@ -133,8 +133,11 @@ namespace Microsoft.Build.Tasks
|
|||
|
||||
if (FailIfNotIncremental)
|
||||
{
|
||||
Log.LogErrorWithCodeFromResources("WriteLinesToFile.ErrorReadingFile", File.ItemSpec);
|
||||
return false;
|
||||
if (Lines?.Length > 0)
|
||||
{
|
||||
Log.LogErrorWithCodeFromResources("WriteLinesToFile.ErrorReadingFile", File.ItemSpec);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -143,7 +146,7 @@ namespace Microsoft.Build.Tasks
|
|||
}
|
||||
else
|
||||
{
|
||||
if (FailIfNotIncremental)
|
||||
if (FailIfNotIncremental && Lines?.Length > 0)
|
||||
{
|
||||
Log.LogErrorWithCodeFromResources("WriteLinesToFile.ErrorOrWarning", File.ItemSpec, string.Empty);
|
||||
return false;
|
||||
|
|
|
@ -181,6 +181,12 @@ namespace Microsoft.Build.Tasks
|
|||
TaskType = exportedTypes.FirstOrDefault(type => type.Name.Equals(taskName, StringComparison.OrdinalIgnoreCase))
|
||||
?? exportedTypes.Where(i => i.FullName != null).FirstOrDefault(type => type.FullName.Equals(taskName, StringComparison.OrdinalIgnoreCase) || type.FullName.EndsWith(taskName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (TaskType == null)
|
||||
{
|
||||
_log.LogErrorWithCodeFromResources("CodeTaskFactory.CouldNotFindTaskInAssembly", taskName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (taskInfo.CodeType == RoslynCodeTaskFactoryCodeType.Class && parameterGroup.Count == 0)
|
||||
{
|
||||
// If the user specified a whole class but nothing in <ParameterGroup />, automatically derive
|
||||
|
|
Загрузка…
Ссылка в новой задаче