зеркало из https://github.com/dotnet/msbuild.git
Merge remote-tracking branch 'dotnet/main' into livelogger
This commit is contained in:
Коммит
41390058e7
|
@ -0,0 +1,27 @@
|
|||
name: 💡 Feature Request
|
||||
description: Suggest an idea for this project.
|
||||
title: "[Feature Request]: "
|
||||
labels: ["Feature Request"]
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Summary
|
||||
description: Brief summary of what this proposal is about.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Background and Motivation
|
||||
description: What is the problem we are solving and in what context did you encounter it?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Proposed Feature
|
||||
description: Please provide a sketch of the feature you are proposing.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Alternative Designs
|
||||
description: If you have an idea how to achieve this new feature, let us know that here. Please include any pointers to code, relevant changes, or related issues you know of.
|
|
@ -455,10 +455,98 @@
|
|||
"operator": "and",
|
||||
"operands": [
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs17.4"
|
||||
}
|
||||
"operator": "or",
|
||||
"operands": [
|
||||
{
|
||||
"name": "isAction",
|
||||
"parameters": {
|
||||
"action": "opened"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "isAction",
|
||||
"parameters": {
|
||||
"action": "reopened"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "labelAdded",
|
||||
"parameters": {
|
||||
"label": "Servicing-consider"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"operator": "or",
|
||||
"operands": [
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs17.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs17.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs17.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs17.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs17.6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs17.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs17.8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs17.9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs17.10"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs16.11"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "prTargetsBranch",
|
||||
"parameters": {
|
||||
"branchName": "vs15.9"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -28,6 +28,7 @@ A wave of features is set to "rotate out" (i.e. become standard functionality) t
|
|||
- [Eliminate project string cache](https://github.com/dotnet/msbuild/pull/7965)
|
||||
- [Log an error when no provided search path for an import exists](https://github.com/dotnet/msbuild/pull/8095)
|
||||
- [Log assembly loads](https://github.com/dotnet/msbuild/pull/8316)
|
||||
- [AnyHaveMetadataValue returns false when passed an empty list](https://github.com/dotnet/msbuild/pull/8603)
|
||||
|
||||
### 17.4
|
||||
- [Respect deps.json when loading assemblies](https://github.com/dotnet/msbuild/pull/7520)
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Dependencies>
|
||||
<ToolsetDependencies>
|
||||
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="6.0.0-beta.23114.5">
|
||||
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="6.0.0-beta.23167.1">
|
||||
<Uri>https://github.com/dotnet/arcade</Uri>
|
||||
<Sha>0c93c1cb1ef9c9d5c1a59f4ab98c2f7e37f12197</Sha>
|
||||
<Sha>92c39a4f0bacef20812f63e2e1d3f7aa8776038d</Sha>
|
||||
<SourceBuild RepoName="arcade" ManagedOnly="true" />
|
||||
</Dependency>
|
||||
<Dependency Name="NuGet.Build.Tasks" Version="6.5.0-rc.149">
|
||||
<Uri>https://github.com/nuget/nuget.client</Uri>
|
||||
<Sha>ca5029046d7b6e55f322c45abb7b342054543710</Sha>
|
||||
</Dependency>
|
||||
<Dependency Name="Microsoft.Net.Compilers.Toolset" Version="4.6.0-2.23152.6">
|
||||
<Dependency Name="Microsoft.Net.Compilers.Toolset" Version="4.6.0-2.23166.9">
|
||||
<Uri>https://github.com/dotnet/roslyn</Uri>
|
||||
<Sha>1314d090671dc1a1500c5303c4b5ae9150f40d98</Sha>
|
||||
<Sha>48b13597fee9df5ecfbd0b8c0758b3f46bc1d440</Sha>
|
||||
</Dependency>
|
||||
<Dependency Name="Microsoft.DotNet.XUnitExtensions" Version="6.0.0-beta.23114.5">
|
||||
<Dependency Name="Microsoft.DotNet.XUnitExtensions" Version="6.0.0-beta.23167.1">
|
||||
<Uri>https://github.com/dotnet/arcade</Uri>
|
||||
<Sha>0c93c1cb1ef9c9d5c1a59f4ab98c2f7e37f12197</Sha>
|
||||
<Sha>92c39a4f0bacef20812f63e2e1d3f7aa8776038d</Sha>
|
||||
</Dependency>
|
||||
</ToolsetDependencies>
|
||||
</Dependencies>
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the MIT license. See License.txt in the project root for full license information. -->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>17.6.0</VersionPrefix>
|
||||
<PackageValidationBaselineVersion>17.5.0-preview-23075-01</PackageValidationBaselineVersion>
|
||||
<VersionPrefix>17.7.0</VersionPrefix>
|
||||
<PackageValidationBaselineVersion>17.6.0-preview-23178-11</PackageValidationBaselineVersion>
|
||||
<AssemblyVersion>15.1.0.0</AssemblyVersion>
|
||||
<PreReleaseVersionLabel>preview</PreReleaseVersionLabel>
|
||||
<DotNetUseShippingVersions>true</DotNetUseShippingVersions>
|
||||
|
@ -48,10 +48,10 @@
|
|||
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>6.0.0-beta.23114.5</MicrosoftDotNetXUnitExtensionsVersion>
|
||||
<MicrosoftDotNetXUnitExtensionsVersion>6.0.0-beta.23167.1</MicrosoftDotNetXUnitExtensionsVersion>
|
||||
<MicrosoftExtensionsDependencyModelVersion>7.0.0</MicrosoftExtensionsDependencyModelVersion>
|
||||
<MicrosoftIORedistVersion>6.0.0</MicrosoftIORedistVersion>
|
||||
<MicrosoftNetCompilersToolsetVersion>4.6.0-2.23152.6</MicrosoftNetCompilersToolsetVersion>
|
||||
<MicrosoftNetCompilersToolsetVersion>4.6.0-2.23166.9</MicrosoftNetCompilersToolsetVersion>
|
||||
<NuGetBuildTasksVersion>6.5.0-rc.149</NuGetBuildTasksVersion>
|
||||
<SystemRuntimeCompilerServicesUnsafeVersion>6.0.0</SystemRuntimeCompilerServicesUnsafeVersion>
|
||||
<SystemTextJsonVersion>7.0.0</SystemTextJsonVersion>
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
"xcopy-msbuild": "17.4.1"
|
||||
},
|
||||
"msbuild-sdks": {
|
||||
"Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.23114.5"
|
||||
"Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.23167.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -222,6 +222,18 @@ namespace Microsoft.Build.UnitTests.Evaluation
|
|||
Assert.Equal("false", itemsFalse[0].EvaluatedInclude);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExpandEmptyItemVectorFunctionWithAnyHaveMetadataValue()
|
||||
{
|
||||
ProjectInstance project = ProjectHelpers.CreateEmptyProjectInstance();
|
||||
Expander<ProjectPropertyInstance, ProjectItemInstance> expander = CreateItemFunctionExpander();
|
||||
ProjectItemInstanceFactory itemFactory = new ProjectItemInstanceFactory(project, "i");
|
||||
|
||||
IList<ProjectItemInstance> itemsEmpty = expander.ExpandIntoItemsLeaveEscaped("@(unsetItem->AnyHaveMetadataValue('Metadatum', 'value'))", itemFactory, ExpanderOptions.ExpandItems, MockElementLocation.Instance);
|
||||
ProjectItemInstance pii = itemsEmpty.ShouldHaveSingleItem<ProjectItemInstance>();
|
||||
pii.EvaluatedInclude.ShouldBe("false");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expand an item vector function Metadata()->DirectoryName()->Distinct()
|
||||
/// </summary>
|
||||
|
|
|
@ -102,6 +102,48 @@ namespace Microsoft.Build.Graph.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateNegotiationOverride()
|
||||
{
|
||||
using (var env = TestEnvironment.Create())
|
||||
{
|
||||
|
||||
TransientTestFile entryProject = CreateProjectFile(env, 1, extraContent: @"<PropertyGroup>
|
||||
<EnableDynamicPlatformResolution>true</EnableDynamicPlatformResolution>
|
||||
<Platform>x64</Platform>
|
||||
<PlatformLookupTable>win32=x64</PlatformLookupTable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include=""$(MSBuildThisFileDirectory)2.proj"" >
|
||||
<OverridePlatformNegotiationValue>x86</OverridePlatformNegotiationValue>
|
||||
</ProjectReference>
|
||||
</ItemGroup>");
|
||||
var proj2 = env.CreateFile("2.proj", @"
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<EnableDynamicPlatformResolution>true</EnableDynamicPlatformResolution>
|
||||
<Platforms>x64;AnyCPU</Platforms>
|
||||
<Platform>x86</Platform>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include=""$(MSBuildThisFileDirectory)3.proj"" >
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
</Project>");
|
||||
var proj3 = env.CreateFile("3.proj", @"
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Platforms>AnyCPU;x86</Platforms>
|
||||
</PropertyGroup>
|
||||
</Project>");
|
||||
|
||||
|
||||
ProjectGraph graph = new ProjectGraph(entryProject.Path);
|
||||
GetFirstNodeWithProjectNumber(graph, 2).ProjectInstance.GlobalProperties.ContainsKey("Platform").ShouldBeFalse();
|
||||
GetFirstNodeWithProjectNumber(graph, 3).ProjectInstance.GlobalProperties["Platform"].ShouldBe("x86");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolvesMultipleReferencesToSameProject()
|
||||
{
|
||||
|
|
|
@ -246,15 +246,15 @@ namespace Microsoft.Build.BackEnd.Logging
|
|||
/// <summary>
|
||||
/// Event set when message is consumed from queue.
|
||||
/// </summary>
|
||||
private ManualResetEventSlim _dequeueEvent;
|
||||
private AutoResetEvent _dequeueEvent;
|
||||
/// <summary>
|
||||
/// Event set when queue become empty.
|
||||
/// </summary>
|
||||
private ManualResetEventSlim _emptyQueueEvent;
|
||||
private ManualResetEvent _emptyQueueEvent;
|
||||
/// <summary>
|
||||
/// Even set when message is added into queue.
|
||||
/// </summary>
|
||||
private ManualResetEventSlim _enqueueEvent;
|
||||
private AutoResetEvent _enqueueEvent;
|
||||
|
||||
/// <summary>
|
||||
/// CTS for stopping logging event processing.
|
||||
|
@ -1183,8 +1183,7 @@ namespace Microsoft.Build.BackEnd.Logging
|
|||
while (_eventQueue.Count >= _queueCapacity)
|
||||
{
|
||||
// Block and wait for dequeue event.
|
||||
_dequeueEvent.Wait();
|
||||
_dequeueEvent.Reset();
|
||||
_dequeueEvent.WaitOne();
|
||||
}
|
||||
|
||||
_eventQueue.Enqueue(buildEvent);
|
||||
|
@ -1209,12 +1208,12 @@ namespace Microsoft.Build.BackEnd.Logging
|
|||
{
|
||||
while (_eventQueue?.IsEmpty == false)
|
||||
{
|
||||
_emptyQueueEvent?.Wait();
|
||||
_emptyQueueEvent?.WaitOne();
|
||||
}
|
||||
// To avoid race condition when last message has been removed from queue but
|
||||
// not yet fully processed (handled by loggers), we need to make sure _emptyQueueEvent
|
||||
// is set as it is guaranteed to be in set state no sooner than after event has been processed.
|
||||
_emptyQueueEvent?.Wait();
|
||||
_emptyQueueEvent?.WaitOne();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1263,9 +1262,9 @@ namespace Microsoft.Build.BackEnd.Logging
|
|||
private void StartLoggingEventProcessing()
|
||||
{
|
||||
_eventQueue = new ConcurrentQueue<object>();
|
||||
_dequeueEvent = new ManualResetEventSlim(false);
|
||||
_emptyQueueEvent = new ManualResetEventSlim(false);
|
||||
_enqueueEvent = new ManualResetEventSlim(false);
|
||||
_dequeueEvent = new AutoResetEvent(false);
|
||||
_emptyQueueEvent = new ManualResetEvent(false);
|
||||
_enqueueEvent = new AutoResetEvent(false);
|
||||
_loggingEventProcessingCancellation = new CancellationTokenSource();
|
||||
|
||||
_loggingEventProcessingThread = new Thread(LoggingEventProc);
|
||||
|
@ -1276,7 +1275,7 @@ namespace Microsoft.Build.BackEnd.Logging
|
|||
void LoggingEventProc()
|
||||
{
|
||||
var completeAdding = _loggingEventProcessingCancellation.Token;
|
||||
WaitHandle[] waitHandlesForNextEvent = { completeAdding.WaitHandle, _enqueueEvent.WaitHandle };
|
||||
WaitHandle[] waitHandlesForNextEvent = { completeAdding.WaitHandle, _enqueueEvent };
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -1295,7 +1294,6 @@ namespace Microsoft.Build.BackEnd.Logging
|
|||
WaitHandle.WaitAny(waitHandlesForNextEvent);
|
||||
}
|
||||
|
||||
_enqueueEvent.Reset();
|
||||
_emptyQueueEvent.Reset();
|
||||
}
|
||||
} while (!_eventQueue.IsEmpty || !completeAdding.IsCancellationRequested);
|
||||
|
|
|
@ -543,22 +543,19 @@ namespace Microsoft.Build.Experimental.ProjectCache
|
|||
string definingProjectPath,
|
||||
Dictionary<string, string> templateGlobalProperties)
|
||||
{
|
||||
// TODO: fix code clone for parsing CurrentSolutionConfiguration xml: https://github.com/dotnet/msbuild/issues/6751
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(solutionConfigurationXml);
|
||||
|
||||
var root = doc.DocumentElement!;
|
||||
var projectConfigurationNodes = root.GetElementsByTagName("ProjectConfiguration");
|
||||
|
||||
ErrorUtilities.VerifyThrow(projectConfigurationNodes.Count > 0, "Expected at least one project in solution");
|
||||
|
||||
var graphEntryPoints = new List<ProjectGraphEntryPoint>(projectConfigurationNodes.Count);
|
||||
|
||||
foreach (XmlNode node in projectConfigurationNodes)
|
||||
XmlNodeList? projectConfigurations = SolutionConfiguration.GetProjectConfigurations(solutionConfigurationXml);
|
||||
if (projectConfigurations == null || projectConfigurations.Count == 0)
|
||||
{
|
||||
ErrorUtilities.VerifyThrowInternalNull(node.Attributes, nameof(node.Attributes));
|
||||
return Array.Empty<ProjectGraphEntryPoint>();
|
||||
}
|
||||
|
||||
var buildProjectInSolution = node.Attributes!["BuildProjectInSolution"];
|
||||
var graphEntryPoints = new List<ProjectGraphEntryPoint>(projectConfigurations.Count);
|
||||
|
||||
foreach (XmlElement projectConfiguration in projectConfigurations)
|
||||
{
|
||||
ErrorUtilities.VerifyThrowInternalNull(projectConfiguration.Attributes, nameof(projectConfiguration.Attributes));
|
||||
|
||||
var buildProjectInSolution = projectConfiguration.Attributes![SolutionConfiguration.BuildProjectInSolutionAttribute];
|
||||
if (buildProjectInSolution is not null &&
|
||||
string.IsNullOrWhiteSpace(buildProjectInSolution.Value) is false &&
|
||||
bool.TryParse(buildProjectInSolution.Value, out var buildProject) &&
|
||||
|
@ -567,12 +564,12 @@ namespace Microsoft.Build.Experimental.ProjectCache
|
|||
continue;
|
||||
}
|
||||
|
||||
var projectPathAttribute = node.Attributes!["AbsolutePath"];
|
||||
XmlAttribute? projectPathAttribute = projectConfiguration.Attributes![SolutionConfiguration.AbsolutePathAttribute];
|
||||
ErrorUtilities.VerifyThrow(projectPathAttribute is not null, "Expected VS to set the project path on each ProjectConfiguration element.");
|
||||
|
||||
var projectPath = projectPathAttribute!.Value;
|
||||
string projectPath = projectPathAttribute!.Value;
|
||||
|
||||
var (configuration, platform) = SolutionFile.ParseConfigurationName(node.InnerText, definingProjectPath, 0, solutionConfigurationXml);
|
||||
(string configuration, string platform) = SolutionFile.ParseConfigurationName(projectConfiguration.InnerText, definingProjectPath, 0, solutionConfigurationXml);
|
||||
|
||||
// Take the defining project global properties and override the configuration and platform.
|
||||
// It's sufficient to only set Configuration and Platform.
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
#if FEATURE_APPDOMAIN
|
||||
using System.Runtime.Remoting;
|
||||
|
@ -123,7 +124,7 @@ namespace Microsoft.Build.BackEnd
|
|||
private List<TaskItem> _remotedTaskItems;
|
||||
|
||||
/// <summary>
|
||||
/// We need access to the build component host so that we can get at the
|
||||
/// We need access to the build component host so that we can get at the
|
||||
/// task host node provider when running a task wrapped by TaskHostTask
|
||||
/// </summary>
|
||||
private readonly IBuildComponentHost _buildComponentHost;
|
||||
|
@ -813,15 +814,15 @@ namespace Microsoft.Build.BackEnd
|
|||
/// 2) checks the global task declarations (in *.TASKS in MSbuild bin dir), searching by exact name and task identity parameters
|
||||
/// 3) checks the tasks declared by the project, searching by fuzzy match (missing namespace, etc.) and task identity parameters
|
||||
/// 4) checks the global task declarations (in *.TASKS in MSbuild bin dir), searching by fuzzy match (missing namespace, etc.) and task identity parameters
|
||||
/// 5) 1-4 again in order without the task identity parameters, to gather additional information for the user (if the task identity
|
||||
/// parameters don't match, it is an error, but at least we can return them a more useful error in this case than just "could not
|
||||
/// 5) 1-4 again in order without the task identity parameters, to gather additional information for the user (if the task identity
|
||||
/// parameters don't match, it is an error, but at least we can return them a more useful error in this case than just "could not
|
||||
/// find task")
|
||||
///
|
||||
///
|
||||
/// The search ordering is meant to reduce the number of assemblies we scan, because loading assemblies can be expensive.
|
||||
/// The tasks and assemblies declared by the project are scanned first, on the assumption that if the project declared
|
||||
/// them, they are likely used.
|
||||
///
|
||||
/// If the set of task identity parameters are defined, only tasks that match that identity are chosen.
|
||||
///
|
||||
/// If the set of task identity parameters are defined, only tasks that match that identity are chosen.
|
||||
/// </summary>
|
||||
/// <returns>The Type of the task, or null if it was not found.</returns>
|
||||
private TaskFactoryWrapper FindTaskInRegistry(IDictionary<string, string> taskIdentityParameters)
|
||||
|
@ -874,7 +875,7 @@ namespace Microsoft.Build.BackEnd
|
|||
taskRuntime ?? XMakeAttributes.MSBuildRuntimeValues.any,
|
||||
taskArchitecture ?? XMakeAttributes.MSBuildArchitectureValues.any);
|
||||
|
||||
// if we've logged this error, even though we've found something, we want to act like we didn't.
|
||||
// if we've logged this error, even though we've found something, we want to act like we didn't.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1240,8 +1241,8 @@ namespace Microsoft.Build.BackEnd
|
|||
bool success;
|
||||
IList<TaskItem> finalTaskItems = _batchBucket.Expander.ExpandIntoTaskItemsLeaveEscaped(parameterValue, ExpanderOptions.ExpandAll, parameterLocation);
|
||||
|
||||
// If there were no items, don't change the parameter's value. EXCEPT if it's marked as a required
|
||||
// parameter, in which case we made an explicit decision to pass in an empty array. This is
|
||||
// If there were no items, don't change the parameter's value. EXCEPT if it's marked as a required
|
||||
// parameter, in which case we made an explicit decision to pass in an empty array. This is
|
||||
// to avoid project authors having to add Conditions on all their tasks to avoid calling them
|
||||
// when a particular item list is empty. This way, we just call the task with an empty list,
|
||||
// the task will loop over an empty list, and return quickly.
|
||||
|
@ -1367,7 +1368,7 @@ namespace Microsoft.Build.BackEnd
|
|||
|
||||
if (outputAsProjectItem != null)
|
||||
{
|
||||
// The common case -- all items involved are Microsoft.Build.Execution.ProjectItemInstance.TaskItems.
|
||||
// The common case -- all items involved are Microsoft.Build.Execution.ProjectItemInstance.TaskItems.
|
||||
// Furthermore, because that is true, we know by definition that they also implement ITaskItem2.
|
||||
newItem = new ProjectItemInstance(_projectInstance, outputTargetName, outputAsProjectItem.IncludeEscaped, parameterLocationEscaped);
|
||||
|
||||
|
@ -1377,25 +1378,21 @@ namespace Microsoft.Build.BackEnd
|
|||
{
|
||||
if (output is ITaskItem2 outputAsITaskItem2)
|
||||
{
|
||||
// Probably a Microsoft.Build.Utilities.TaskItem. Not quite as good, but we can still preserve escaping.
|
||||
// Probably a Microsoft.Build.Utilities.TaskItem. Not quite as good, but we can still preserve escaping.
|
||||
newItem = new ProjectItemInstance(_projectInstance, outputTargetName, outputAsITaskItem2.EvaluatedIncludeEscaped, parameterLocationEscaped);
|
||||
|
||||
// It would be nice to be copy-on-write here, but Utilities.TaskItem doesn't know about CopyOnWritePropertyDictionary.
|
||||
foreach (DictionaryEntry entry in outputAsITaskItem2.CloneCustomMetadataEscaped())
|
||||
{
|
||||
newItem.SetMetadataOnTaskOutput((string)entry.Key, (string)entry.Value);
|
||||
}
|
||||
// It would be nice to be copy-on-write here, but Utilities.TaskItem doesn't know about CopyOnWritePropertyDictionary.
|
||||
newItem.SetMetadataOnTaskOutput(outputAsITaskItem2.CloneCustomMetadataEscaped().Cast<KeyValuePair<string, string>>());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not a ProjectItemInstance.TaskItem or even a ITaskItem2, so we have to fake it.
|
||||
// Setting an item spec expects the escaped value, as does setting metadata.
|
||||
// Not a ProjectItemInstance.TaskItem or even a ITaskItem2, so we have to fake it.
|
||||
// Setting an item spec expects the escaped value, as does setting metadata.
|
||||
newItem = new ProjectItemInstance(_projectInstance, outputTargetName, EscapingUtilities.Escape(output.ItemSpec), parameterLocationEscaped);
|
||||
|
||||
foreach (DictionaryEntry entry in output.CloneCustomMetadata())
|
||||
{
|
||||
newItem.SetMetadataOnTaskOutput((string)entry.Key, EscapingUtilities.Escape((string)entry.Value));
|
||||
}
|
||||
newItem.SetMetadataOnTaskOutput(output.CloneCustomMetadata()
|
||||
.Cast<KeyValuePair<string, string>>()
|
||||
.Select(x => new KeyValuePair<string, string>(x.Key, EscapingUtilities.Escape(x.Value))));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1418,7 +1415,7 @@ namespace Microsoft.Build.BackEnd
|
|||
// to store an ITaskItem array in a property, join all the item-specs with semi-colons to make the
|
||||
// property value, and ignore/discard the attributes on the ITaskItems.
|
||||
//
|
||||
// An empty ITaskItem[] should create a blank value property, for compatibility.
|
||||
// An empty ITaskItem[] should create a blank value property, for compatibility.
|
||||
StringBuilder joinedOutputs = (outputs.Length == 0) ? new StringBuilder() : null;
|
||||
|
||||
foreach (ITaskItem output in outputs)
|
||||
|
@ -1463,7 +1460,7 @@ namespace Microsoft.Build.BackEnd
|
|||
/// </summary>
|
||||
private void GatherArrayStringAndValueOutputs(bool outputTargetIsItem, string outputTargetName, string[] outputs, ElementLocation parameterLocation, TaskPropertyInfo parameter)
|
||||
{
|
||||
// if the task has generated outputs (if it didn't, don't do anything)
|
||||
// if the task has generated outputs (if it didn't, don't do anything)
|
||||
if (outputs != null)
|
||||
{
|
||||
if (outputTargetIsItem)
|
||||
|
@ -1494,7 +1491,7 @@ namespace Microsoft.Build.BackEnd
|
|||
// to store an object array in a property, join all the string representations of the objects with
|
||||
// semi-colons to make the property value
|
||||
//
|
||||
// An empty ITaskItem[] should create a blank value property, for compatibility.
|
||||
// An empty ITaskItem[] should create a blank value property, for compatibility.
|
||||
StringBuilder joinedOutputs = (outputs.Length == 0) ? new StringBuilder() : null;
|
||||
|
||||
foreach (string output in outputs)
|
||||
|
|
|
@ -247,7 +247,7 @@ namespace Microsoft.Build.Construction
|
|||
};
|
||||
using (XmlWriter xw = XmlWriter.Create(solutionConfigurationContents, settings))
|
||||
{
|
||||
// TODO: fix code clone for parsing CurrentSolutionConfiguration xml: https://github.com/dotnet/msbuild/issues/6751
|
||||
// TODO: Consider augmenting SolutionConfiguration with this code
|
||||
xw.WriteStartElement("SolutionConfiguration");
|
||||
|
||||
// add a project configuration entry for each project in the solution
|
||||
|
|
|
@ -1946,11 +1946,16 @@ namespace Microsoft.Build.Evaluation
|
|||
// If there are no items of the given type, then bail out early
|
||||
if (itemsOfType.Count == 0)
|
||||
{
|
||||
// .. but only if there isn't a function "Count()", since that will want to return something (zero) for an empty list
|
||||
// ... but only if there isn't a function "Count", since that will want to return something (zero) for an empty list
|
||||
if (expressionCapture.Captures?.Any(capture => string.Equals(capture.FunctionName, "Count", StringComparison.OrdinalIgnoreCase)) != true)
|
||||
{
|
||||
itemsFromCapture = new List<Pair<string, S>>();
|
||||
return false;
|
||||
// ...or a function "AnyHaveMetadataValue", since that will want to return false for an empty list.
|
||||
if (!ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_6) ||
|
||||
expressionCapture.Captures?.Any(capture => string.Equals(capture.FunctionName, "AnyHaveMetadataValue", StringComparison.OrdinalIgnoreCase)) != true)
|
||||
{
|
||||
itemsFromCapture = new List<Pair<string, S>>();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using Microsoft.Build.Collections;
|
||||
using Microsoft.Build.Construction;
|
||||
|
@ -458,13 +459,44 @@ namespace Microsoft.Build.Evaluation
|
|||
{
|
||||
lock (_locker)
|
||||
{
|
||||
LinkedList<ProjectRootElement> oldStrongCache = _strongCache;
|
||||
_weakCache = new WeakValueDictionary<string, ProjectRootElement>(StringComparer.OrdinalIgnoreCase);
|
||||
_strongCache = new LinkedList<ProjectRootElement>();
|
||||
|
||||
foreach (ProjectRootElement projectRootElement in oldStrongCache)
|
||||
if (Traits.Instance.EscapeHatches.AlwaysDoImmutableFilesUpToDateCheck)
|
||||
{
|
||||
RaiseProjectRootElementRemovedFromStrongCache(projectRootElement);
|
||||
LinkedList<ProjectRootElement> oldStrongCache = _strongCache;
|
||||
_weakCache = new WeakValueDictionary<string, ProjectRootElement>(StringComparer.OrdinalIgnoreCase);
|
||||
_strongCache = new LinkedList<ProjectRootElement>();
|
||||
|
||||
foreach (ProjectRootElement projectRootElement in oldStrongCache)
|
||||
{
|
||||
RaiseProjectRootElementRemovedFromStrongCache(projectRootElement);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Manually iterate through LinkedList so we can remove items during this iteration
|
||||
for (var listNode = _strongCache.First; listNode != null;)
|
||||
{
|
||||
var nextNode = listNode.Next;
|
||||
|
||||
ProjectRootElement projectRootElement = listNode.Value;
|
||||
// Do not remove cache of files from immutable locations.
|
||||
// Those are mostly SDK project files and will be most probably needed in next builds.
|
||||
if (!FileClassifier.Shared.IsNonModifiable(projectRootElement.FullPath))
|
||||
{
|
||||
_weakCache.Remove(projectRootElement.FullPath);
|
||||
_strongCache.Remove(listNode);
|
||||
RaiseProjectRootElementRemovedFromStrongCache(projectRootElement);
|
||||
}
|
||||
|
||||
listNode = nextNode;
|
||||
}
|
||||
|
||||
// From weak list remove all which is not in strong list anymore
|
||||
IList<string> toBeRemovedFromWeakRefs = _weakCache.Keys.Except(_strongCache.Select(i => i.FullPath)).ToList();
|
||||
foreach (string victim in toBeRemovedFromWeakRefs)
|
||||
{
|
||||
_weakCache.Remove(victim);
|
||||
}
|
||||
_weakCache.Scavenge();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace Microsoft.Build.Graph
|
|||
private const string PlatformMetadataName = "Platform";
|
||||
private const string PlatformsMetadataName = "Platforms";
|
||||
private const string EnableDynamicPlatformResolutionMetadataName = "EnableDynamicPlatformResolution";
|
||||
private const string OverridePlatformNegotiationValue = "OverridePlatformNegotiationValue";
|
||||
|
||||
private static readonly char[] PropertySeparator = MSBuildConstants.SemicolonChar;
|
||||
|
||||
|
@ -134,7 +135,9 @@ namespace Microsoft.Build.Graph
|
|||
null, // Platform negotiation requires an evaluation with no global properties first
|
||||
_projectCollection);
|
||||
|
||||
var selectedPlatform = PlatformNegotiation.GetNearestPlatform(projectInstance.GetPropertyValue(PlatformMetadataName), projectInstance.GetPropertyValue(PlatformsMetadataName), projectInstance.GetPropertyValue(PlatformLookupTableMetadataName), requesterInstance.GetPropertyValue(PlatformLookupTableMetadataName), projectInstance.FullPath, requesterInstance.GetPropertyValue(PlatformMetadataName));
|
||||
string overridePlatformNegotiationMetadataValue = projectReferenceItem.GetMetadataValue(OverridePlatformNegotiationValue);
|
||||
|
||||
var selectedPlatform = PlatformNegotiation.GetNearestPlatform(overridePlatformNegotiationMetadataValue, projectInstance.GetPropertyValue(PlatformMetadataName), projectInstance.GetPropertyValue(PlatformsMetadataName), projectInstance.GetPropertyValue(PlatformLookupTableMetadataName), requesterInstance.GetPropertyValue(PlatformLookupTableMetadataName), projectInstance.FullPath, requesterInstance.GetPropertyValue(PlatformMetadataName));
|
||||
|
||||
if (selectedPlatform.Equals(String.Empty))
|
||||
{
|
||||
|
|
|
@ -628,11 +628,11 @@ namespace Microsoft.Build.Execution
|
|||
/// which legally have built-in metadata. If necessary we can calculate it on the new items we're making if requested.
|
||||
/// We don't copy them too because tasks shouldn't set them (they might become inconsistent)
|
||||
/// </summary>
|
||||
internal void SetMetadataOnTaskOutput(string name, string evaluatedValueEscaped)
|
||||
internal void SetMetadataOnTaskOutput(IEnumerable<KeyValuePair<string, string>> items)
|
||||
{
|
||||
_project.VerifyThrowNotImmutable();
|
||||
|
||||
_taskItem.SetMetadataOnTaskOutput(name, evaluatedValueEscaped);
|
||||
_taskItem.SetMetadataOnTaskOutput(items);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1489,8 +1489,8 @@ namespace Microsoft.Build.Execution
|
|||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
// This is ignore case to ensure that task items whose item specs differ only by
|
||||
// casing still have the same hash code, since this is used to determine if we have duplicates when
|
||||
// This is ignore case to ensure that task items whose item specs differ only by
|
||||
// casing still have the same hash code, since this is used to determine if we have duplicates when
|
||||
// we do duplicate removal.
|
||||
return StringComparer.OrdinalIgnoreCase.GetHashCode(ItemSpec);
|
||||
}
|
||||
|
@ -1785,6 +1785,18 @@ namespace Microsoft.Build.Execution
|
|||
}
|
||||
}
|
||||
|
||||
internal void SetMetadataOnTaskOutput(IEnumerable<KeyValuePair<string, string>> items)
|
||||
{
|
||||
ProjectInstance.VerifyThrowNotImmutable(_isImmutable);
|
||||
_directMetadata ??= new CopyOnWritePropertyDictionary<ProjectMetadataInstance>();
|
||||
|
||||
var metadata = items
|
||||
.Where(item => !FileUtilities.ItemSpecModifiers.IsDerivableItemSpecModifier(item.Key))
|
||||
.Select(item => new ProjectMetadataInstance(item.Key, item.Value, true /* may be built-in metadata name */));
|
||||
|
||||
_directMetadata.ImportProperties(metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deep clone this into another TaskItem
|
||||
/// </summary>
|
||||
|
|
|
@ -126,6 +126,7 @@
|
|||
<Link>PlatformNegotiation.cs</Link>
|
||||
<ExcludeFromStyleCop>true</ExcludeFromStyleCop>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\SolutionConfiguration.cs" />
|
||||
<Compile Include="..\Shared\TaskLoggingHelper.cs">
|
||||
<Link>BackEnd\Components\RequestBuilder\IntrinsicTasks\TaskLoggingHelper.cs</Link>
|
||||
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
|
@ -1349,7 +1349,7 @@ namespace Microsoft.Build.CommandLine
|
|||
messagesToLogInBuildLoggers.Add(
|
||||
new BuildManager.DeferredBuildMessage(
|
||||
String.Format("Included response file: {0}", responseFilePath),
|
||||
MessageImportance.Normal,
|
||||
MessageImportance.Low,
|
||||
responseFilePath));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Microsoft.Build.Shared
|
|||
/// </summary>
|
||||
internal static class PlatformNegotiation
|
||||
{
|
||||
internal static string GetNearestPlatform(string referencedProjectPlatform, string projectReferencePlatformsMetadata, string projectReferenceLookupTableMetadata, string platformLookupTable, string projectPath, string currentProjectPlatform, TaskLoggingHelper? log = null)
|
||||
internal static string GetNearestPlatform(string overridePlatformValue, string referencedProjectPlatform, string projectReferencePlatformsMetadata, string projectReferenceLookupTableMetadata, string platformLookupTable, string projectPath, string currentProjectPlatform, TaskLoggingHelper? log = null)
|
||||
{
|
||||
Dictionary<string, string>? currentProjectLookupTable = ExtractLookupTable(platformLookupTable, log);
|
||||
|
||||
|
@ -41,9 +41,14 @@ namespace Microsoft.Build.Shared
|
|||
|
||||
string buildProjectReferenceAs = string.Empty;
|
||||
|
||||
// If an override value is set define that as the platform value as the top priority
|
||||
if (!string.IsNullOrEmpty(overridePlatformValue))
|
||||
{
|
||||
buildProjectReferenceAs = overridePlatformValue;
|
||||
}
|
||||
// If the referenced project has a defined `Platform` that's compatible, it will build that way by default.
|
||||
// Don't set `buildProjectReferenceAs` and the `_GetProjectReferencePlatformProperties` target will handle the rest.
|
||||
if (!string.IsNullOrEmpty(referencedProjectPlatform) && referencedProjectPlatform.Equals(currentProjectPlatform, StringComparison.OrdinalIgnoreCase))
|
||||
else if (!string.IsNullOrEmpty(referencedProjectPlatform) && referencedProjectPlatform.Equals(currentProjectPlatform, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
log?.LogMessageFromResources(MessageImportance.Low, "GetCompatiblePlatform.ReferencedProjectHasDefinitivePlatform", projectPath, referencedProjectPlatform);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
// 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.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace Microsoft.Build.Shared
|
||||
{
|
||||
internal sealed class SolutionConfiguration
|
||||
{
|
||||
public const string ProjectAttribute = "Project";
|
||||
|
||||
public const string AbsolutePathAttribute = "AbsolutePath";
|
||||
|
||||
public const string BuildProjectInSolutionAttribute = "BuildProjectInSolution";
|
||||
|
||||
// This field stores pre-cached project elements for project guids for quicker access by project guid
|
||||
private readonly Dictionary<string, XmlElement> _cachedProjectElements = new Dictionary<string, XmlElement>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// This field stores pre-cached project elements for project guids for quicker access by project absolute path
|
||||
private readonly Dictionary<string, XmlElement> _cachedProjectElementsByAbsolutePath = new Dictionary<string, XmlElement>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// This field stores the project absolute path for quicker access by project guid
|
||||
private readonly Dictionary<string, string> _cachedProjectAbsolutePathsByGuid = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// This field stores the project guid for quicker access by project absolute path
|
||||
private readonly Dictionary<string, string> _cachedProjectGuidsByAbsolutePath = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// This field stores the list of dependency project guids by depending project guid
|
||||
private readonly Dictionary<string, List<string>> _cachedDependencyProjectGuidsByDependingProjectGuid = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public SolutionConfiguration(string xmlString)
|
||||
{
|
||||
// Example:
|
||||
//
|
||||
// <SolutionConfiguration>
|
||||
// <ProjectConfiguration Project="{786E302A-96CE-43DC-B640-D6B6CC9BF6C0}" AbsolutePath="c:foo\Project1\A.csproj" BuildProjectInSolution="True">Debug|AnyCPU</ProjectConfiguration>
|
||||
// <ProjectConfiguration Project="{881C1674-4ECA-451D-85B6-D7C59B7F16FA}" AbsolutePath="c:foo\Project2\B.csproj" BuildProjectInSolution="True">Debug|AnyCPU<ProjectDependency Project="{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}" /></ProjectConfiguration>
|
||||
// <ProjectConfiguration Project="{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}" AbsolutePath="c:foo\Project3\C.csproj" BuildProjectInSolution="True">Debug|AnyCPU</ProjectConfiguration>
|
||||
// </SolutionConfiguration>
|
||||
//
|
||||
XmlNodeList? projectConfigurationElements = GetProjectConfigurations(xmlString);
|
||||
if (projectConfigurationElements != null)
|
||||
{
|
||||
foreach (XmlElement xmlElement in projectConfigurationElements)
|
||||
{
|
||||
string projectGuid = xmlElement.GetAttribute(ProjectAttribute);
|
||||
string projectAbsolutePath = xmlElement.GetAttribute(AbsolutePathAttribute);
|
||||
|
||||
// What we really want here is the normalized path, like we'd get with an item's "FullPath" metadata. However,
|
||||
// if there's some bogus full path in the solution configuration (e.g. a website with a "full path" of c:\solutiondirectory\http://localhost)
|
||||
// we do NOT want to throw -- chances are extremely high that that's information that will never actually be used. So resolve the full path
|
||||
// but just swallow any IO-related exceptions that result. If the path is bogus, the method will return null, so we'll just quietly fail
|
||||
// to cache it below.
|
||||
projectAbsolutePath = FileUtilities.GetFullPathNoThrow(projectAbsolutePath);
|
||||
|
||||
if (!string.IsNullOrEmpty(projectGuid))
|
||||
{
|
||||
_cachedProjectElements[projectGuid] = xmlElement;
|
||||
if (!string.IsNullOrEmpty(projectAbsolutePath))
|
||||
{
|
||||
_cachedProjectElementsByAbsolutePath[projectAbsolutePath] = xmlElement;
|
||||
_cachedProjectAbsolutePathsByGuid[projectGuid] = projectAbsolutePath;
|
||||
_cachedProjectGuidsByAbsolutePath[projectAbsolutePath] = projectGuid;
|
||||
}
|
||||
|
||||
foreach (XmlNode dependencyNode in xmlElement.ChildNodes)
|
||||
{
|
||||
if (dependencyNode.NodeType != XmlNodeType.Element)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
XmlElement dependencyElement = ((XmlElement)dependencyNode);
|
||||
|
||||
if (!String.Equals(dependencyElement.Name, "ProjectDependency", StringComparison.Ordinal))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string dependencyGuid = dependencyElement.GetAttribute("Project");
|
||||
|
||||
if (dependencyGuid.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_cachedDependencyProjectGuidsByDependingProjectGuid.TryGetValue(projectGuid, out List<string>? list))
|
||||
{
|
||||
list = new List<string>();
|
||||
_cachedDependencyProjectGuidsByDependingProjectGuid.Add(projectGuid, list);
|
||||
}
|
||||
|
||||
list.Add(dependencyGuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SolutionConfiguration Empty { get; } = new SolutionConfiguration(string.Empty);
|
||||
|
||||
public ICollection<XmlElement> ProjectConfigurations => _cachedProjectElements.Values;
|
||||
|
||||
public static XmlNodeList? GetProjectConfigurations(string xmlString)
|
||||
{
|
||||
XmlDocument? doc = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(xmlString))
|
||||
{
|
||||
doc = new XmlDocument();
|
||||
var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore };
|
||||
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString), settings))
|
||||
{
|
||||
doc.Load(reader);
|
||||
}
|
||||
}
|
||||
|
||||
return doc?.DocumentElement?.ChildNodes;
|
||||
}
|
||||
|
||||
public bool TryGetProjectByGuid(string projectGuid, [NotNullWhen(true)] out XmlElement? projectElement) => _cachedProjectElements.TryGetValue(projectGuid, out projectElement);
|
||||
|
||||
public bool TryGetProjectByAbsolutePath(string projectFullPath, [NotNullWhen(true)] out XmlElement? projectElement) => _cachedProjectElementsByAbsolutePath.TryGetValue(projectFullPath, out projectElement);
|
||||
|
||||
public bool TryGetProjectGuidByAbsolutePath(string projectFullPath, [NotNullWhen(true)] out string? projectGuid) => _cachedProjectGuidsByAbsolutePath.TryGetValue(projectFullPath, out projectGuid);
|
||||
|
||||
public bool TryGetProjectDependencies(string projectGuid, [NotNullWhen(true)] out List<string>? dependencyProjectGuids) => _cachedDependencyProjectGuidsByDependingProjectGuid.TryGetValue(projectGuid, out dependencyProjectGuids);
|
||||
|
||||
public bool TryGetProjectPathByGuid(string projectGuid, [NotNullWhen(true)] out string? projectPath) => _cachedProjectAbsolutePathsByGuid.TryGetValue(projectGuid, out projectPath);
|
||||
}
|
||||
}
|
|
@ -40,6 +40,29 @@ namespace Microsoft.Build.Tasks.UnitTests
|
|||
task.AssignedProjectsWithPlatform[0].GetMetadata("NearestPlatform").ShouldBe("x64");
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void ResolvesViaOverride()
|
||||
{
|
||||
// OverridePlatformNegotiationValue always takes priority over everything. It is typically user-defined.
|
||||
TaskItem projectReference = new TaskItem("foo.bar");
|
||||
projectReference.SetMetadata("Platforms", "x64;x86;AnyCPU");
|
||||
projectReference.SetMetadata("platform", "x86");
|
||||
projectReference.SetMetadata("OverridePlatformNegotiationValue", "x86");
|
||||
|
||||
GetCompatiblePlatform task = new GetCompatiblePlatform()
|
||||
{
|
||||
BuildEngine = new MockEngine(_output),
|
||||
CurrentProjectPlatform = "x64",
|
||||
PlatformLookupTable = "win32=x64",
|
||||
AnnotatedProjects = new TaskItem[] { projectReference }
|
||||
};
|
||||
|
||||
task.Execute().ShouldBeTrue();
|
||||
|
||||
task.AssignedProjectsWithPlatform[0].GetMetadata("NearestPlatform").ShouldBe("");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolvesViaProjectReferencesPlatformLookupTable()
|
||||
{
|
||||
|
|
|
@ -80,5 +80,29 @@ namespace Microsoft.Build.Tasks.UnitTests
|
|||
bool result = project.Build(logger);
|
||||
Assert.True(result, "Output:" + Environment.NewLine + logger.FullLog);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test for https://github.com/dotnet/msbuild/issues/8153
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void IsWellKnownAttributeValuePreserved()
|
||||
{
|
||||
ObjectModelHelpers.DeleteTempProjectDirectory();
|
||||
|
||||
ObjectModelHelpers.CreateFileInTempProjectDirectory("Myapp.proj", @"
|
||||
<Project ToolsVersion=`msbuilddefaulttoolsversion` xmlns=`msbuildnamespace`>
|
||||
<Target Name =`Repro`>
|
||||
<CreateItem Include=`*.txt` AdditionalMetadata=`MyProperty=Identity`>
|
||||
<Output TaskParameter=`Include` ItemName=`TestItem`/>
|
||||
</CreateItem>
|
||||
<Error Text=`@(TestItem)` Condition=""'%(MyProperty)' != 'Identity' ""/>
|
||||
</Target>
|
||||
</Project>
|
||||
");
|
||||
|
||||
ObjectModelHelpers.CreateFileInTempProjectDirectory("Foo.txt", "foo");
|
||||
MockLogger logger = new MockLogger(_output);
|
||||
ObjectModelHelpers.BuildTempProjectFileExpectSuccess("Myapp.proj", logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1940,6 +1940,48 @@ namespace Microsoft.Build.UnitTests.GenerateResource_Tests.InProc
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenerateResourceWarnsWhenUsingBinaryFormatter()
|
||||
{
|
||||
using TestEnvironment env = TestEnvironment.Create();
|
||||
TransientTestFile resource = env.CreateFile(".resx", @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<root>
|
||||
<data name=""$this.Icon"" type=""System.Drawing.Icon, System.Drawing"" mimetype=""application/x-microsoft.net.object.binary.base64"">
|
||||
<value>
|
||||
AAABAAEAEBAAAAAAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAA
|
||||
AAD///8BoqKiDaKiotmioqL5oqKiK////wH///8B////Af///wH///8B////AaKioiGioqLxoqKi5aKi
|
||||
ohn///8B////AbS0tBW0tLTz29vb/7Ozsu18Wi+Be1gswXtYLO17WCzte1gswXtYLIGzs7Lz2dnZ/7S0
|
||||
tPu0tLQj////Af///wH///8BxsbGQdPT0//Cv739nGs7/6ZsNf+ubzf/rm83/6ZsNf+hdkr/xcTD/8bG
|
||||
xf/GxsY/////Af///wH///8B////AYxlNmejiGn1r3hE/7uMXv/Ck3H/xJF0/8OPcf+/kGz/uIpd/7SG
|
||||
Wf+hhWT1jGU2Z////wH///8B////AZZtOzWWbTvVs31G/8KZcf/Yqon/79/P//r28//69fP/79/R/9en
|
||||
hf++lGz/s31G/5ZtO9WWbTs1////Af///wGhdUGBsIBK/8abb//Zqoj///7r///67v///fL///7y///8
|
||||
7////ev/2aN6/8KZbP+wgEr/oXVBgf///wH///8BrH5Iwb+PWP/No4H/8NvB///35v/68uP/xcC2//Ht
|
||||
3v///Oj///Xf/+/Ur//ImXL/v49Y/6x+SMH///8B////AbeHTu3JnGb/z5+A//rz4v/99un/8vDj/42M
|
||||
hP+Bf3f/0s/C///76//67Mz/x5Bt/8mcZv+3h07t////Af///wHCkFTtzqZx/9Glif/69un//fju////
|
||||
+f+BgHn/sa6k/4F/d//Jxrr/+vDT/8mWcv/OpnH/wpBU7f///wH///8BzZlbwdOsdf/Zt5j/8ePW//77
|
||||
9f/19fP/n56V//Dw6f/4+PL/vrmt//Dawv/Sqof/06x1/82ZW8H///8B////AbOddIvTrXf/38Sa/969
|
||||
qv//////8PDu/+fl2v////f////3///+8//ctJj/28CW/8Kqfv/Gn2qF////AQCZ3T0KmtjZLpzF9d6/
|
||||
iv/iyaf/37+u//Hj3P/z8ez/9PHr//Hi2f/cuqP/38Oe/4yxqf84ptH5DprWzwCZ3ScAoON9fNHy7WHD
|
||||
6O86pMb74seS/+bRqf/gwqb/1a6W/9Wrkv/evaD/5M+m/7/Bnv9Hstf9q+P2/Smw6NkAoOMnAKfpe13J
|
||||
8eW16Pn/Ycfr7zqqzPPsxIj/6cuU/+fQnf/n0J3/6cuU/97Cjv8yqtD1gdPw9XPQ8+sAp+nNAKfpBQCu
|
||||
7wUAru+LW8v05b/s+v9cy/HpTbLJxfq8dMH6vHTt+rx07fq8dMFRssjDac/y7XzW9u0Aru/JAK7vHf//
|
||||
/wH///8BALX0AwC19IEAtfTRALX0ywC19Af///8B////Af///wH///8BALX0FwC19NEAtfTJALX0J///
|
||||
/wH///8BAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA
|
||||
//8AAP//AAD//w==
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
");
|
||||
|
||||
GenerateResource gr = Utilities.CreateTask(_output, usePreserialized: true, env: env);
|
||||
gr.Sources = new ITaskItem[] { new TaskItem(resource.Path) };
|
||||
gr.WarnOnBinaryFormatterUse = true;
|
||||
|
||||
gr.Execute().ShouldBeTrue();
|
||||
|
||||
Utilities.AssertLogContainsResource(gr, "GenerateResource.BinaryFormatterUse", "$this.Icon", "System.Drawing.Icon, System.Drawing");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cause failures in ResourceReader
|
||||
/// </summary>
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Microsoft.Build.Tasks.UnitTests.GenerateResource
|
|||
@"<data name=""StringResource"" xml:space=""preserve"">
|
||||
<value>StringValue</value>
|
||||
<comment>Comment</comment>
|
||||
</data>"));
|
||||
</data>"), null, false);
|
||||
|
||||
AssertSingleStringResource(resxWithSingleString, "StringResource", "StringValue");
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ namespace Microsoft.Build.Tasks.UnitTests.GenerateResource
|
|||
@"<data name=""StringResource"">
|
||||
<value> StringValue </value>
|
||||
<comment>Comment</comment>
|
||||
</data>"));
|
||||
</data>"), null, false);
|
||||
|
||||
AssertSingleStringResource(resxWithSingleString, "StringResource", " StringValue ");
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ namespace Microsoft.Build.Tasks.UnitTests.GenerateResource
|
|||
@"<data name=""StringResource"" xml:space=""preserve"">
|
||||
<value> </value>
|
||||
<comment>Comment</comment>
|
||||
</data>"));
|
||||
</data>"), null, false);
|
||||
|
||||
AssertSingleStringResource(resxWithSingleString, "StringResource", " ");
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ namespace Microsoft.Build.Tasks.UnitTests.GenerateResource
|
|||
@"<data name=""StringResource"">
|
||||
<value> </value>
|
||||
<comment>Comment</comment>
|
||||
</data>"));
|
||||
</data>"), null, false);
|
||||
|
||||
AssertSingleStringResource(resxWithSingleString, "StringResource", "");
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ namespace Microsoft.Build.Tasks.UnitTests.GenerateResource
|
|||
ResXHelper.SurroundWithBoilerplate(
|
||||
@"<data name=""StringResource"" type=""System.String"">
|
||||
<value>StringValue</value>
|
||||
</data>"));
|
||||
</data>"), null, false);
|
||||
|
||||
AssertSingleStringResource(resxWithSingleString, "StringResource", "StringValue");
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ namespace Microsoft.Build.Tasks.UnitTests.GenerateResource
|
|||
</data>
|
||||
<data name=""2StringResource2"" xml:space=""preserve"">
|
||||
<value>2StringValue2</value>
|
||||
</data>"));
|
||||
</data>"), null, false);
|
||||
|
||||
resxWithTwoStrings.Count.ShouldBe(2);
|
||||
|
||||
|
@ -121,7 +121,7 @@ namespace Microsoft.Build.Tasks.UnitTests.GenerateResource
|
|||
@" <assembly alias=""System.Windows.Forms"" name=""System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"" />
|
||||
<data name=""$this.AccessibleDescription"" type=""System.Resources.ResXNullRef, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"">
|
||||
<value />
|
||||
</data>"));
|
||||
</data>"), null, false);
|
||||
|
||||
resxWithNullRef.ShouldHaveSingleItem();
|
||||
|
||||
|
@ -143,7 +143,7 @@ namespace Microsoft.Build.Tasks.UnitTests.GenerateResource
|
|||
$@" <assembly alias=""System.Windows.Forms"" name=""System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"" />
|
||||
<data name=""TextFile1"" type=""System.Resources.ResXFileRef, System.Windows.Forms"">
|
||||
<value>ResourceHandling\TextFile1.txt;{stringType};utf-8</value>
|
||||
</data>"));
|
||||
</data>"), null, false);
|
||||
|
||||
AssertSingleStringResource(resxWithLinkedString, "TextFile1", "Contents of TextFile1");
|
||||
}
|
||||
|
@ -174,6 +174,8 @@ $@" <assembly alias=""System.Windows.Forms"" name=""System.Windows.Forms, Versi
|
|||
<data name=""TextFile1"" type=""System.Resources.ResXFileRef, System.Windows.Forms"">
|
||||
<value>ResourceHandling\TextFileInShiftJIS.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;shift_jis</value>
|
||||
</data>"),
|
||||
null,
|
||||
false,
|
||||
Path.Combine(baseDir.Path, nameof(LoadsStringFromFileRefAsStringWithShiftJISEncoding) + ".resx"),
|
||||
useRelativePath: true);
|
||||
|
||||
|
@ -210,7 +212,7 @@ $@" <assembly alias=""System.Windows.Forms"" name=""System.Windows.Forms, Versi
|
|||
b7eblRw4yy8Ta2GCpaZp1sIzz2LfCMS+EYh9401iw/gG1gYfvzjQIXcAAAAASUVORK5CYII=
|
||||
</value>
|
||||
</data>
|
||||
"));
|
||||
"), null, false);
|
||||
resxWithEmbeddedBitmap.ShouldHaveSingleItem();
|
||||
resxWithEmbeddedBitmap[0].ShouldBeOfType(typeof(TypeConverterByteArrayResource));
|
||||
|
||||
|
@ -228,7 +230,7 @@ $@" <assembly alias=""System.Windows.Forms"" name=""System.Windows.Forms, Versi
|
|||
<data name=""color"" type=""System.Drawing.Color, System.Drawing"">
|
||||
<value>Blue</value>
|
||||
</data>
|
||||
"));
|
||||
"), null, false);
|
||||
resxWithEmbeddedBitmap.ShouldHaveSingleItem();
|
||||
resxWithEmbeddedBitmap[0].ShouldBeOfType(typeof(TypeConverterStringResource));
|
||||
|
||||
|
@ -252,7 +254,7 @@ $@" <assembly alias=""System.Windows.Forms"" name=""System.Windows.Forms, Versi
|
|||
ResXHelper.SurroundWithBoilerplate(
|
||||
@" <assembly alias=""System.Drawing"" name=""System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"" />
|
||||
<data name=""Color1"" type=""System.Drawing.Color, System.Drawing"">Blue</data>
|
||||
"));
|
||||
"), null, false);
|
||||
resxWithEmbeddedBitmap.ShouldHaveSingleItem();
|
||||
resxWithEmbeddedBitmap[0].ShouldBeOfType(typeof(TypeConverterStringResource));
|
||||
|
||||
|
@ -272,7 +274,7 @@ $@" <assembly alias=""System.Windows.Forms"" name=""System.Windows.Forms, Versi
|
|||
$@" <data name='Image1' type='System.Resources.ResXFileRef, System.Windows.Forms'>
|
||||
<value>{bitmapPath};System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
"));
|
||||
"), null, false);
|
||||
resxWithLinkedBitmap.ShouldHaveSingleItem();
|
||||
resxWithLinkedBitmap[0].ShouldBeOfType(typeof(FileStreamResource));
|
||||
|
||||
|
@ -301,7 +303,7 @@ $@" <data name='Image1' type='System.Resources.ResXFileRef, System.Windows.Form
|
|||
$@" <data name='Image1' type='System.Resources.ResXFileRef, System.Windows.Forms'>
|
||||
<value>{linkedTextFile.Path};{typeNameInResx}</value>
|
||||
</data>
|
||||
"));
|
||||
"), null, false);
|
||||
|
||||
var resource = resources.ShouldHaveSingleItem()
|
||||
.ShouldBeOfType<LiveObjectResource>();
|
||||
|
@ -321,7 +323,7 @@ $@" <data name='Image1' type='System.Resources.ResXFileRef, System.Windows.Form
|
|||
ResXHelper.SurroundWithBoilerplate(
|
||||
@" <assembly name=""System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"" />
|
||||
<data name=""Color1"" type=""System.Drawing.Color, System.Drawing""><value>Blue</value></data>
|
||||
"));
|
||||
"), null, false);
|
||||
resxWithEmbeddedBitmap.ShouldHaveSingleItem();
|
||||
resxWithEmbeddedBitmap[0].ShouldBeOfType(typeof(TypeConverterStringResource));
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Microsoft.Build.UnitTests
|
|||
cache.IsDirty.ShouldBeFalse();
|
||||
|
||||
// Getting a file that wasn't in the cache is a write operation.
|
||||
cache.GetResXFileInfo(resx, useMSBuildResXReader);
|
||||
cache.GetResXFileInfo(resx, useMSBuildResXReader, null, false);
|
||||
cache.IsDirty.ShouldBeTrue();
|
||||
|
||||
// Add linkedFiles to further test serialization and deserialization.
|
||||
|
@ -72,7 +72,7 @@ namespace Microsoft.Build.UnitTests
|
|||
resX2.linkedFiles[1].ShouldBe(resX.linkedFiles[1]);
|
||||
|
||||
// Asking for a file that's in the cache should not dirty the cache.
|
||||
cache2.GetResXFileInfo(resx, useMSBuildResXReader);
|
||||
cache2.GetResXFileInfo(resx, useMSBuildResXReader, null, false);
|
||||
cache2.IsDirty.ShouldBeFalse();
|
||||
|
||||
// Changing UseSourcePath to false should dirty the cache.
|
||||
|
|
|
@ -154,6 +154,28 @@ namespace Microsoft.Build.Tasks.UnitTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RedundantParametersAreLogged()
|
||||
{
|
||||
using TestEnvironment testEnv = TestEnvironment.Create(_output);
|
||||
|
||||
MockEngine engine = new(_output);
|
||||
|
||||
string file = testEnv.ExpectFile().Path;
|
||||
|
||||
WriteLinesToFile task = new()
|
||||
{
|
||||
BuildEngine = engine,
|
||||
File = new TaskItem(file),
|
||||
Lines = new ITaskItem[] { new TaskItem($"{nameof(RedundantParametersAreLogged)} Test") },
|
||||
WriteOnlyWhenDifferent = true,
|
||||
Overwrite = false,
|
||||
};
|
||||
|
||||
task.Execute().ShouldBeTrue();
|
||||
engine.AssertLogContainsMessageFromResource(AssemblyResources.GetString, "WriteLinesToFile.UnusedWriteOnlyWhenDifferent", file);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should create directory structure when target <see cref="WriteLinesToFile.File"/> does not exist.
|
||||
/// </summary>
|
||||
|
|
|
@ -152,7 +152,6 @@ namespace Microsoft.Build.Tasks
|
|||
private const string attrFullConfiguration = "FullConfiguration";
|
||||
private const string buildReferenceMetadataName = "BuildReference";
|
||||
private const string referenceOutputAssemblyMetadataName = "ReferenceOutputAssembly";
|
||||
private const string buildProjectInSolutionAttribute = "BuildProjectInSolution";
|
||||
private const string attrConfiguration = "Configuration";
|
||||
private const string attrPlatform = "Platform";
|
||||
private const string attrSetConfiguration = "SetConfiguration";
|
||||
|
@ -337,7 +336,7 @@ namespace Microsoft.Build.Tasks
|
|||
if (projectConfigurationElement != null && resolvedProjectWithConfiguration != null && onlyReferenceAndBuildProjectsEnabledInSolutionConfiguration)
|
||||
{
|
||||
// The value of the specified attribute. An empty string is returned if a matching attribute is not found or if the attribute does not have a specified or default value.
|
||||
string buildProjectInSolution = projectConfigurationElement.GetAttribute(buildProjectInSolutionAttribute);
|
||||
string buildProjectInSolution = projectConfigurationElement.GetAttribute(SolutionConfiguration.BuildProjectInSolutionAttribute);
|
||||
|
||||
// We could not parse out what was in the attribute, act as if it was not set in the first place.
|
||||
if (bool.TryParse(buildProjectInSolution, out bool buildProject))
|
||||
|
|
|
@ -122,9 +122,9 @@ namespace Microsoft.Build.Tasks
|
|||
}
|
||||
else
|
||||
{
|
||||
if (WriteOnlyWhenDifferent && ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_6))
|
||||
if (WriteOnlyWhenDifferent)
|
||||
{
|
||||
Log.LogWarningWithCodeFromResources("WriteLinesToFile.UnusedWriteOnlyWhenDifferent", File.ItemSpec);
|
||||
Log.LogMessageFromResources(MessageImportance.Normal, "WriteLinesToFile.UnusedWriteOnlyWhenDifferent", File.ItemSpec);
|
||||
}
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
System.IO.File.AppendAllText(File.ItemSpec, buffer.ToString(), encoding);
|
||||
|
|
|
@ -274,6 +274,12 @@ namespace Microsoft.Build.Tasks
|
|||
}
|
||||
}
|
||||
|
||||
// Indicates whether any BinaryFormatter use should lead to a warning.
|
||||
public bool WarnOnBinaryFormatterUse
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the namespace to use for the generated class source for the
|
||||
/// strongly typed resource. If left blank, no namespace is used.
|
||||
|
@ -808,7 +814,8 @@ namespace Microsoft.Build.Tasks
|
|||
StronglyTypedClassName,
|
||||
PublicClass,
|
||||
ExtractResWFiles,
|
||||
OutputDirectory);
|
||||
OutputDirectory,
|
||||
WarnOnBinaryFormatterUse);
|
||||
|
||||
this.StronglyTypedClassName = process.StronglyTypedClassName; // in case a default was chosen
|
||||
this.StronglyTypedFileName = process.StronglyTypedFilename; // in case a default was chosen
|
||||
|
@ -1510,7 +1517,7 @@ namespace Microsoft.Build.Tasks
|
|||
ResGenDependencies.ResXFile resxFileInfo;
|
||||
try
|
||||
{
|
||||
resxFileInfo = _cache.GetResXFileInfo(sourceFilePath, UsePreserializedResources);
|
||||
resxFileInfo = _cache.GetResXFileInfo(sourceFilePath, UsePreserializedResources, Log, WarnOnBinaryFormatterUse);
|
||||
}
|
||||
catch (Exception e) when (!ExceptionHandling.NotExpectedIoOrXmlException(e) || e is MSBuildResXException)
|
||||
{
|
||||
|
@ -1971,7 +1978,7 @@ namespace Microsoft.Build.Tasks
|
|||
{
|
||||
byte[] serializedData = ByteArrayFromBase64WrappedString(data);
|
||||
|
||||
BinaryFormatter binaryFormatter = new BinaryFormatter();
|
||||
BinaryFormatter binaryFormatter = new();
|
||||
|
||||
using (MemoryStream memoryStream = new MemoryStream(serializedData))
|
||||
{
|
||||
|
@ -2337,6 +2344,8 @@ namespace Microsoft.Build.Tasks
|
|||
/// </summary>
|
||||
private bool _useSourcePath = false;
|
||||
|
||||
private bool _logWarningForBinaryFormatter = false;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
|
@ -2357,7 +2366,8 @@ namespace Microsoft.Build.Tasks
|
|||
string classname,
|
||||
bool publicClass,
|
||||
bool extractingResWFiles,
|
||||
string resWOutputDirectory)
|
||||
string resWOutputDirectory,
|
||||
bool logWarningForBinaryFormatter)
|
||||
{
|
||||
_logger = log;
|
||||
_assemblyFiles = assemblyFilesList;
|
||||
|
@ -2376,6 +2386,7 @@ namespace Microsoft.Build.Tasks
|
|||
_resWOutputDirectory = resWOutputDirectory;
|
||||
_portableLibraryCacheInfo = new List<ResGenDependencies.PortableLibraryFile>();
|
||||
_usePreserializedResources = usePreserializedResources;
|
||||
_logWarningForBinaryFormatter = logWarningForBinaryFormatter;
|
||||
|
||||
#if !FEATURE_ASSEMBLYLOADCONTEXT
|
||||
// If references were passed in, we will have to give the ResxResourceReader an object
|
||||
|
@ -2980,7 +2991,7 @@ namespace Microsoft.Build.Tasks
|
|||
}
|
||||
else
|
||||
{
|
||||
foreach (IResource resource in MSBuildResXReader.GetResourcesFromFile(filename, shouldUseSourcePath))
|
||||
foreach (IResource resource in MSBuildResXReader.GetResourcesFromFile(filename, shouldUseSourcePath, _logger, _logWarningForBinaryFormatter))
|
||||
{
|
||||
AddResource(reader, resource, filename, 0, 0);
|
||||
}
|
||||
|
|
|
@ -59,8 +59,9 @@ namespace Microsoft.Build.Tasks
|
|||
string referencedProjectPlatform = AssignedProjectsWithPlatform[i].GetMetadata("Platform");
|
||||
string projectReferencePlatformsMetadata = AssignedProjectsWithPlatform[i].GetMetadata("Platforms");
|
||||
string projectReferenceLookupTableMetadata = AssignedProjectsWithPlatform[i].GetMetadata("PlatformLookupTable");
|
||||
string projectReferenceOverridePlatformNegotiationMetadata = AssignedProjectsWithPlatform[i].GetMetadata("OverridePlatformNegotiationValue");
|
||||
|
||||
string? buildProjectReferenceAs = PlatformNegotiation.GetNearestPlatform(referencedProjectPlatform, projectReferencePlatformsMetadata, projectReferenceLookupTableMetadata, PlatformLookupTable, AssignedProjectsWithPlatform[i].ItemSpec, CurrentProjectPlatform, Log);
|
||||
string? buildProjectReferenceAs = PlatformNegotiation.GetNearestPlatform(projectReferenceOverridePlatformNegotiationMetadata, referencedProjectPlatform, projectReferencePlatformsMetadata, projectReferenceLookupTableMetadata, PlatformLookupTable, AssignedProjectsWithPlatform[i].ItemSpec, CurrentProjectPlatform, Log);
|
||||
|
||||
AssignedProjectsWithPlatform[i].SetMetadata("NearestPlatform", buildProjectReferenceAs);
|
||||
Log.LogMessageFromResources(MessageImportance.Low, "GetCompatiblePlatform.DisplayChosenPlatform", AssignedProjectsWithPlatform[i].ItemSpec, buildProjectReferenceAs);
|
||||
|
|
|
@ -102,6 +102,9 @@
|
|||
<Compile Include="..\Shared\StrongNameHelpers.cs">
|
||||
<Link>StrongNameHelpers.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\SolutionConfiguration.cs">
|
||||
<Link>SolutionConfiguration.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\TaskLoggingHelperExtension.cs">
|
||||
<Link>TaskLoggingHelperExtension.cs</Link>
|
||||
<ExcludeFromStyleCop>True</ExcludeFromStyleCop>
|
||||
|
|
|
@ -1631,11 +1631,11 @@ Copyright (C) Microsoft Corporation. All rights reserved.
|
|||
<UseDefaultPlatformLookupTables Condition="'$(UseDefaultPlatformLookupTables)' == ''">true</UseDefaultPlatformLookupTables>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- This target skips VS builds because they already supply Platform and
|
||||
Configuration information. -->
|
||||
<!-- This target skips sln-based builds because they already supply Platform and
|
||||
Configuration information. See AssignProjectConfiguration -->
|
||||
<Target Name="_GetProjectReferencePlatformProperties"
|
||||
Condition="'$(EnableDynamicPlatformResolution)' == 'true'
|
||||
and '$(BuildingInsideVisualStudio)' != 'true'
|
||||
and '$(CurrentSolutionConfigurationContents)' == ''
|
||||
and '@(_MSBuildProjectReferenceExistent)' != ''">
|
||||
|
||||
<!-- Allow preset SetPlatform to override this operation -->
|
||||
|
@ -2464,7 +2464,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
|
|||
====================================================================================================
|
||||
-->
|
||||
<Target Name="GenerateBindingRedirects"
|
||||
Inputs="$(MSBuildAllProjects);@(AppConfigFile);$(ResolveAssemblyReferencesStateFile);$(SuggestedBindingRedirectsCacheFile)"
|
||||
Inputs="$(MSBuildAllProjects);@(AppConfigWithTargetPath);$(ResolveAssemblyReferencesStateFile);$(SuggestedBindingRedirectsCacheFile)"
|
||||
Outputs="$(_GenerateBindingRedirectsIntermediateAppConfig)"
|
||||
Condition="'$(AutoGenerateBindingRedirects)' == 'true' and '$(GenerateBindingRedirectsOutputType)' == 'true'"
|
||||
DependsOnTargets="_GenerateSuggestedBindingRedirectsCache">
|
||||
|
@ -3328,8 +3328,10 @@ Copyright (C) Microsoft Corporation. All rights reserved.
|
|||
SdkToolsPath="$(ResgenToolPath)"
|
||||
ExecuteAsTool="$(ResGenExecuteAsTool)"
|
||||
EnvironmentVariables="$(ResGenEnvironment)"
|
||||
WarnOnBinaryFormatterUse="$(GenerateResourceWarnOnBinaryFormatterUse)"
|
||||
MSBuildRuntime="$(GenerateResourceMSBuildRuntime)"
|
||||
MSBuildArchitecture="$(GenerateResourceMSBuildArchitecture)">
|
||||
MSBuildArchitecture="$(GenerateResourceMSBuildArchitecture)"
|
||||
>
|
||||
|
||||
<Output TaskParameter="FilesWritten" ItemName="FileWrites"/>
|
||||
<Output TaskParameter="StronglyTypedFileName" ItemName="Compile"/>
|
||||
|
|
|
@ -125,13 +125,13 @@ namespace Microsoft.Build.Tasks
|
|||
translator.Translate(ref baseLinkedFileDirectory);
|
||||
}
|
||||
|
||||
internal ResXFile GetResXFileInfo(string resxFile, bool useMSBuildResXReader)
|
||||
internal ResXFile GetResXFileInfo(string resxFile, bool useMSBuildResXReader, TaskLoggingHelper log, bool logWarningForBinaryFormatter)
|
||||
{
|
||||
// First, try to retrieve the resx information from our hashtable.
|
||||
if (!resXFiles.TryGetValue(resxFile, out ResXFile retVal))
|
||||
{
|
||||
// Ok, the file wasn't there. Add it to our cache and return it to the caller.
|
||||
retVal = AddResxFile(resxFile, useMSBuildResXReader);
|
||||
retVal = AddResxFile(resxFile, useMSBuildResXReader, log, logWarningForBinaryFormatter);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -141,19 +141,19 @@ namespace Microsoft.Build.Tasks
|
|||
{
|
||||
resXFiles.Remove(resxFile);
|
||||
_isDirty = true;
|
||||
retVal = AddResxFile(resxFile, useMSBuildResXReader);
|
||||
retVal = AddResxFile(resxFile, useMSBuildResXReader, log, logWarningForBinaryFormatter);
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private ResXFile AddResxFile(string file, bool useMSBuildResXReader)
|
||||
private ResXFile AddResxFile(string file, bool useMSBuildResXReader, TaskLoggingHelper log, bool logWarningForBinaryFormatter)
|
||||
{
|
||||
// This method adds a .resx file "file" to our .resx cache. The method causes the file
|
||||
// to be cracked for contained files.
|
||||
|
||||
var resxFile = new ResXFile(file, BaseLinkedFileDirectory, useMSBuildResXReader);
|
||||
var resxFile = new ResXFile(file, BaseLinkedFileDirectory, useMSBuildResXReader, log, logWarningForBinaryFormatter);
|
||||
resXFiles.Add(file, resxFile);
|
||||
_isDirty = true;
|
||||
return resxFile;
|
||||
|
@ -230,7 +230,7 @@ namespace Microsoft.Build.Tasks
|
|||
|
||||
internal string[] LinkedFiles => linkedFiles;
|
||||
|
||||
internal ResXFile(string filename, string baseLinkedFileDirectory, bool useMSBuildResXReader) : base(filename)
|
||||
internal ResXFile(string filename, string baseLinkedFileDirectory, bool useMSBuildResXReader, TaskLoggingHelper log, bool logWarningForBinaryFormatter) : base(filename)
|
||||
{
|
||||
// Creates a new ResXFile object and populates the class member variables
|
||||
// by computing a list of linked files within the .resx that was passed in.
|
||||
|
@ -239,7 +239,7 @@ namespace Microsoft.Build.Tasks
|
|||
|
||||
if (FileSystems.Default.FileExists(FileName))
|
||||
{
|
||||
linkedFiles = GetLinkedFiles(filename, baseLinkedFileDirectory, useMSBuildResXReader);
|
||||
linkedFiles = GetLinkedFiles(filename, baseLinkedFileDirectory, useMSBuildResXReader, log, logWarningForBinaryFormatter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,7 +260,7 @@ namespace Microsoft.Build.Tasks
|
|||
/// </summary>
|
||||
/// <exception cref="ArgumentException">May be thrown if Resx is invalid. May contain XmlException.</exception>
|
||||
/// <exception cref="XmlException">May be thrown if Resx is invalid</exception>
|
||||
private static string[] GetLinkedFiles(string filename, string baseLinkedFileDirectory, bool useMSBuildResXReader)
|
||||
private static string[] GetLinkedFiles(string filename, string baseLinkedFileDirectory, bool useMSBuildResXReader, TaskLoggingHelper log, bool logWarningForBinaryFormatter)
|
||||
{
|
||||
// This method finds all linked .resx files for the .resx file that is passed in.
|
||||
// filename is the filename of the .resx file that is to be examined.
|
||||
|
@ -270,7 +270,7 @@ namespace Microsoft.Build.Tasks
|
|||
|
||||
if (useMSBuildResXReader)
|
||||
{
|
||||
foreach (IResource resource in MSBuildResXReader.GetResourcesFromFile(filename, pathsRelativeToBasePath: baseLinkedFileDirectory == null))
|
||||
foreach (IResource resource in MSBuildResXReader.GetResourcesFromFile(filename, pathsRelativeToBasePath: baseLinkedFileDirectory == null, log, logWarningForBinaryFormatter))
|
||||
{
|
||||
if (resource is FileStreamResource linkedResource)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
|
@ -42,25 +41,10 @@ namespace Microsoft.Build.Tasks
|
|||
// This field stores all the distinct project references by project absolute path
|
||||
private readonly HashSet<string> _cachedProjectReferencesByAbsolutePath = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// This field stores pre-cached project elements for project guids for quicker access by project guid
|
||||
private readonly Dictionary<string, XmlElement> _cachedProjectElements = new Dictionary<string, XmlElement>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// This field stores pre-cached project elements for project guids for quicker access by project absolute path
|
||||
private readonly Dictionary<string, XmlElement> _cachedProjectElementsByAbsolutePath = new Dictionary<string, XmlElement>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// This field stores the project absolute path for quicker access by project guid
|
||||
private readonly Dictionary<string, string> _cachedProjectAbsolutePathsByGuid = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// This field stores the project guid for quicker access by project absolute path
|
||||
private readonly Dictionary<string, string> _cachedProjectGuidsByAbsolutePath = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// This field stores the list of dependency project guids by depending project guid
|
||||
private readonly Dictionary<string, List<string>> _cachedDependencyProjectGuidsByDependingProjectGuid = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
|
||||
private SolutionConfiguration _solutionConfiguration = SolutionConfiguration.Empty;
|
||||
|
||||
private const string attributeProject = "Project";
|
||||
|
||||
private const string attributeAbsolutePath = "AbsolutePath";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
@ -121,86 +105,7 @@ namespace Microsoft.Build.Tasks
|
|||
/// <summary>
|
||||
/// Pre-cache individual project elements from the XML string in a hashtable for quicker access.
|
||||
/// </summary>
|
||||
internal void CacheProjectElementsFromXml(string xmlString)
|
||||
{
|
||||
// TODO: fix code clone for parsing CurrentSolutionConfiguration xml: https://github.com/dotnet/msbuild/issues/6751
|
||||
XmlDocument doc = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(xmlString))
|
||||
{
|
||||
doc = new XmlDocument();
|
||||
var settings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore };
|
||||
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString), settings))
|
||||
{
|
||||
doc.Load(reader);
|
||||
}
|
||||
}
|
||||
|
||||
// Example:
|
||||
//
|
||||
// <SolutionConfiguration>
|
||||
// <ProjectConfiguration Project="{786E302A-96CE-43DC-B640-D6B6CC9BF6C0}" AbsolutePath="c:foo\Project1\A.csproj" BuildProjectInSolution="True">Debug|AnyCPU</ProjectConfiguration>
|
||||
// <ProjectConfiguration Project="{881C1674-4ECA-451D-85B6-D7C59B7F16FA}" AbsolutePath="c:foo\Project2\B.csproj" BuildProjectInSolution="True">Debug|AnyCPU<ProjectDependency Project="{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}" /></ProjectConfiguration>
|
||||
// <ProjectConfiguration Project="{4A727FF8-65F2-401E-95AD-7C8BBFBE3167}" AbsolutePath="c:foo\Project3\C.csproj" BuildProjectInSolution="True">Debug|AnyCPU</ProjectConfiguration>
|
||||
// </SolutionConfiguration>
|
||||
//
|
||||
if (doc?.DocumentElement != null)
|
||||
{
|
||||
foreach (XmlElement xmlElement in doc.DocumentElement.ChildNodes)
|
||||
{
|
||||
string projectGuid = xmlElement.GetAttribute(attributeProject);
|
||||
string projectAbsolutePath = xmlElement.GetAttribute(attributeAbsolutePath);
|
||||
|
||||
// What we really want here is the normalized path, like we'd get with an item's "FullPath" metadata. However,
|
||||
// if there's some bogus full path in the solution configuration (e.g. a website with a "full path" of c:\solutiondirectory\http://localhost)
|
||||
// we do NOT want to throw -- chances are extremely high that that's information that will never actually be used. So resolve the full path
|
||||
// but just swallow any IO-related exceptions that result. If the path is bogus, the method will return null, so we'll just quietly fail
|
||||
// to cache it below.
|
||||
projectAbsolutePath = FileUtilities.GetFullPathNoThrow(projectAbsolutePath);
|
||||
|
||||
if (!string.IsNullOrEmpty(projectGuid))
|
||||
{
|
||||
_cachedProjectElements[projectGuid] = xmlElement;
|
||||
if (!string.IsNullOrEmpty(projectAbsolutePath))
|
||||
{
|
||||
_cachedProjectElementsByAbsolutePath[projectAbsolutePath] = xmlElement;
|
||||
_cachedProjectAbsolutePathsByGuid[projectGuid] = projectAbsolutePath;
|
||||
_cachedProjectGuidsByAbsolutePath[projectAbsolutePath] = projectGuid;
|
||||
}
|
||||
|
||||
foreach (XmlNode dependencyNode in xmlElement.ChildNodes)
|
||||
{
|
||||
if (dependencyNode.NodeType != XmlNodeType.Element)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
XmlElement dependencyElement = ((XmlElement)dependencyNode);
|
||||
|
||||
if (!String.Equals(dependencyElement.Name, "ProjectDependency", StringComparison.Ordinal))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string dependencyGuid = dependencyElement.GetAttribute("Project");
|
||||
|
||||
if (dependencyGuid.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_cachedDependencyProjectGuidsByDependingProjectGuid.TryGetValue(projectGuid, out List<string> list))
|
||||
{
|
||||
list = new List<string>();
|
||||
_cachedDependencyProjectGuidsByDependingProjectGuid.Add(projectGuid, list);
|
||||
}
|
||||
|
||||
list.Add(dependencyGuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
internal void CacheProjectElementsFromXml(string xmlString) => _solutionConfiguration = new SolutionConfiguration(xmlString);
|
||||
|
||||
/// <summary>
|
||||
/// Helper method for retrieving whatever was stored in the XML string for the given project
|
||||
|
@ -219,7 +124,7 @@ namespace Microsoft.Build.Tasks
|
|||
{
|
||||
string projectGuid = projectRef.GetMetadata(attributeProject);
|
||||
|
||||
if ((_cachedProjectElements.TryGetValue(projectGuid, out XmlElement projectElement)) && (projectElement != null))
|
||||
if (_solutionConfiguration.TryGetProjectByGuid(projectGuid, out XmlElement projectElement))
|
||||
{
|
||||
return projectElement;
|
||||
}
|
||||
|
@ -228,7 +133,7 @@ namespace Microsoft.Build.Tasks
|
|||
// next we'll try a lookup by the absolute path of the project
|
||||
string projectFullPath = projectRef.GetMetadata("FullPath"); // reserved metadata "FullPath" is used at it will cache the value
|
||||
|
||||
if ((_cachedProjectElementsByAbsolutePath.TryGetValue(projectFullPath, out projectElement)) && (projectElement != null))
|
||||
if (_solutionConfiguration.TryGetProjectByAbsolutePath(projectFullPath, out projectElement))
|
||||
{
|
||||
return projectElement;
|
||||
}
|
||||
|
@ -243,14 +148,14 @@ namespace Microsoft.Build.Tasks
|
|||
protected void AddSyntheticProjectReferences(string currentProjectAbsolutePath)
|
||||
{
|
||||
// Get the guid for this project
|
||||
if (!_cachedProjectGuidsByAbsolutePath.TryGetValue(currentProjectAbsolutePath, out string projectGuid))
|
||||
if (!_solutionConfiguration.TryGetProjectGuidByAbsolutePath(currentProjectAbsolutePath, out string projectGuid))
|
||||
{
|
||||
// We were passed a blob, but we weren't listed in it. Odd. Return.
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the guid to look up the dependencies for it
|
||||
if (!_cachedDependencyProjectGuidsByDependingProjectGuid.TryGetValue(projectGuid, out List<string> guids))
|
||||
if (!_solutionConfiguration.TryGetProjectDependencies(projectGuid, out List<string> guids))
|
||||
{
|
||||
// We didn't have dependencies listed in the blob
|
||||
return;
|
||||
|
@ -262,7 +167,7 @@ namespace Microsoft.Build.Tasks
|
|||
foreach (string guid in guids)
|
||||
{
|
||||
// Get the absolute path of the dependency, using the blob
|
||||
if (!_cachedProjectAbsolutePathsByGuid.TryGetValue(guid, out string path))
|
||||
if (!_solutionConfiguration.TryGetProjectPathByGuid(guid, out string path))
|
||||
{
|
||||
// We had a dependency listed in the blob that wasn't itself in the blob. Odd. Return.
|
||||
continue;
|
||||
|
|
|
@ -9,6 +9,7 @@ using System.Text;
|
|||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Build.Shared;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
#nullable disable
|
||||
|
||||
|
@ -16,7 +17,7 @@ namespace Microsoft.Build.Tasks.ResourceHandling
|
|||
{
|
||||
internal class MSBuildResXReader
|
||||
{
|
||||
public static IReadOnlyList<IResource> ReadResources(Stream s, string filename, bool pathsRelativeToBasePath)
|
||||
public static IReadOnlyList<IResource> ReadResources(Stream s, string filename, bool pathsRelativeToBasePath, TaskLoggingHelper log, bool logWarningForBinaryFormatter)
|
||||
{
|
||||
var resources = new List<IResource>();
|
||||
var aliases = new Dictionary<string, string>();
|
||||
|
@ -38,7 +39,7 @@ namespace Microsoft.Build.Tasks.ResourceHandling
|
|||
case "resheader":
|
||||
break;
|
||||
case "data":
|
||||
ParseData(filename, pathsRelativeToBasePath, resources, aliases, elem);
|
||||
ParseData(filename, pathsRelativeToBasePath, resources, aliases, elem, log, logWarningForBinaryFormatter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +102,14 @@ namespace Microsoft.Build.Tasks.ResourceHandling
|
|||
return aliasedTypeName;
|
||||
}
|
||||
|
||||
private static void ParseData(string resxFilename, bool pathsRelativeToBasePath, List<IResource> resources, Dictionary<string, string> aliases, XElement elem)
|
||||
private static void ParseData(
|
||||
string resxFilename,
|
||||
bool pathsRelativeToBasePath,
|
||||
List<IResource> resources,
|
||||
Dictionary<string, string> aliases,
|
||||
XElement elem,
|
||||
TaskLoggingHelper log,
|
||||
bool logWarningForBinaryFormatter)
|
||||
{
|
||||
string name = elem.Attribute("name").Value;
|
||||
string value;
|
||||
|
@ -186,6 +194,12 @@ namespace Microsoft.Build.Tasks.ResourceHandling
|
|||
case BinSerializedObjectMimeType:
|
||||
case Beta2CompatSerializedObjectMimeType:
|
||||
case CompatBinSerializedObjectMimeType:
|
||||
// Warn of BinaryFormatter exposure (SDK should turn this on by default in .NET 8+)
|
||||
if (logWarningForBinaryFormatter)
|
||||
{
|
||||
log?.LogWarningWithCodeFromResources(null, resxFilename, ((IXmlLineInfo)elem).LineNumber, ((IXmlLineInfo)elem).LinePosition, 0, 0, "GenerateResource.BinaryFormatterUse", name, typename);
|
||||
}
|
||||
|
||||
// BinaryFormatter from byte array
|
||||
byte[] binaryFormatterBytes = Convert.FromBase64String(value);
|
||||
|
||||
|
@ -284,19 +298,19 @@ namespace Microsoft.Build.Tasks.ResourceHandling
|
|||
/// <summary>
|
||||
/// Extract <see cref="IResource"/>s from a given file on disk.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<IResource> GetResourcesFromFile(string filename, bool pathsRelativeToBasePath)
|
||||
public static IReadOnlyList<IResource> GetResourcesFromFile(string filename, bool pathsRelativeToBasePath, TaskLoggingHelper log, bool logWarningForBinaryFormatter)
|
||||
{
|
||||
using (var x = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
return ReadResources(x, filename, pathsRelativeToBasePath);
|
||||
return ReadResources(x, filename, pathsRelativeToBasePath, log, logWarningForBinaryFormatter);
|
||||
}
|
||||
}
|
||||
|
||||
public static IReadOnlyList<IResource> GetResourcesFromString(string resxContent, string basePath = null, bool? useRelativePath = null)
|
||||
public static IReadOnlyList<IResource> GetResourcesFromString(string resxContent, TaskLoggingHelper log, bool logWarningForBinaryFormatter, string basePath = null, bool? useRelativePath = null)
|
||||
{
|
||||
using (var x = new MemoryStream(Encoding.UTF8.GetBytes(resxContent)))
|
||||
{
|
||||
return ReadResources(x, basePath, useRelativePath.GetValueOrDefault(basePath != null));
|
||||
return ReadResources(x, basePath, useRelativePath.GetValueOrDefault(basePath != null), log, logWarningForBinaryFormatter);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1161,6 +1161,11 @@
|
|||
<value>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</value>
|
||||
<comment>{StrBegin="MSB3824: "}</comment>
|
||||
</data>
|
||||
<data name="GenerateResource.BinaryFormatterUse">
|
||||
<value>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</value>
|
||||
<comment>{StrBegin="MSB3825: "}</comment>
|
||||
</data>
|
||||
|
||||
|
||||
<!--
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: Funkce ClickOnce nepodporuje požadovanou úroveň provedení {0}.</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: Aby bylo možné provést sestavení pomocí .NET Core, musí být vstupy prostředků ve formátu .txt nebo .resx.</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: Die Anforderungsausführungsebene "{0}" wird von ClickOnce nicht unterstützt.</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: Für die Kompilierung mit .NET Core müssen Ressourceneingaben im TXT- oder RESX-Format vorliegen.</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: ClickOnce no admite el nivel de ejecución de solicitudes '{0}'.</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: Para compilar con .NET Core, las entradas de recursos deben estar en formato .txt o .resx.</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: ClickOnce ne prend pas en charge le niveau d'exécution de la requête '{0}'.</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: Pour pouvoir générer avec .NET Core, les entrées de ressource doivent être au format .txt ou .resx.</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: ClickOnce non supporta il livello di esecuzione richieste '{0}'.</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: per compilare con .NET Core, gli input delle risorse devono essere in formato. txt o. resx.</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: ClickOnce では、要求の実行レベル '{0}' はサポートされていません。</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: .NET Core を使用してビルドするには、リソースの入力を .txt 形式または .resx 形式にする必要があります。</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: ClickOnce는 요청 실행 수준 '{0}'을(를) 지원하지 않습니다.</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: .NET Core로 빌드하려면 리소스 입력이 .txt 또는 .resx 형식이어야 합니다.</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: Funkcja ClickOnce nie obsługuje poziomu wykonania żądania „{0}”.</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: Aby kompilować przy użyciu platformy .NET Core, dane wejściowe zasobów muszą być w formacie txt lub resx.</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: O ClickOnce não dá suporte ao nível de execução de solicitação "{0}".</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: Para compilar com o .NET Core, as entradas de recurso devem estar em formato .txt ou .resx.</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: ClickOnce не поддерживает уровень выполнения запроса "{0}".</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: для сборки с использованием .NET Core входные данные ресурсов должны быть в формате TXT или RESX.</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: ClickOnce, '{0}' istek yürütme düzeyini desteklemiyor.</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: .NET Core ile derlemek için kaynak girişleri .txt veya .resx biçiminde olmalıdır.</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: ClickOnce 不支持请求执行级别“{0}”。</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: 要使用 .NET Core 进行生成,资源输入必须为 .txt 或 .resx 格式。</target>
|
||||
|
|
|
@ -1039,6 +1039,13 @@
|
|||
<target state="translated">MSB3190: ClickOnce 不支援要求執行層級 '{0}'。</target>
|
||||
<note>{StrBegin="MSB3190: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.BinaryFormatterUse">
|
||||
<source>MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</source>
|
||||
<target state="new">MSB3825: Resource "{0}" of type "{1}" is deserialized via BinaryFormatter at runtime. BinaryFormatter is deprecated due to possible security risks and will be removed with .NET 9. If you wish to continue using it, set property "GenerateResourceWarnOnBinaryFormatterUse" to false.
|
||||
More information: https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-security-guide</target>
|
||||
<note>{StrBegin="MSB3825: "}</note>
|
||||
</trans-unit>
|
||||
<trans-unit id="GenerateResource.CoreSupportsLimitedScenarios">
|
||||
<source>MSB3824: In order to build with .NET Core, resource inputs must be in .txt or .resx format.</source>
|
||||
<target state="translated">MSB3824: 若要使用 .NET Core 建置,資源輸入必須採用 .txt 或 .resx 格式。</target>
|
||||
|
|
Загрузка…
Ссылка в новой задаче