Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eng/Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<PackageReference Update="Microsoft.CodeQuality.Analyzers" Version="3.3.0" PrivateAssets="all" />
<PackageReference Update="Microsoft.DotNet.GenAPI" Version="2.1.0-prerelease-02404-02" />
<PackageReference Update="Microsoft.DotNet.XUnitExtensions" Version="$(MicrosoftDotNetXUnitExtensionsVersion)" />
<PackageReference Update="Microsoft.IO.Redist" Version="4.7.1" />
<PackageReference Update="Microsoft.Net.Compilers.Toolset" Version="$(MicrosoftNetCompilersToolsetVersion)" />
<PackageReference Update="Microsoft.VisualStudio.SDK.EmbedInteropTypes" Version="15.0.15" />
<PackageReference Update="Microsoft.VisualStudio.Setup.Configuration.Interop" Version="1.16.30" />
Expand Down
1 change: 1 addition & 0 deletions scripts/Deploy-MSBuild.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.IO.Redist" Condition="'$(FeatureMSIORedist)' == 'true'" />

<PackageReference Include="Shouldly" />
<PackageDownload Include="NuGet.CommandLine" Version="[$(NuGetCommandLinePackageVersion)]" />
</ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions src/Build/Microsoft.Build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
<PackageReference Include="System.Text.Json" />

<PackageReference Include="System.Reflection.Metadata" Condition="'$(MonoBuild)' == 'true'" />

<PackageReference Include="Microsoft.IO.Redist" Condition="'$(FeatureMSIORedist)' == 'true'" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
Expand Down
5 changes: 5 additions & 0 deletions src/Directory.BeforeCommon.targets
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,9 @@
<DocumentationFile Condition=" '$(GenerateDocumentationFile)' == 'true' ">$(IntermediateOutputPath)\$(AssemblyName).xml</DocumentationFile>
</PropertyGroup>

<PropertyGroup Condition="'$(MonoBuild)' != 'true' and $([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">
<DefineConstants>$(DefineConstants);FEATURE_MSIOREDIST</DefineConstants>
<FeatureMSIORedist>true</FeatureMSIORedist>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.IO.Redist" Condition="'$(FeatureMSIORedist)' == 'true'" />
<PackageReference Include="Microsoft.VisualStudio.Setup.Configuration.Interop" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" />
<PackageReference Include="Shouldly" />
</ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/MSBuild/MSBuild.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.IO.Redist" Condition="'$(FeatureMSIORedist)' == 'true'" />
<PackageReference Include="System.Configuration.ConfigurationManager" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<file src="$X86BinPath$/Microsoft.Build.Framework.dll" target="v15.0/bin" />
<file src="$X86BinPath$/Microsoft.Build.Tasks.Core.dll" target="v15.0/bin" />
<file src="$X86BinPath$/Microsoft.Build.Utilities.Core.dll" target="v15.0/bin" />
<file src="$X86BinPath$/Microsoft.IO.Redist.dll" target="v15.0/bin" />
<file src="$X86BinPath$/System.Collections.Immutable.dll" target="v15.0/bin" />
<file src="$X86BinPath$/System.Memory.dll" target="v15.0/bin" />
<file src="$X86BinPath$/System.Text.Json.dll" target="v15.0/bin" />
Expand Down Expand Up @@ -87,6 +88,7 @@
<file src="$X86BinPath$/Microsoft.Build.Framework.dll" target="v15.0/bin/amd64" />
<file src="$X86BinPath$/Microsoft.Build.Tasks.Core.dll" target="v15.0/bin/amd64" />
<file src="$X86BinPath$/Microsoft.Build.Utilities.Core.dll" target="v15.0/bin/amd64" />
<file src="$X86BinPath$/Microsoft.IO.Redist.dll" target="v15.0/bin/amd64" />
<file src="$X86BinPath$/System.Collections.Immutable.dll" target="v15.0/bin/amd64" />
<file src="$X86BinPath$/System.Memory.dll" target="v15.0/bin/amd64" />
<file src="$X86BinPath$/System.Text.Json.dll" target="v15.0/bin/amd64" />
Expand Down
2 changes: 2 additions & 0 deletions src/Package/MSBuild.VSSetup/files.swr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
74 changes: 74 additions & 0 deletions src/Shared/FileSystem/ManagedFileSystem.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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)
Expand All @@ -38,19 +53,78 @@ public byte[] ReadFileAllBytes(string path)
return File.ReadAllBytes(path);
}

#if FEATURE_MSIOREDIST
private static IEnumerable<string> HandleFileLoadException(
Func<string, string, Microsoft.IO.SearchOption, IEnumerable<string>> 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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the FusionLog property available only if fusion logging is actually enabled?

I don't see FileNotFoundException listed as an exception thrown by Directory.Enumerate* so it looks like it should work without the when.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works when fusion logging is disabled. The FusionLog in this case consists of a warning "WRN: Assembly binding logging is turned OFF. To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1."

If Directory.Enumerate indeed does not throw FileNotFoundException, then additional check in when should not have any performance implications, cause it is used in rare case when we indeed have a failure. And I felt like it is safer to have it than not not have.

But I suppose you are right and we can remove this when from this line.

{
throw new InvalidOperationException(ex.Message, ex);
}
}
#endif

public virtual IEnumerable<string> 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<string> 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<string> 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)
Expand Down
16 changes: 12 additions & 4 deletions src/Shared/UnitTests/FileMatcher_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Microsoft.Build.Shared.FileSystem;
using Xunit;
using Xunit.Abstractions;
using Microsoft.Build.Utilities;

namespace Microsoft.Build.UnitTests
{
Expand Down Expand Up @@ -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.
}
Expand Down
2 changes: 2 additions & 0 deletions src/Tasks/Microsoft.Build.Tasks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,8 @@
<ProjectReference Include="..\StringTools\StringTools.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.IO.Redist" Condition="'$(FeatureMSIORedist)' == 'true'" />

<PackageReference Include="System.Collections.Immutable" />
<PackageReference Include="System.Resources.Extensions" />
</ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/Utilities/Microsoft.Build.Utilities.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<ProjectReference Include="..\Framework\Microsoft.Build.Framework.csproj" />
<ProjectReference Include="..\StringTools\StringTools.csproj" />

<PackageReference Include="Microsoft.IO.Redist" Condition="'$(FeatureMSIORedist)' == 'true'" />
<PackageReference Include="System.Collections.Immutable" />
<PackageReference Include="System.Configuration.ConfigurationManager" />
</ItemGroup>
Expand Down