diff --git a/eng/Packages.props b/eng/Packages.props
index b4e087118a4..1a2171602ba 100644
--- a/eng/Packages.props
+++ b/eng/Packages.props
@@ -13,6 +13,7 @@
+
diff --git a/scripts/Deploy-MSBuild.ps1 b/scripts/Deploy-MSBuild.ps1
index 07b58d1f82d..f97b9ad94f5 100644
--- a/scripts/Deploy-MSBuild.ps1
+++ b/scripts/Deploy-MSBuild.ps1
@@ -98,6 +98,7 @@ if ($runtime -eq "Desktop") {
FileToCopy "$bootstrapBinDirectory\Microsoft.Bcl.AsyncInterfaces.dll"
FileToCopy "$bootstrapBinDirectory\Microsoft.Data.Entity.targets"
+ FileToCopy "$bootstrapBinDirectory\Microsoft.IO.Redist.dll"
FileToCopy "$bootstrapBinDirectory\Microsoft.ServiceModel.targets"
FileToCopy "$bootstrapBinDirectory\Microsoft.WinFx.targets"
FileToCopy "$bootstrapBinDirectory\Microsoft.WorkflowBuildExtensions.targets"
diff --git a/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj b/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj
index 18ad711bac4..378c5127883 100644
--- a/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj
+++ b/src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj
@@ -20,6 +20,8 @@
+
+
diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj
index d08e337c5da..f7540863381 100644
--- a/src/Build/Microsoft.Build.csproj
+++ b/src/Build/Microsoft.Build.csproj
@@ -36,6 +36,8 @@
+
+
diff --git a/src/Directory.BeforeCommon.targets b/src/Directory.BeforeCommon.targets
index 913c97b1281..ce322f9833b 100644
--- a/src/Directory.BeforeCommon.targets
+++ b/src/Directory.BeforeCommon.targets
@@ -142,4 +142,9 @@
$(IntermediateOutputPath)\$(AssemblyName).xml
+
+ $(DefineConstants);FEATURE_MSIOREDIST
+ true
+
+
diff --git a/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj b/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj
index b73c360d59d..4358e5a16a8 100644
--- a/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj
+++ b/src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj
@@ -11,6 +11,7 @@
+
diff --git a/src/MSBuild/MSBuild.csproj b/src/MSBuild/MSBuild.csproj
index 93185ce820a..17594f48d2f 100644
--- a/src/MSBuild/MSBuild.csproj
+++ b/src/MSBuild/MSBuild.csproj
@@ -229,6 +229,7 @@
+
diff --git a/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec b/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec
index 2918e172a5c..04a42dbfce4 100644
--- a/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec
+++ b/src/Package/MSBuild.Engine.Corext/MsBuild.Engine.Corext.nuspec
@@ -31,6 +31,7 @@
+
@@ -87,6 +88,7 @@
+
diff --git a/src/Package/MSBuild.VSSetup/files.swr b/src/Package/MSBuild.VSSetup/files.swr
index 67e5764974d..fc7164e4899 100644
--- a/src/Package/MSBuild.VSSetup/files.swr
+++ b/src/Package/MSBuild.VSSetup/files.swr
@@ -32,6 +32,7 @@ folder InstallDir:\MSBuild\Current\Bin
file source=$(X86BinPath)Microsoft.Build.Framework.tlb
file source=$(X86BinPath)Microsoft.Build.Tasks.Core.dll vs.file.ngenApplications="[installDir]\Common7\IDE\vsn.exe" vs.file.ngenApplications="[installDir]\MSBuild\Current\Bin\MSBuild.exe" vs.file.ngenArchitecture=all vs.file.ngenPriority=1
file source=$(X86BinPath)Microsoft.Build.Utilities.Core.dll vs.file.ngenApplications="[installDir]\Common7\IDE\vsn.exe" vs.file.ngenApplications="[installDir]\MSBuild\Current\Bin\MSBuild.exe" vs.file.ngenArchitecture=all vs.file.ngenPriority=1
+ file source=$(X86BinPath)Microsoft.IO.Redist.dll vs.file.ngenApplications="[installDir]\Common7\IDE\vsn.exe" vs.file.ngenApplications="[installDir]\MSBuild\Current\Bin\MSBuild.exe" vs.file.ngenArchitecture=all vs.file.ngenPriority=1
file source=$(X86BinPath)MSBuild.exe vs.file.ngenArchitecture=x86 vs.file.ngenPriority=1
file source=$(X86BinPath)MSBuild.exe.config
file source=$(TaskHostBinPath)MSBuildTaskHost.exe vs.file.ngenArchitecture=x86
@@ -184,6 +185,7 @@ folder InstallDir:\MSBuild\Current\Bin\amd64
file source=$(X86BinPath)System.Memory.dll vs.file.ngenArchitecture=all
file source=$(X86BinPath)System.Text.Json.dll vs.file.ngenArchitecture=all
file source=$(X86BinPath)Microsoft.Bcl.AsyncInterfaces.dll vs.file.ngenArchitecture=all
+ file source=$(X86BinPath)Microsoft.IO.Redist.dll vs.file.ngenArchitecture=all
file source=$(X86BinPath)System.Text.Encodings.Web.dll vs.file.ngenArchitecture=all
file source=$(X86BinPath)System.Threading.Tasks.Extensions.dll vs.file.ngenArchitecture=all
file source=$(X86BinPath)System.Numerics.Vectors.dll vs.file.ngenArchitecture=all
diff --git a/src/Shared/FileSystem/ManagedFileSystem.cs b/src/Shared/FileSystem/ManagedFileSystem.cs
index 6d8bd32fb4e..d5d80a07e35 100644
--- a/src/Shared/FileSystem/ManagedFileSystem.cs
+++ b/src/Shared/FileSystem/ManagedFileSystem.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using Microsoft.Build.Utilities;
using System;
using System.Collections.Generic;
using System.IO;
@@ -16,6 +17,20 @@ internal class ManagedFileSystem : IFileSystem
public static ManagedFileSystem Singleton() => ManagedFileSystem.Instance;
+ private static bool ShouldUseMicrosoftIO
+ {
+ get
+ {
+#if !MICROSOFT_BUILD_ENGINE_OM_UNITTESTS
+ return ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave17_0);
+#else
+ // We need to mock usage of ChangeWaves class,
+ // because Microsoft.Build.Engine.OM.UnitTests should not have access to internals of Microsoft.Build.Framework.
+ return true;
+#endif
+ }
+ }
+
protected ManagedFileSystem() { }
public TextReader ReadFile(string path)
@@ -38,19 +53,78 @@ public byte[] ReadFileAllBytes(string path)
return File.ReadAllBytes(path);
}
+#if FEATURE_MSIOREDIST
+ private static IEnumerable HandleFileLoadException(
+ Func> enumerateFunctionDelegate,
+ string path,
+ string searchPattern,
+ Microsoft.IO.SearchOption searchOption
+ )
+ {
+ try
+ {
+ return enumerateFunctionDelegate(path, searchPattern, searchOption);
+ }
+ // Microsoft.IO.Redist has a dependency on System.Buffers and if System.Buffers assembly is not found the line above throws an exception.
+ // However, FileMatcher class (that in most cases calls the enumeration) does not allow to fail on a IO-related exception. Such behavior hides the actual exception and makes it obscure.
+ // We rethrow it to make it fail with a proper error message and call stack.
+ catch (FileLoadException ex)
+ {
+ throw new InvalidOperationException(ex.Message, ex);
+ }
+ // Sometimes FileNotFoundException is thrown when there is an assembly load failure. In this case it should have FusionLog.
+ catch (FileNotFoundException ex) when (ex.FusionLog != null)
+ {
+ throw new InvalidOperationException(ex.Message, ex);
+ }
+ }
+#endif
+
public virtual IEnumerable EnumerateFiles(string path, string searchPattern, SearchOption searchOption)
{
+#if FEATURE_MSIOREDIST
+ return ShouldUseMicrosoftIO
+ ? HandleFileLoadException(
+ (path, searchPattern, searchOption) => Microsoft.IO.Directory.EnumerateFiles(path, searchPattern, searchOption),
+ path,
+ searchPattern,
+ (Microsoft.IO.SearchOption)searchOption
+ )
+ : Directory.EnumerateFiles(path, searchPattern, searchOption);
+#else
return Directory.EnumerateFiles(path, searchPattern, searchOption);
+#endif
}
public virtual IEnumerable EnumerateDirectories(string path, string searchPattern, SearchOption searchOption)
{
+#if FEATURE_MSIOREDIST
+ return ShouldUseMicrosoftIO
+ ? HandleFileLoadException(
+ (path, searchPattern, searchOption) => Microsoft.IO.Directory.EnumerateDirectories(path, searchPattern, searchOption),
+ path,
+ searchPattern,
+ (Microsoft.IO.SearchOption)searchOption
+ )
+ : Directory.EnumerateDirectories(path, searchPattern, searchOption);
+#else
return Directory.EnumerateDirectories(path, searchPattern, searchOption);
+#endif
}
public virtual IEnumerable EnumerateFileSystemEntries(string path, string searchPattern, SearchOption searchOption)
{
+#if FEATURE_MSIOREDIST
+ return ShouldUseMicrosoftIO
+ ? HandleFileLoadException(
+ (path, searchPattern, searchOption) => Microsoft.IO.Directory.EnumerateFileSystemEntries(path, searchPattern, searchOption),
+ path,
+ searchPattern, (Microsoft.IO.SearchOption)searchOption
+ )
+ : Directory.EnumerateFileSystemEntries(path, searchPattern, searchOption);
+#else
return Directory.EnumerateFileSystemEntries(path, searchPattern, searchOption);
+#endif
}
public FileAttributes GetAttributes(string path)
diff --git a/src/Shared/UnitTests/FileMatcher_Tests.cs b/src/Shared/UnitTests/FileMatcher_Tests.cs
index d8cf2eeed4c..471e1536b63 100644
--- a/src/Shared/UnitTests/FileMatcher_Tests.cs
+++ b/src/Shared/UnitTests/FileMatcher_Tests.cs
@@ -12,6 +12,7 @@
using Microsoft.Build.Shared.FileSystem;
using Xunit;
using Xunit.Abstractions;
+using Microsoft.Build.Utilities;
namespace Microsoft.Build.UnitTests
{
@@ -1244,13 +1245,20 @@ public void IllegalPaths()
[Fact]
[PlatformSpecific(TestPlatforms.Windows)] // Nothing's too long for Unix
[SkipOnTargetFramework(TargetFrameworkMonikers.Netcoreapp)]
- public void IllegalTooLongPath()
+ public void IllegalTooLongPathOptOutWave17_0()
{
- string longString = new string('X', 500) + "*"; // need a wildcard to do anything
- string[] result = FileMatcher.Default.GetFiles(@"c:\", longString);
+ using (var env = TestEnvironment.Create())
+ {
+ ChangeWaves.ResetStateForTests();
+ env.SetEnvironmentVariable("MSBUILDDISABLEFEATURESFROMVERSION", ChangeWaves.Wave17_0.ToString());
+ BuildEnvironmentHelper.ResetInstance_ForUnitTestsOnly();
- Assert.Equal(longString, result[0]); // Does not throw
+ string longString = new string('X', 500) + "*"; // need a wildcard to do anything
+ string[] result = FileMatcher.Default.GetFiles(@"c:\", longString);
+ Assert.Equal(longString, result[0]); // Does not throw
+ ChangeWaves.ResetStateForTests();
+ }
// Not checking that GetFileSpecMatchInfo returns the illegal-path flag,
// not certain that won't break something; this fix is merely to avoid a crash.
}
diff --git a/src/Tasks/Microsoft.Build.Tasks.csproj b/src/Tasks/Microsoft.Build.Tasks.csproj
index f7c4b9555f1..69933efefbf 100644
--- a/src/Tasks/Microsoft.Build.Tasks.csproj
+++ b/src/Tasks/Microsoft.Build.Tasks.csproj
@@ -988,6 +988,8 @@
+
+
diff --git a/src/Utilities/Microsoft.Build.Utilities.csproj b/src/Utilities/Microsoft.Build.Utilities.csproj
index 09634e72315..da7f065bffe 100644
--- a/src/Utilities/Microsoft.Build.Utilities.csproj
+++ b/src/Utilities/Microsoft.Build.Utilities.csproj
@@ -21,6 +21,7 @@
+