Merge remote-tracking branch 'dotnet/main' into livelogger

This commit is contained in:
Ladi Prosek 2023-03-31 16:54:20 +02:00
Родитель b0542f37f6 4c9e8aa8a9
Коммит 41390058e7
49 изменённых файлов: 736 добавлений и 237 удалений

27
.github/ISSUE_TEMPLATE/06_feature_request.yml поставляемый Normal file
Просмотреть файл

@ -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.

96
.github/fabricbot.json поставляемый
Просмотреть файл

@ -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>
<!--

7
src/Tasks/Resources/xlf/Strings.cs.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.de.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.es.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.fr.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.it.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.ja.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.ko.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.pl.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.pt-BR.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.ru.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.tr.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.zh-Hans.xlf сгенерированный
Просмотреть файл

@ -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>

7
src/Tasks/Resources/xlf/Strings.zh-Hant.xlf сгенерированный
Просмотреть файл

@ -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>