From 16e9d33bea501cd9e6cb5c48935a85ae58ebbed5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Aug 2021 11:15:20 -0700 Subject: [PATCH 01/13] [release/6.0-rc1] Add Crossgen2 symbol files to package (#58193) * Add Crossgen2 symbol files to package * Slight improvement Co-authored-by: Anton Lapounov --- .../Microsoft.NETCore.App.Crossgen2.sfxproj | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj index 6990339554f497..4c3c0f82a1a55b 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj @@ -64,6 +64,18 @@ + + + <_Crossgen2SymbolFilesToPackage Include="@(Reference->'$(CoreCLRArtifactsPath)PDB\%(FileName).pdb')" /> + + <_Crossgen2SymbolFilesToPackage Include="@(NativeRuntimeAsset->'$(CoreCLRArtifactsPdbDir)%(FileName).pdb')" Condition="'$(TargetOS)' == 'windows' and '%(FileName)' != 'crossgen2'" /> + <_Crossgen2SymbolFilesToPackage Include="@(NativeRuntimeAsset->'$(CoreCLRArtifactsPath)%(FileName)%(Extension)$(SymbolsSuffix)')" Condition="'$(TargetOS)' != 'windows' and '%(FileName)' != 'crossgen2'" /> + <_Crossgen2SymbolFilesToPackage Remove="@(_Crossgen2SymbolFilesToPackage)" Condition="!Exists('%(Identity)')" /> + + <_SymbolFilesToPackage Include="@(_Crossgen2SymbolFilesToPackage)" TargetPath="tools/" /> + + + <_diaSymTargetArch>$(TargetArchitecture) From 0cd887c8b697d341adcd73f125cf7dc777754938 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Aug 2021 11:17:38 -0700 Subject: [PATCH 02/13] [mono] Avoid a JIT assert. (#58127) Workaround for https://github.com/dotnet/runtime/issues/57560. Co-authored-by: Zoltan Varga --- src/mono/mono/mini/method-to-ir.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 5b607e55636ead..96ac001f7eb464 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -5324,20 +5324,20 @@ handle_call_res_devirt (MonoCompile *cfg, MonoMethod *cmethod, MonoInst *call_re MonoClass *gcomparer = mono_class_get_geqcomparer_class (); g_assert (gcomparer); gcomparer_inst = mono_class_inflate_generic_class_checked (gcomparer, &ctx, error); - mono_error_assert_ok (error); + if (is_ok (error)) { + MONO_INST_NEW (cfg, typed_objref, OP_TYPED_OBJREF); + typed_objref->type = STACK_OBJ; + typed_objref->dreg = alloc_ireg_ref (cfg); + typed_objref->sreg1 = call_res->dreg; + typed_objref->klass = gcomparer_inst; + MONO_ADD_INS (cfg->cbb, typed_objref); - MONO_INST_NEW (cfg, typed_objref, OP_TYPED_OBJREF); - typed_objref->type = STACK_OBJ; - typed_objref->dreg = alloc_ireg_ref (cfg); - typed_objref->sreg1 = call_res->dreg; - typed_objref->klass = gcomparer_inst; - MONO_ADD_INS (cfg->cbb, typed_objref); + call_res = typed_objref; - call_res = typed_objref; - - /* Force decompose */ - cfg->flags |= MONO_CFG_NEEDS_DECOMPOSE; - cfg->cbb->needs_decompose = TRUE; + /* Force decompose */ + cfg->flags |= MONO_CFG_NEEDS_DECOMPOSE; + cfg->cbb->needs_decompose = TRUE; + } } } From 7a1f2a44312f71646dcbf2d4d011ec7faadde41c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Aug 2021 11:18:59 -0700 Subject: [PATCH 03/13] [release/6.0-rc1] [MacCatalyst] Make AppleCryptoNative_SslSetEnabledCipherSuites check for 32 bit & 16 bit SSLCipherSuite (#58182) * [MacCatalyst] Make AppleCryptoNative_SslSetEnabledCipherSuites check for 32 bit & 16 bit SSLCipherSuite According to CipherSuites.h, SSLCipherSuite is a 16 bit value on iOS/tvOS x64 & arm64, but on MacCatalyst that is only true on arm64. x64 is defined as 32 bit. ``` /* 16-bit value on iOS */ typedef uint16_t SSLCipherSuite; /* 32-bit value elsewhere */ typedef uint32_t SSLCipherSuite; ``` Fixes https://github.com/dotnet/runtime/issues/53120 * Feedback Co-authored-by: Steve Pfister --- .../System.Security.Cryptography.Native.Apple/pal_ssl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_ssl.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_ssl.c index 2d66847c1731b3..0770a946bee1ed 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_ssl.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native.Apple/pal_ssl.c @@ -596,19 +596,19 @@ int32_t AppleCryptoNative_SslSetEnabledCipherSuites(SSLContextRef sslContext, co // Max numCipherSuites is 2^16 (all possible cipher suites) assert(numCipherSuites < (1 << 16)); -#if !defined(TARGET_MACCATALYST) && !defined(TARGET_IOS) && !defined(TARGET_TVOS) +#if !defined(TARGET_ARM64) && !defined(TARGET_IOS) && !defined(TARGET_TVOS) if (sizeof(SSLCipherSuite) == sizeof(uint32_t)) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - // macOS + // macOS & MacCatalyst x64 return SSLSetEnabledCiphers(sslContext, (const SSLCipherSuite *)cipherSuites, (size_t)numCipherSuites); #pragma clang diagnostic pop } else #endif { - // MacCatalyst, iOS, tvOS, watchOS + // MacCatalyst arm64, iOS, tvOS, watchOS SSLCipherSuite* cipherSuites16 = (SSLCipherSuite*)calloc((size_t)numCipherSuites, sizeof(SSLCipherSuite)); if (cipherSuites16 == NULL) From 8da82f23adea445dd9d75a0ee5575fdae3cd8b8d Mon Sep 17 00:00:00 2001 From: Jo Shields Date: Fri, 27 Aug 2021 14:20:01 -0400 Subject: [PATCH 04/13] Give tvOS a special value for Personal/MyDocuments (#58056) --- .../System.Native/Interop.SearchPath.iOS.cs | 14 +++++++++ .../Native/Unix/System.Native/entrypoints.c | 1 + .../Unix/System.Native/pal_searchpath.c | 6 ++++ .../Unix/System.Native/pal_searchpath.h | 2 ++ .../Unix/System.Native/pal_searchpath.m | 7 +++++ .../System.Private.CoreLib.Shared.projitems | 2 ++ .../src/System/IO/Path.Unix.NoniOS.cs | 10 +++++++ .../src/System/IO/Path.Unix.cs | 1 - .../src/System/IO/Path.Unix.iOS.cs | 16 ++++++++++ .../tests/System/EnvironmentTests.cs | 13 ++++++++- src/libraries/sendtohelixhelp.proj | 2 +- .../System.Private.CoreLib.csproj | 3 ++ .../src/System/Environment.iOS.cs | 29 ++++++++++++++----- 13 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.NoniOS.cs create mode 100644 src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.iOS.cs diff --git a/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs new file mode 100644 index 00000000000000..8d73184ca4d50a --- /dev/null +++ b/src/libraries/Common/src/Interop/OSX/System.Native/Interop.SearchPath.iOS.cs @@ -0,0 +1,14 @@ +// 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.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Sys + { + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_SearchPath_TempDirectory")] + internal static extern string SearchPathTempDirectory(); + } +} diff --git a/src/libraries/Native/Unix/System.Native/entrypoints.c b/src/libraries/Native/Unix/System.Native/entrypoints.c index c8b678ec08340b..b3ae64f96f91ef 100644 --- a/src/libraries/Native/Unix/System.Native/entrypoints.c +++ b/src/libraries/Native/Unix/System.Native/entrypoints.c @@ -218,6 +218,7 @@ static const Entry s_sysNative[] = DllImportEntry(SystemNative_GetOSArchitecture) DllImportEntry(SystemNative_GetProcessArchitecture) DllImportEntry(SystemNative_SearchPath) + DllImportEntry(SystemNative_SearchPath_TempDirectory) DllImportEntry(SystemNative_RegisterForSigChld) DllImportEntry(SystemNative_SetDelayedSigChildConsoleConfigurationHandler) DllImportEntry(SystemNative_SetTerminalInvalidationHandler) diff --git a/src/libraries/Native/Unix/System.Native/pal_searchpath.c b/src/libraries/Native/Unix/System.Native/pal_searchpath.c index fbf3d903df01c7..de8037dc1a2959 100644 --- a/src/libraries/Native/Unix/System.Native/pal_searchpath.c +++ b/src/libraries/Native/Unix/System.Native/pal_searchpath.c @@ -10,3 +10,9 @@ const char* SystemNative_SearchPath(int32_t folderId) __builtin_unreachable(); return NULL; } + +const char* SystemNative_SearchPath_TempDirectory() +{ + __builtin_unreachable(); + return NULL; +} diff --git a/src/libraries/Native/Unix/System.Native/pal_searchpath.h b/src/libraries/Native/Unix/System.Native/pal_searchpath.h index e2de05d8c8860a..cdb872914624ca 100644 --- a/src/libraries/Native/Unix/System.Native/pal_searchpath.h +++ b/src/libraries/Native/Unix/System.Native/pal_searchpath.h @@ -7,3 +7,5 @@ #include "pal_types.h" PALEXPORT const char* SystemNative_SearchPath(int32_t folderId); + +PALEXPORT const char* SystemNative_SearchPath_TempDirectory(void); diff --git a/src/libraries/Native/Unix/System.Native/pal_searchpath.m b/src/libraries/Native/Unix/System.Native/pal_searchpath.m index 2e96041f3dda82..231c508c527cab 100644 --- a/src/libraries/Native/Unix/System.Native/pal_searchpath.m +++ b/src/libraries/Native/Unix/System.Native/pal_searchpath.m @@ -11,3 +11,10 @@ const char* path = [[url path] UTF8String]; return path == NULL ? NULL : strdup (path); } + +const char* SystemNative_SearchPath_TempDirectory() +{ + NSString* tempPath = NSTemporaryDirectory(); + const char *path = [tempPath UTF8String]; + return path == NULL ? NULL : strdup (path); +} diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 5a1593f032c69a..e72c543d580803 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -2112,6 +2112,8 @@ + + diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.NoniOS.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.NoniOS.cs new file mode 100644 index 00000000000000..b2a9a4b06a083e --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.NoniOS.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.IO +{ + public static partial class Path + { + private static string DefaultTempPath => "/tmp/"; + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs index 61786ad757a434..f3ec19941c21b2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs @@ -80,7 +80,6 @@ private static string RemoveLongPathPrefix(string path) public static string GetTempPath() { const string TempEnvVar = "TMPDIR"; - const string DefaultTempPath = "/tmp/"; // Get the temp path from the TMPDIR environment variable. // If it's not set, just return the default path. diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.iOS.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.iOS.cs new file mode 100644 index 00000000000000..c1c4a7047eec5e --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.iOS.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace System.IO +{ + public static partial class Path + { + private static string? s_defaultTempPath; + + private static string DefaultTempPath => + s_defaultTempPath ?? (s_defaultTempPath = Interop.Sys.SearchPathTempDirectory()) ?? + throw new InvalidOperationException(); + } +} diff --git a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs index f019b1eb11a02f..f2b35eb6c2cdf7 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/EnvironmentTests.cs @@ -330,6 +330,13 @@ public void FailFast_ExceptionStackTrace_InnerException() } } + [Fact] + [PlatformSpecific(TestPlatforms.AnyUnix | TestPlatforms.Browser)] + public void GetFolderPath_Unix_PersonalExists() + { + Assert.True(Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Personal))); + } + [Fact] [PlatformSpecific(TestPlatforms.AnyUnix | TestPlatforms.Browser)] // Tests OS-specific environment public void GetFolderPath_Unix_PersonalIsHomeAndUserProfile() @@ -339,7 +346,11 @@ public void GetFolderPath_Unix_PersonalIsHomeAndUserProfile() Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.Personal)); Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)); } - Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); + // tvOS effectively doesn't have a HOME + if (!PlatformDetection.IstvOS) + { + Assert.Equal(Environment.GetEnvironmentVariable("HOME"), Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); + } } [Theory] diff --git a/src/libraries/sendtohelixhelp.proj b/src/libraries/sendtohelixhelp.proj index 14cf90630710d4..14ea741c8c5956 100644 --- a/src/libraries/sendtohelixhelp.proj +++ b/src/libraries/sendtohelixhelp.proj @@ -294,7 +294,7 @@ $(AppleTestTarget) - + false diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index 1878cb4ed7c053..7aa4413aad70da 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -271,6 +271,9 @@ Common\Interop\OSX\Interop.SearchPath.cs + + Common\Interop\OSX\Interop.SearchPath.iOS.cs + diff --git a/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs b/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs index 1a95bdc408f1c2..01ceb05bba7dcf 100644 --- a/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs +++ b/src/mono/System.Private.CoreLib/src/System/Environment.iOS.cs @@ -36,18 +36,14 @@ private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOptio { switch (folder) { - // TODO: fix for tvOS (https://github.com/dotnet/runtime/issues/34007) - // The "normal" NSDocumentDirectory is a read-only directory on tvOS - // and that breaks a lot of assumptions in the runtime and the BCL - case SpecialFolder.Personal: case SpecialFolder.LocalApplicationData: - return Interop.Sys.SearchPath(NSSearchPathDirectory.NSDocumentDirectory); + return CombineDocumentDirectory(string.Empty); case SpecialFolder.ApplicationData: // note: at first glance that looked like a good place to return NSLibraryDirectory // but it would break isolated storage for existing applications - return CombineSearchPath(NSSearchPathDirectory.NSDocumentDirectory, ".config"); + return CombineDocumentDirectory(".config"); case SpecialFolder.Resources: return Interop.Sys.SearchPath(NSSearchPathDirectory.NSLibraryDirectory); // older (8.2 and previous) would return String.Empty @@ -63,7 +59,7 @@ private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOptio return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Pictures"); case SpecialFolder.Templates: - return CombineSearchPath(NSSearchPathDirectory.NSDocumentDirectory, "Templates"); + return CombineDocumentDirectory("Templates"); case SpecialFolder.MyVideos: return Path.Combine(GetFolderPathCore(SpecialFolder.Personal, SpecialFolderOption.None), "Videos"); @@ -72,7 +68,7 @@ private static string GetFolderPathCore(SpecialFolder folder, SpecialFolderOptio return "/usr/share/templates"; case SpecialFolder.Fonts: - return CombineSearchPath(NSSearchPathDirectory.NSDocumentDirectory, ".fonts"); + return CombineDocumentDirectory(".fonts"); case SpecialFolder.Favorites: return CombineSearchPath(NSSearchPathDirectory.NSLibraryDirectory, "Favorites"); @@ -100,6 +96,23 @@ static string CombineSearchPath(NSSearchPathDirectory searchPath, string subdire Path.Combine(path, subdirectory) : string.Empty; } + + static string CombineDocumentDirectory(string subdirectory) + { +#if TARGET_TVOS + string? path = CombineSearchPath(NSSearchPathDirectory.NSLibraryDirectory, Path.Combine("Caches", "Documents", subdirectory)); + // Special version of CombineSearchPath which creates the path if needed. + // This isn't needed for "real" search paths which always exist, but on tvOS + // the base path is really a subdirectory we define rather than an OS directory. + // In order to not treat Directory.Exists(SpecialFolder.ApplicationData) differently + // on tvOS, guarantee that it exists by creating it here + if (!Directory.Exists (path)) + Directory.CreateDirectory (path); +#else + string? path = CombineSearchPath(NSSearchPathDirectory.NSDocumentDirectory, subdirectory); +#endif + return path; + } } } } From 262b509bc01138519c08b06ee711000846036132 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Aug 2021 11:20:38 -0700 Subject: [PATCH 05/13] [mono] Replace -disable-fp-elim with -frame-pointer=all (#58195) `-disable-fp-elim` was removed in LLVM 8 in commit b7cef81fd36c85e52b115b9ed6d1fb92d63781d6. Also see https://reviews.llvm.org/D56351. The replacement option, `-frame-pointer`, is still present in LLVM 11. Fixes https://github.com/dotnet/runtime/issues/58112. Co-authored-by: Imran Hameed --- src/mono/mono/mini/aot-compiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 369016e11892d6..34c1e7606d048e 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -1149,7 +1149,7 @@ arch_init (MonoAotCompile *acfg) if (strstr (acfg->aot_opts.mtriple, "ios")) { g_string_append (acfg->llc_args, " -mattr=+v7"); - g_string_append (acfg->llc_args, " -exception-model=dwarf -disable-fp-elim"); + g_string_append (acfg->llc_args, " -exception-model=dwarf -frame-pointer=all"); } } From 72f18b5a0b1ca0054a90f4ba878cd3236862b831 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Fri, 27 Aug 2021 16:47:52 -0600 Subject: [PATCH 06/13] Make JsonGenerator be an incremental generator (#57088) (#58278) * Make JsonGenerator be an incremental generator * Improve incrementalism by doing less work when not applicable * Change SourceGeneration.UnitTests to SourceGeneration.Unit.Tests so it is built and executed in CI * Get unit tests running after IIncrementalGenerator migration * Fix duplicate file name tests by working around https://github.com/dotnet/roslyn/issues/54185. * Fix unit tests now that they are running in CI against non-English languages. * Fix System.Text.Json.SourceGeneration.Unit.Tests on WASM * Disable STJ.SourceGeneration.Unit.Tests on Browser Co-authored-by: Eric Erhardt Co-authored-by: Chris Sienkiewicz --- eng/Versions.props | 6 +-- .../System.Text.Json/System.Text.Json.sln | 2 +- .../gen/JsonSourceGenerator.Emitter.cs | 23 +++++---- .../gen/JsonSourceGenerator.Parser.cs | 51 +++++++++++++++---- .../gen/JsonSourceGenerator.cs | 48 +++++++---------- .../CompilationHelper.cs | 26 +++++++--- .../JsonSourceGeneratorDiagnosticsTests.cs | 0 .../JsonSourceGeneratorTests.cs | 0 ...t.Json.SourceGeneration.Unit.Tests.csproj} | 2 +- .../TypeWrapperTests.cs | 0 src/libraries/tests.proj | 3 ++ 11 files changed, 101 insertions(+), 60 deletions(-) rename src/libraries/System.Text.Json/tests/{System.Text.Json.SourceGeneration.UnitTests => System.Text.Json.SourceGeneration.Unit.Tests}/CompilationHelper.cs (90%) rename src/libraries/System.Text.Json/tests/{System.Text.Json.SourceGeneration.UnitTests => System.Text.Json.SourceGeneration.Unit.Tests}/JsonSourceGeneratorDiagnosticsTests.cs (100%) rename src/libraries/System.Text.Json/tests/{System.Text.Json.SourceGeneration.UnitTests => System.Text.Json.SourceGeneration.Unit.Tests}/JsonSourceGeneratorTests.cs (100%) rename src/libraries/System.Text.Json/tests/{System.Text.Json.SourceGeneration.UnitTests/System.Text.Json.SourceGeneration.UnitTests.csproj => System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.csproj} (94%) rename src/libraries/System.Text.Json/tests/{System.Text.Json.SourceGeneration.UnitTests => System.Text.Json.SourceGeneration.Unit.Tests}/TypeWrapperTests.cs (100%) diff --git a/eng/Versions.props b/eng/Versions.props index 42d6f811752efa..a86e7cc942f824 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -40,9 +40,9 @@ - - 3.9.0 - 3.9.0 + + 4.0.0-3.final + 4.0.0-3.final diff --git a/src/libraries/System.Text.Json/System.Text.Json.sln b/src/libraries/System.Text.Json/System.Text.Json.sln index b8309363a7b30a..42d0da090e9bc4 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.sln +++ b/src/libraries/System.Text.Json/System.Text.Json.sln @@ -43,7 +43,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Text.Encodings.Web", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Collections.Immutable", "..\System.Collections.Immutable\ref\System.Collections.Immutable.csproj", "{BE27618A-2916-4269-9AD5-6BC5EDC32B30}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Text.Json.SourceGeneration.UnitTests", "tests\System.Text.Json.SourceGeneration.UnitTests\System.Text.Json.SourceGeneration.UnitTests.csproj", "{F6A18EB5-A8CC-4A39-9E85-5FA226019C3D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Text.Json.SourceGeneration.Unit.Tests", "tests\System.Text.Json.SourceGeneration.Unit.Tests\System.Text.Json.SourceGeneration.Unit.Tests.csproj", "{F6A18EB5-A8CC-4A39-9E85-5FA226019C3D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs index 5acb94ea9d34df..ca93f97e70585e 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs @@ -79,15 +79,17 @@ private sealed partial class Emitter defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true); - private readonly GeneratorExecutionContext _executionContext; + private readonly SourceProductionContext _sourceProductionContext; private ContextGenerationSpec _currentContext = null!; private readonly SourceGenerationSpec _generationSpec = null!; - public Emitter(in GeneratorExecutionContext executionContext, SourceGenerationSpec generationSpec) + private readonly HashSet _emittedPropertyFileNames = new(); + + public Emitter(in SourceProductionContext sourceProductionContext, SourceGenerationSpec generationSpec) { - _executionContext = executionContext; + _sourceProductionContext = sourceProductionContext; _generationSpec = generationSpec; } @@ -166,7 +168,7 @@ namespace {@namespace} sb.AppendLine("}"); } - _executionContext.AddSource(fileName, SourceText.From(sb.ToString(), Encoding.UTF8)); + _sourceProductionContext.AddSource(fileName, SourceText.From(sb.ToString(), Encoding.UTF8)); } private void GenerateTypeInfo(TypeGenerationSpec typeGenerationSpec) @@ -243,7 +245,7 @@ private void GenerateTypeInfo(TypeGenerationSpec typeGenerationSpec) break; case ClassType.TypeUnsupportedBySourceGen: { - _executionContext.ReportDiagnostic( + _sourceProductionContext.ReportDiagnostic( Diagnostic.Create(TypeNotSupported, Location.None, new string[] { typeGenerationSpec.TypeRef })); return; } @@ -253,13 +255,16 @@ private void GenerateTypeInfo(TypeGenerationSpec typeGenerationSpec) } } - try + // Don't add a duplicate file, but instead raise a diagnostic to say the duplicate has been skipped. + // Workaround https://github.com/dotnet/roslyn/issues/54185 by keeping track of the file names we've used. + string propertyFileName = $"{_currentContext.ContextType.Name}.{typeGenerationSpec.TypeInfoPropertyName}.g.cs"; + if (_emittedPropertyFileNames.Add(propertyFileName)) { - AddSource($"{_currentContext.ContextType.Name}.{typeGenerationSpec.TypeInfoPropertyName}.g.cs", source); + AddSource(propertyFileName, source); } - catch (ArgumentException) + else { - _executionContext.ReportDiagnostic(Diagnostic.Create(DuplicateTypeName, Location.None, new string[] { typeGenerationSpec.TypeInfoPropertyName })); + _sourceProductionContext.ReportDiagnostic(Diagnostic.Create(DuplicateTypeName, Location.None, new string[] { typeGenerationSpec.TypeInfoPropertyName })); } } diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index b75b7a686bb4cf..cd47bcae0c0755 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -31,7 +32,8 @@ private sealed class Parser private const string JsonPropertyNameAttributeFullName = "System.Text.Json.Serialization.JsonPropertyNameAttribute"; private const string JsonPropertyOrderAttributeFullName = "System.Text.Json.Serialization.JsonPropertyOrderAttribute"; - private readonly GeneratorExecutionContext _executionContext; + private readonly Compilation _compilation; + private readonly SourceProductionContext _sourceProductionContext; private readonly MetadataLoadContextInternal _metadataLoadContext; private readonly Type _ilistOfTType; @@ -43,7 +45,7 @@ private sealed class Parser private readonly Type? _dictionaryType; private readonly Type? _idictionaryOfTKeyTValueType; private readonly Type? _ireadonlyDictionaryType; - private readonly Type? _isetType; + private readonly Type? _isetType; private readonly Type? _stackOfTType; private readonly Type? _queueOfTType; private readonly Type? _concurrentStackType; @@ -96,10 +98,11 @@ private sealed class Parser defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); - public Parser(in GeneratorExecutionContext executionContext) + public Parser(Compilation compilation, in SourceProductionContext sourceProductionContext) { - _executionContext = executionContext; - _metadataLoadContext = new MetadataLoadContextInternal(executionContext.Compilation); + _compilation = compilation; + _sourceProductionContext = sourceProductionContext; + _metadataLoadContext = new MetadataLoadContextInternal(_compilation); _ilistOfTType = _metadataLoadContext.Resolve(SpecialType.System_Collections_Generic_IList_T); _icollectionOfTType = _metadataLoadContext.Resolve(SpecialType.System_Collections_Generic_ICollection_T); @@ -138,9 +141,9 @@ public Parser(in GeneratorExecutionContext executionContext) PopulateKnownTypes(); } - public SourceGenerationSpec? GetGenerationSpec(List classDeclarationSyntaxList) + public SourceGenerationSpec? GetGenerationSpec(ImmutableArray classDeclarationSyntaxList) { - Compilation compilation = _executionContext.Compilation; + Compilation compilation = _compilation; INamedTypeSymbol jsonSerializerContextSymbol = compilation.GetTypeByMetadataName("System.Text.Json.Serialization.JsonSerializerContext"); INamedTypeSymbol jsonSerializableAttributeSymbol = compilation.GetTypeByMetadataName("System.Text.Json.Serialization.JsonSerializableAttribute"); INamedTypeSymbol jsonSourceGenerationOptionsAttributeSymbol = compilation.GetTypeByMetadataName("System.Text.Json.Serialization.JsonSourceGenerationOptionsAttribute"); @@ -198,7 +201,7 @@ public Parser(in GeneratorExecutionContext executionContext) if (!TryGetClassDeclarationList(contextTypeSymbol, out List classDeclarationList)) { // Class or one of its containing types is not partial so we can't add to it. - _executionContext.ReportDiagnostic(Diagnostic.Create(ContextClassesMustBePartial, Location.None, new string[] { contextTypeSymbol.Name })); + _sourceProductionContext.ReportDiagnostic(Diagnostic.Create(ContextClassesMustBePartial, Location.None, new string[] { contextTypeSymbol.Name })); continue; } @@ -400,6 +403,36 @@ private static bool TryGetClassDeclarationList(INamedTypeSymbol typeSymbol, [Not return typeGenerationSpec; } + internal static bool IsSyntaxTargetForGeneration(SyntaxNode node) => node is ClassDeclarationSyntax { AttributeLists: { Count: > 0 }, BaseList: { Types : {Count : > 0 } } }; + + internal static ClassDeclarationSyntax? GetSemanticTargetForGeneration(GeneratorSyntaxContext context) + { + var classDeclarationSyntax = (ClassDeclarationSyntax)context.Node; + + foreach (AttributeListSyntax attributeListSyntax in classDeclarationSyntax.AttributeLists) + { + foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes) + { + IMethodSymbol attributeSymbol = context.SemanticModel.GetSymbolInfo(attributeSyntax).Symbol as IMethodSymbol; + if (attributeSymbol == null) + { + continue; + } + + INamedTypeSymbol attributeContainingTypeSymbol = attributeSymbol.ContainingType; + string fullName = attributeContainingTypeSymbol.ToDisplayString(); + + if (fullName == "System.Text.Json.Serialization.JsonSerializableAttribute") + { + return classDeclarationSyntax; + } + } + + } + + return null; + } + private static JsonSourceGenerationMode? GetJsonSourceGenerationModeEnumVal(SyntaxNode propertyValueMode) { IEnumerable enumTokens = propertyValueMode @@ -729,7 +762,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener if (!type.TryGetDeserializationConstructor(useDefaultCtorInAnnotatedStructs, out ConstructorInfo? constructor)) { classType = ClassType.TypeUnsupportedBySourceGen; - _executionContext.ReportDiagnostic(Diagnostic.Create(MultipleJsonConstructorAttribute, Location.None, new string[] { $"{type}" })); + _sourceProductionContext.ReportDiagnostic(Diagnostic.Create(MultipleJsonConstructorAttribute, Location.None, new string[] { $"{type}" })); } else { diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.cs index 51b548e57892ba..e155488975622b 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +//#define LAUNCH_DEBUGGER using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Reflection; @@ -16,22 +18,21 @@ namespace System.Text.Json.SourceGeneration /// Generates source code to optimize serialization and deserialization with JsonSerializer. /// [Generator] - public sealed partial class JsonSourceGenerator : ISourceGenerator + public sealed partial class JsonSourceGenerator : IIncrementalGenerator { - /// - /// Registers a syntax resolver to receive compilation units. - /// - /// - public void Initialize(GeneratorInitializationContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { - context.RegisterForSyntaxNotifications(() => new SyntaxReceiver()); + IncrementalValuesProvider classDeclarations = context.SyntaxProvider + .CreateSyntaxProvider(static (s, _) => Parser.IsSyntaxTargetForGeneration(s), static (s, _) => Parser.GetSemanticTargetForGeneration(s)) + .Where(static c => c is not null); + + IncrementalValueProvider<(Compilation, ImmutableArray)> compilationAndClasses = + context.CompilationProvider.Combine(classDeclarations.Collect()); + + context.RegisterSourceOutput(compilationAndClasses, (spc, source) => Execute(source.Item1, source.Item2, spc)); } - /// - /// Generates source code to optimize serialization and deserialization with JsonSerializer. - /// - /// - public void Execute(GeneratorExecutionContext executionContext) + private void Execute(Compilation compilation, ImmutableArray contextClasses, SourceProductionContext context) { #if LAUNCH_DEBUGGER if (!Diagnostics.Debugger.IsAttached) @@ -39,37 +40,22 @@ public void Execute(GeneratorExecutionContext executionContext) Diagnostics.Debugger.Launch(); } #endif - SyntaxReceiver receiver = (SyntaxReceiver)executionContext.SyntaxReceiver; - List? contextClasses = receiver.ClassDeclarationSyntaxList; - if (contextClasses == null) + if (contextClasses.IsDefaultOrEmpty) { return; } - Parser parser = new(executionContext); - SourceGenerationSpec? spec = parser.GetGenerationSpec(receiver.ClassDeclarationSyntaxList); + Parser parser = new(compilation, context); + SourceGenerationSpec? spec = parser.GetGenerationSpec(contextClasses); if (spec != null) { _rootTypes = spec.ContextGenerationSpecList[0].RootSerializableTypes; - Emitter emitter = new(executionContext, spec); + Emitter emitter = new(context, spec); emitter.Emit(); } } - private sealed class SyntaxReceiver : ISyntaxReceiver - { - public List? ClassDeclarationSyntaxList { get; private set; } - - public void OnVisitSyntaxNode(SyntaxNode syntaxNode) - { - if (syntaxNode is ClassDeclarationSyntax cds) - { - (ClassDeclarationSyntaxList ??= new List()).Add(cds); - } - } - } - /// /// Helper for unit tests. /// diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/CompilationHelper.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs similarity index 90% rename from src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/CompilationHelper.cs rename to src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs index 86a261f284e67a..7d1858d5e47a91 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/CompilationHelper.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -16,6 +17,11 @@ namespace System.Text.Json.SourceGeneration.UnitTests { public class CompilationHelper { + private static readonly CSharpParseOptions s_parseOptions = + new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Parse) + // workaround https://github.com/dotnet/roslyn/pull/55866. We can remove "LangVersion=Preview" when we get a Roslyn build with that change. + .WithLanguageVersion(LanguageVersion.Preview); + public static Compilation CreateCompilation( string source, MetadataReference[] additionalReferences = null, @@ -55,18 +61,18 @@ public static Compilation CreateCompilation( return CSharpCompilation.Create( assemblyName, - syntaxTrees: new[] { CSharpSyntaxTree.ParseText(source) }, + syntaxTrees: new[] { CSharpSyntaxTree.ParseText(source, s_parseOptions) }, references: references.ToArray(), options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) ); } - private static GeneratorDriver CreateDriver(Compilation compilation, params ISourceGenerator[] generators) + private static GeneratorDriver CreateDriver(Compilation compilation, IIncrementalGenerator[] generators) => CSharpGeneratorDriver.Create( - generators: ImmutableArray.Create(generators), - parseOptions: new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Parse)); + generators: generators.Select(g => g.AsSourceGenerator()), + parseOptions: s_parseOptions); - public static Compilation RunGenerators(Compilation compilation, out ImmutableArray diagnostics, params ISourceGenerator[] generators) + public static Compilation RunGenerators(Compilation compilation, out ImmutableArray diagnostics, params IIncrementalGenerator[] generators) { CreateDriver(compilation, generators).RunGeneratorsAndUpdateCompilation(compilation, out Compilation outCompilation, out diagnostics); return outCompilation; @@ -267,7 +273,15 @@ internal static void CheckDiagnosticMessages(ImmutableArray diagnost Array.Sort(actualMessages); Array.Sort(expectedMessages); - Assert.Equal(expectedMessages, actualMessages); + if (CultureInfo.CurrentUICulture.Name.StartsWith("en", StringComparison.OrdinalIgnoreCase)) + { + Assert.Equal(expectedMessages, actualMessages); + } + else + { + // for non-English runs, just compare the number of messages are the same + Assert.Equal(expectedMessages.Length, actualMessages.Length); + } } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorDiagnosticsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorDiagnosticsTests.cs rename to src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs rename to src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/System.Text.Json.SourceGeneration.UnitTests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.csproj similarity index 94% rename from src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/System.Text.Json.SourceGeneration.UnitTests.csproj rename to src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.csproj index fad3b73e1026df..ef8eb335c61e1c 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/System.Text.Json.SourceGeneration.UnitTests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/System.Text.Json.SourceGeneration.Unit.Tests.csproj @@ -5,7 +5,7 @@ - + diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/TypeWrapperTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/TypeWrapperTests.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.UnitTests/TypeWrapperTests.cs rename to src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/TypeWrapperTests.cs diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 38fd8bef71336a..79e47df5100e6d 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -233,6 +233,9 @@ + + + From 7bfbc967ebc846e353f8f65a79f32129d7a9430d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Aug 2021 17:30:23 -0700 Subject: [PATCH 07/13] [release/6.0-rc1] Migrate LoggerMessageGenerator to IIncrementalGenerator (#58271) * Migrate LoggerMessageGenerator to IIncrementalGenerator This reduces the time spent in the background in VS running the source generator, since we only need to respond to methods that have the LoggerMessageAttribute on them. Contributes to #56702 * PR feedback * PR feedback Co-authored-by: Eric Erhardt --- .../tests/SourceGenerators/RoslynTestUtils.cs | 7 +-- .../gen/LoggerMessageGenerator.Parser.cs | 38 ++++++++++++-- .../gen/LoggerMessageGenerator.cs | 49 ++++++++----------- .../LoggerMessageGeneratorParserTests.cs | 5 +- 4 files changed, 62 insertions(+), 37 deletions(-) diff --git a/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs b/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs index 4928270b06f170..1c57260b8601de 100644 --- a/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs +++ b/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs @@ -141,10 +141,9 @@ public static TextSpan MakeSpan(string text, int spanNum) /// Runs a Roslyn generator over a set of source files. /// public static async Task<(ImmutableArray, ImmutableArray)> RunGenerator( - ISourceGenerator generator, + IIncrementalGenerator generator, IEnumerable? references, IEnumerable sources, - AnalyzerConfigOptionsProvider? optionsProvider = null, bool includeBaseReferences = true, CancellationToken cancellationToken = default) { @@ -156,7 +155,9 @@ public static TextSpan MakeSpan(string text, int spanNum) Compilation? comp = await proj!.GetCompilationAsync(CancellationToken.None).ConfigureAwait(false); - CSharpGeneratorDriver cgd = CSharpGeneratorDriver.Create(new[] { generator }, optionsProvider: optionsProvider); + // workaround https://github.com/dotnet/roslyn/pull/55866. We can remove "LangVersion=Preview" when we get a Roslyn build with that change. + CSharpParseOptions options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview); + CSharpGeneratorDriver cgd = CSharpGeneratorDriver.Create(new[] { generator.AsSourceGenerator() }, parseOptions: options); GeneratorDriver gd = cgd.RunGenerators(comp!, cancellationToken); GeneratorDriverRunResult r = gd.GetRunResult(); diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs index 4a995039104b9d..b448bc79081e8d 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs @@ -17,6 +17,8 @@ public partial class LoggerMessageGenerator { internal class Parser { + private const string LoggerMessageAttribute = "Microsoft.Extensions.Logging.LoggerMessageAttribute"; + private readonly CancellationToken _cancellationToken; private readonly Compilation _compilation; private readonly Action _reportDiagnostic; @@ -28,13 +30,41 @@ public Parser(Compilation compilation, Action reportDiagnostic, Canc _reportDiagnostic = reportDiagnostic; } + internal static bool IsSyntaxTargetForGeneration(SyntaxNode node) => + node is MethodDeclarationSyntax m && m.AttributeLists.Count > 0; + + internal static ClassDeclarationSyntax? GetSemanticTargetForGeneration(GeneratorSyntaxContext context) + { + var methodDeclarationSyntax = (MethodDeclarationSyntax)context.Node; + + foreach (AttributeListSyntax attributeListSyntax in methodDeclarationSyntax.AttributeLists) + { + foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes) + { + IMethodSymbol attributeSymbol = context.SemanticModel.GetSymbolInfo(attributeSyntax).Symbol as IMethodSymbol; + if (attributeSymbol == null) + { + continue; + } + + INamedTypeSymbol attributeContainingTypeSymbol = attributeSymbol.ContainingType; + string fullName = attributeContainingTypeSymbol.ToDisplayString(); + + if (fullName == LoggerMessageAttribute) + { + return methodDeclarationSyntax.Parent as ClassDeclarationSyntax; + } + } + } + + return null; + } + /// /// Gets the set of logging classes containing methods to output. /// public IReadOnlyList GetLogClasses(IEnumerable classes) { - const string LoggerMessageAttribute = "Microsoft.Extensions.Logging.LoggerMessageAttribute"; - INamedTypeSymbol loggerMessageAttribute = _compilation.GetTypeByMetadataName(LoggerMessageAttribute); if (loggerMessageAttribute == null) { @@ -442,11 +472,11 @@ public IReadOnlyList GetLogClasses(IEnumerable + bool IsAllowedKind(SyntaxKind kind) => kind == SyntaxKind.ClassDeclaration || kind == SyntaxKind.StructDeclaration || kind == SyntaxKind.RecordDeclaration; - + while (parentLoggerClass != null && IsAllowedKind(parentLoggerClass.Kind())) { currentLoggerClass.ParentClass = new LoggerClass diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.cs index 92105d515e328c..7aaca68e758a28 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.cs @@ -3,7 +3,10 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.Tracing; +using System.Linq; using System.Runtime.CompilerServices; using System.Text; using Microsoft.CodeAnalysis; @@ -15,50 +18,38 @@ namespace Microsoft.Extensions.Logging.Generators { [Generator] - public partial class LoggerMessageGenerator : ISourceGenerator + public partial class LoggerMessageGenerator : IIncrementalGenerator { - [ExcludeFromCodeCoverage] - public void Initialize(GeneratorInitializationContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { - context.RegisterForSyntaxNotifications(SyntaxReceiver.Create); + IncrementalValuesProvider classDeclarations = context.SyntaxProvider + .CreateSyntaxProvider(static (s, _) => Parser.IsSyntaxTargetForGeneration(s), static (ctx, _) => Parser.GetSemanticTargetForGeneration(ctx)) + .Where(static m => m is not null); + + IncrementalValueProvider<(Compilation, ImmutableArray)> compilationAndClasses = + context.CompilationProvider.Combine(classDeclarations.Collect()); + + context.RegisterSourceOutput(compilationAndClasses, static (spc, source) => Execute(source.Item1, source.Item2, spc)); } - [ExcludeFromCodeCoverage] - public void Execute(GeneratorExecutionContext context) + private static void Execute(Compilation compilation, ImmutableArray classes, SourceProductionContext context) { - if (context.SyntaxReceiver is not SyntaxReceiver receiver || receiver.ClassDeclarations.Count == 0) + if (classes.IsDefaultOrEmpty) { // nothing to do yet return; } - var p = new Parser(context.Compilation, context.ReportDiagnostic, context.CancellationToken); - IReadOnlyList logClasses = p.GetLogClasses(receiver.ClassDeclarations); + IEnumerable distinctClasses = classes.Distinct(); + + var p = new Parser(compilation, context.ReportDiagnostic, context.CancellationToken); + IReadOnlyList logClasses = p.GetLogClasses(distinctClasses); if (logClasses.Count > 0) { var e = new Emitter(); string result = e.Emit(logClasses, context.CancellationToken); - - context.AddSource("LoggerMessage.g.cs", SourceText.From(result, Encoding.UTF8)); - } - } - [ExcludeFromCodeCoverage] - private sealed class SyntaxReceiver : ISyntaxReceiver - { - internal static ISyntaxReceiver Create() - { - return new SyntaxReceiver(); - } - - public List ClassDeclarations { get; } = new (); - - public void OnVisitSyntaxNode(SyntaxNode syntaxNode) - { - if (syntaxNode is ClassDeclarationSyntax classSyntax) - { - ClassDeclarations.Add(classSyntax); - } + context.AddSource("LoggerMessage.g.cs", SourceText.From(result, Encoding.UTF8)); } } } diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs index b2fe61084c52ea..a1ec4253469ae7 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs @@ -380,6 +380,7 @@ public class Object {} public class Void {} public class String {} public struct DateTime {} + public abstract class Attribute {} } namespace System.Collections { @@ -392,10 +393,12 @@ public interface ILogger {} } namespace Microsoft.Extensions.Logging { - public class LoggerMessageAttribute {} + public class LoggerMessageAttribute : System.Attribute {} } partial class C { + [Microsoft.Extensions.Logging.LoggerMessage] + public static partial void Log(ILogger logger); } ", false, includeBaseReferences: false, includeLoggingReferences: false); From 9edb089db864c8a2ac61bf3d19aea531a020e442 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Aug 2021 20:04:04 -0600 Subject: [PATCH 08/13] [release/6.0-rc1] Add internal junction support to link APIs (#58285) * Add mount point support to link APIs. * Add junction and virtual drive tests. * Move PrintName comment outside of if else of reparseTag check. * Add Windows platform specific attribute to junction and virtual drive test classes. * Revert FILE_NAME_OPENED to FILE_NAME_NORMALIZED * Revert addition of FILE_NAME_OPENED const. * Remove unnecessary enumeration junction test. * Rename GetNewCwdPath to ChangeCurrentDirectory * Make Junction_ResolveLinkTarget a theory and test both resolveFinalTarget * Shorter name for targetPath string. Typo in comment. Fix Debug.Assert. * Clarify test comment. Change PlatformDetection for OperatingSystem check. * Cleaner unit tests for virtual drive, add indirection test * Skip virtual drive tests in Windows Nano (subst not available). Small test rename. * Simplify Junctions tests, add indirection test * Address test suggestions. * Revert MountHelper.CreateSymbolicLink changes. Unrelated, and will be refactored/removed in the future. Detect if SUBST is available in Windows machine, to bring back Nano. * Add dwReserved0 check for mount points in GetFinalLinkTarget. * Use Yoda we don't. * Fix CI issues Co-authored-by: carlossanlop Co-authored-by: David Cantu --- .../Kernel32/Interop.REPARSE_DATA_BUFFER.cs | 29 +- .../TestUtilities/System/PlatformDetection.cs | 22 ++ .../BaseSymbolicLinks.FileSystem.cs | 5 +- .../Base/SymbolicLinks/BaseSymbolicLinks.cs | 17 +- .../tests/Junctions.Windows.cs | 71 +++++ .../PortedCommon/ReparsePointUtilities.cs | 125 +++++++-- .../tests/System.IO.FileSystem.Tests.csproj | 7 +- .../VirtualDriveSymbolicLinks.Windows.cs | 247 ++++++++++++++++++ .../src/System/IO/FileSystem.Windows.cs | 55 ++-- 9 files changed, 522 insertions(+), 56 deletions(-) create mode 100644 src/libraries/System.IO.FileSystem/tests/Junctions.Windows.cs create mode 100644 src/libraries/System.IO.FileSystem/tests/VirtualDriveSymbolicLinks.Windows.cs diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.REPARSE_DATA_BUFFER.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.REPARSE_DATA_BUFFER.cs index 3bcb9162d57bfc..123ac9235b9fdc 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.REPARSE_DATA_BUFFER.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.REPARSE_DATA_BUFFER.cs @@ -14,24 +14,29 @@ internal static partial class Kernel32 internal const uint SYMLINK_FLAG_RELATIVE = 1; // https://msdn.microsoft.com/library/windows/hardware/ff552012.aspx - // We don't need all the struct fields; omitting the rest. [StructLayout(LayoutKind.Sequential)] - internal unsafe struct REPARSE_DATA_BUFFER + internal unsafe struct SymbolicLinkReparseBuffer { internal uint ReparseTag; internal ushort ReparseDataLength; internal ushort Reserved; - internal SymbolicLinkReparseBuffer ReparseBufferSymbolicLink; + internal ushort SubstituteNameOffset; + internal ushort SubstituteNameLength; + internal ushort PrintNameOffset; + internal ushort PrintNameLength; + internal uint Flags; + } - [StructLayout(LayoutKind.Sequential)] - internal struct SymbolicLinkReparseBuffer - { - internal ushort SubstituteNameOffset; - internal ushort SubstituteNameLength; - internal ushort PrintNameOffset; - internal ushort PrintNameLength; - internal uint Flags; - } + [StructLayout(LayoutKind.Sequential)] + internal struct MountPointReparseBuffer + { + public uint ReparseTag; + public ushort ReparseDataLength; + public ushort Reserved; + public ushort SubstituteNameOffset; + public ushort SubstituteNameLength; + public ushort PrintNameOffset; + public ushort PrintNameLength; } } } diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index efef067dbce645..fbd5df9afdde75 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -267,6 +267,28 @@ private static bool GetStaticNonPublicBooleanPropertyValue(string typeName, stri public static bool IsIcuGlobalization => ICUVersion > new Version(0,0,0,0); public static bool IsNlsGlobalization => IsNotInvariantGlobalization && !IsIcuGlobalization; + public static bool IsSubstAvailable + { + get + { + try + { + if (IsWindows) + { + string systemRoot = Environment.GetEnvironmentVariable("SystemRoot"); + if (string.IsNullOrWhiteSpace(systemRoot)) + { + return false; + } + string system32 = Path.Combine(systemRoot, "System32"); + return File.Exists(Path.Combine(system32, "subst.exe")); + } + } + catch { } + return false; + } + } + private static Version GetICUVersion() { int version = 0; diff --git a/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.FileSystem.cs b/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.FileSystem.cs index 0682f8ce16e5bb..9f61e73a36a6b1 100644 --- a/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.FileSystem.cs +++ b/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.FileSystem.cs @@ -460,11 +460,10 @@ private void ResolveLinkTarget_ReturnFinalTarget(string link1Path, string link1T Assert.Equal(filePath, finalTarget.FullName); } + // Must call inside a remote executor protected void CreateSymbolicLink_PathToTarget_RelativeToLinkPath_Internal(bool createOpposite) { - string tempCwd = GetRandomDirPath(); - Directory.CreateDirectory(tempCwd); - Directory.SetCurrentDirectory(tempCwd); + string tempCwd = ChangeCurrentDirectory(); // Create a dummy file or directory in cwd. string fileOrDirectoryInCwd = GetRandomFileName(); diff --git a/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.cs b/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.cs index f120cdf10eba53..6e5637d8327271 100644 --- a/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.cs +++ b/src/libraries/System.IO.FileSystem/tests/Base/SymbolicLinks/BaseSymbolicLinks.cs @@ -1,10 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Buffers; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Microsoft.Win32.SafeHandles; using Xunit; namespace System.IO.Tests @@ -36,5 +32,18 @@ protected DirectoryInfo CreateSelfReferencingSymbolicLink() protected string GetRandomDirPath() => Path.Join(ActualTestDirectory.Value, GetRandomDirName()); private Lazy ActualTestDirectory => new Lazy(() => GetTestDirectoryActualCasing()); + + /// + /// Changes the current working directory path to a new temporary directory. + /// Important: Make sure to call this inside a remote executor to avoid changing the cwd for all tests in same process. + /// + /// The path of the new cwd. + protected string ChangeCurrentDirectory() + { + string tempCwd = GetRandomDirPath(); + Directory.CreateDirectory(tempCwd); + Directory.SetCurrentDirectory(tempCwd); + return tempCwd; + } } } diff --git a/src/libraries/System.IO.FileSystem/tests/Junctions.Windows.cs b/src/libraries/System.IO.FileSystem/tests/Junctions.Windows.cs new file mode 100644 index 00000000000000..f4f2150b803149 --- /dev/null +++ b/src/libraries/System.IO.FileSystem/tests/Junctions.Windows.cs @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace System.IO.Tests +{ + [PlatformSpecific(TestPlatforms.Windows)] + public class Junctions : BaseSymbolicLinks + { + protected DirectoryInfo CreateJunction(string junctionPath, string targetPath) + { + Assert.True(MountHelper.CreateJunction(junctionPath, targetPath)); + DirectoryInfo junctionInfo = new(junctionPath); + return junctionInfo; + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void Junction_ResolveLinkTarget(bool returnFinalTarget) + { + string junctionPath = GetRandomLinkPath(); + string targetPath = GetRandomDirPath(); + + Directory.CreateDirectory(targetPath); + DirectoryInfo junctionInfo = CreateJunction(junctionPath, targetPath); + + FileSystemInfo? targetFromDirectoryInfo = junctionInfo.ResolveLinkTarget(returnFinalTarget); + FileSystemInfo? targetFromDirectory = Directory.ResolveLinkTarget(junctionPath, returnFinalTarget); + + Assert.True(targetFromDirectoryInfo is DirectoryInfo); + Assert.True(targetFromDirectory is DirectoryInfo); + + Assert.Equal(targetPath, junctionInfo.LinkTarget); + + Assert.Equal(targetPath, targetFromDirectoryInfo.FullName); + Assert.Equal(targetPath, targetFromDirectory.FullName); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void Junction_ResolveLinkTarget_WithIndirection(bool returnFinalTarget) + { + string firstJunctionPath = GetRandomLinkPath(); + string middleJunctionPath = GetRandomLinkPath(); + string targetPath = GetRandomDirPath(); + + Directory.CreateDirectory(targetPath); + CreateJunction(middleJunctionPath, targetPath); + DirectoryInfo firstJunctionInfo = CreateJunction(firstJunctionPath, middleJunctionPath); + + string expectedTargetPath = returnFinalTarget ? targetPath : middleJunctionPath; + + FileSystemInfo? targetFromDirectoryInfo = firstJunctionInfo.ResolveLinkTarget(returnFinalTarget); + FileSystemInfo? targetFromDirectory = Directory.ResolveLinkTarget(firstJunctionPath, returnFinalTarget); + + Assert.True(targetFromDirectoryInfo is DirectoryInfo); + Assert.True(targetFromDirectory is DirectoryInfo); + + // Always the immediate target + Assert.Equal(middleJunctionPath, firstJunctionInfo.LinkTarget); + + Assert.Equal(expectedTargetPath, targetFromDirectoryInfo.FullName); + Assert.Equal(expectedTargetPath, targetFromDirectory.FullName); + } + } +} diff --git a/src/libraries/System.IO.FileSystem/tests/PortedCommon/ReparsePointUtilities.cs b/src/libraries/System.IO.FileSystem/tests/PortedCommon/ReparsePointUtilities.cs index 5423bda6814b3b..8c7f3608d35ce2 100644 --- a/src/libraries/System.IO.FileSystem/tests/PortedCommon/ReparsePointUtilities.cs +++ b/src/libraries/System.IO.FileSystem/tests/PortedCommon/ReparsePointUtilities.cs @@ -10,14 +10,14 @@ #define DEBUG using System; -using System.IO; -using System.Text; -using System.Diagnostics; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; using System.Runtime.InteropServices; -using System.ComponentModel; -using System.Threading; +using System.Text; using System.Threading.Tasks; + public static class MountHelper { [DllImport("kernel32.dll", EntryPoint = "GetVolumeNameForVolumeMountPointW", CharSet = CharSet.Unicode, BestFitMapping = false, SetLastError = true)] @@ -28,9 +28,7 @@ public static class MountHelper [DllImport("kernel32.dll", EntryPoint = "DeleteVolumeMountPointW", CharSet = CharSet.Unicode, BestFitMapping = false, SetLastError = true)] private static extern bool DeleteVolumeMountPoint(string mountPoint); - /// Creates a symbolic link using command line tools - /// The existing file - /// + /// Creates a symbolic link using command line tools. public static bool CreateSymbolicLink(string linkPath, string targetPath, bool isDirectory) { Process symLinkProcess = new Process(); @@ -48,20 +46,78 @@ public static bool CreateSymbolicLink(string linkPath, string targetPath, bool i symLinkProcess.StartInfo.RedirectStandardOutput = true; symLinkProcess.Start(); - if (symLinkProcess != null) + symLinkProcess.WaitForExit(); + return symLinkProcess.ExitCode == 0; + } + + /// On Windows, creates a junction using command line tools. + public static bool CreateJunction(string junctionPath, string targetPath) + { + if (!OperatingSystem.IsWindows()) { - symLinkProcess.WaitForExit(); - return (0 == symLinkProcess.ExitCode); + throw new PlatformNotSupportedException(); } - else + + return RunProcess(CreateProcessStartInfo("cmd", "/c", "mklink", "/J", junctionPath, targetPath)); + } + + /// + /// On Windows, mounts a folder to an assigned virtual drive letter using the subst command. + /// subst is not available in Windows Nano. + /// + public static char CreateVirtualDrive(string targetDir) + { + if (!OperatingSystem.IsWindows()) + { + throw new PlatformNotSupportedException(); + } + + char driveLetter = GetNextAvailableDriveLetter(); + bool success = RunProcess(CreateProcessStartInfo("cmd", "/c", SubstPath, $"{driveLetter}:", targetDir)); + if (!success || !DriveInfo.GetDrives().Any(x => x.Name[0] == driveLetter)) + { + throw new InvalidOperationException($"Could not create virtual drive {driveLetter}: with subst"); + } + return driveLetter; + + // Finds the next unused drive letter and returns it. + char GetNextAvailableDriveLetter() { - return false; + List existingDrives = DriveInfo.GetDrives().Select(x => x.Name[0]).ToList(); + + // A,B are reserved, C is usually reserved + IEnumerable range = Enumerable.Range('D', 'Z' - 'D'); + IEnumerable castRange = range.Select(x => Convert.ToChar(x)); + IEnumerable allDrivesLetters = castRange.Except(existingDrives); + + if (!allDrivesLetters.Any()) + { + throw new ArgumentOutOfRangeException("No drive letters available"); + } + + return allDrivesLetters.First(); } } - public static void Mount(string volumeName, string mountPoint) + /// + /// On Windows, unassigns the specified virtual drive letter from its mounted folder. + /// + public static void DeleteVirtualDrive(char driveLetter) { + if (!OperatingSystem.IsWindows()) + { + throw new PlatformNotSupportedException(); + } + bool success = RunProcess(CreateProcessStartInfo("cmd", "/c", SubstPath, "/d", $"{driveLetter}:")); + if (!success || DriveInfo.GetDrives().Any(x => x.Name[0] == driveLetter)) + { + throw new InvalidOperationException($"Could not delete virtual drive {driveLetter}: with subst"); + } + } + + public static void Mount(string volumeName, string mountPoint) + { if (volumeName[volumeName.Length - 1] != Path.DirectorySeparatorChar) volumeName += Path.DirectorySeparatorChar; if (mountPoint[mountPoint.Length - 1] != Path.DirectorySeparatorChar) @@ -93,8 +149,47 @@ public static void Unmount(string mountPoint) throw new Exception(string.Format("Win32 error: {0}", Marshal.GetLastPInvokeError())); } + private static ProcessStartInfo CreateProcessStartInfo(string fileName, params string[] arguments) + { + var info = new ProcessStartInfo + { + FileName = fileName, + UseShellExecute = false, + RedirectStandardOutput = true + }; + + foreach (var argument in arguments) + { + info.ArgumentList.Add(argument); + } + + return info; + } + + private static bool RunProcess(ProcessStartInfo startInfo) + { + var process = Process.Start(startInfo); + process.WaitForExit(); + return process.ExitCode == 0; + } + + private static string SubstPath + { + get + { + if (!OperatingSystem.IsWindows()) + { + throw new PlatformNotSupportedException(); + } + + string systemRoot = Environment.GetEnvironmentVariable("SystemRoot") ?? @"C:\Windows"; + string system32 = Path.Join(systemRoot, "System32"); + return Path.Join(system32, "subst.exe"); + } + } + /// For standalone debugging help. Change Main0 to Main - public static void Main0(string[] args) + public static void Main0(string[] args) { try { diff --git a/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj b/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj index 736d3b1ee5654b..bb7cac297d73a3 100644 --- a/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj +++ b/src/libraries/System.IO.FileSystem/tests/System.IO.FileSystem.Tests.csproj @@ -1,4 +1,4 @@ - + true true @@ -80,9 +80,11 @@ + + @@ -211,8 +213,7 @@ - + diff --git a/src/libraries/System.IO.FileSystem/tests/VirtualDriveSymbolicLinks.Windows.cs b/src/libraries/System.IO.FileSystem/tests/VirtualDriveSymbolicLinks.Windows.cs new file mode 100644 index 00000000000000..d88425086b7024 --- /dev/null +++ b/src/libraries/System.IO.FileSystem/tests/VirtualDriveSymbolicLinks.Windows.cs @@ -0,0 +1,247 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +namespace System.IO.Tests +{ + // Need to reuse the same virtual drive for all the test methods. + // Creating and disposing one virtual drive per class achieves this. + [PlatformSpecific(TestPlatforms.Windows)] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsSubstAvailable))] + public class VirtualDrive_SymbolicLinks : BaseSymbolicLinks + { + protected override void Dispose(bool disposing) + { + try + { + if (VirtualDriveLetter != default) + { + MountHelper.DeleteVirtualDrive(VirtualDriveLetter); + Directory.Delete(VirtualDriveTargetDir, recursive: true); + } + } + catch { } // avoid exceptions on dispose + base.Dispose(disposing); + } + + [Theory] + // false, false, false, false // Target is not in virtual drive + // false, false, true, false // Target is not in virtual drive + [InlineData(false, true, false, true)] // Immediate target expected, target is in virtual drive + [InlineData(false, true, true, false)] // Final target expected, target is in virtual drive + // true, false, false, false // Target is not in virtual drive + // true, false, true, false // Target is not in virtual drive + [InlineData(true, true, false, true)] // Immediate target expected, target is in virtual drive + [InlineData(true, true, true, false)] // Final target expected, target is in virtual drive + public void VirtualDrive_SymbolicLinks_LinkAndTarget( + bool isLinkInVirtualDrive, + bool isTargetInVirtualDrive, + bool returnFinalTarget, + bool isExpectedTargetPathVirtual) + { + string linkExpectedFolderPath = GetVirtualOrRealPath(isLinkInVirtualDrive); + // File link + string fileLinkName = GetRandomLinkName(); + string fileLinkPath = Path.Join(linkExpectedFolderPath, fileLinkName); + // Directory link + string dirLinkName = GetRandomLinkName(); + string dirLinkPath = Path.Join(linkExpectedFolderPath, dirLinkName); + + string targetExpectedFolderPath = GetVirtualOrRealPath(isTargetInVirtualDrive); + // File target + string fileTargetFileName = GetRandomFileName(); + string fileTargetPath = Path.Join(targetExpectedFolderPath, fileTargetFileName); + // Directory target + string dirTargetFileName = GetRandomDirName(); + string dirTargetPath = Path.Join(targetExpectedFolderPath, dirTargetFileName); + + // Create targets + File.Create(fileTargetPath).Dispose(); + Directory.CreateDirectory(dirTargetPath); + + // Create links + FileInfo fileLinkInfo = new FileInfo(fileLinkPath); + fileLinkInfo.CreateAsSymbolicLink(fileTargetPath); + DirectoryInfo dirLinkInfo = new DirectoryInfo(dirLinkPath); + dirLinkInfo.CreateAsSymbolicLink(dirTargetPath); + + // The expected results depend on the target location and the value of returnFinalTarget + + // LinkTarget always retrieves the immediate target, so the expected value + // is always the path that was provided by the user for the target + + // Verify the LinkTarget values of the link infos + Assert.Equal(fileTargetPath, fileLinkInfo.LinkTarget); + Assert.Equal(dirTargetPath, dirLinkInfo.LinkTarget); + + // When the target is in a virtual drive, and returnFinalTarget is true, + // the expected target path is the real path, not the virtual path + string expectedTargetPath = GetVirtualOrRealPath(isExpectedTargetPathVirtual); + + string expectedTargetFileInfoFullName = Path.Join(expectedTargetPath, fileTargetFileName); + string expectedTargetDirectoryInfoFullName = Path.Join(expectedTargetPath, dirTargetFileName); + + // Verify target infos from link info instances + FileSystemInfo? targetFileInfoFromFileInfoLink = fileLinkInfo.ResolveLinkTarget(returnFinalTarget); + FileSystemInfo? targetDirInfoFromDirInfoLink = dirLinkInfo.ResolveLinkTarget(returnFinalTarget); + + Assert.True(targetFileInfoFromFileInfoLink is FileInfo); + Assert.True(targetDirInfoFromDirInfoLink is DirectoryInfo); + + Assert.Equal(expectedTargetFileInfoFullName, targetFileInfoFromFileInfoLink.FullName); + Assert.Equal(expectedTargetDirectoryInfoFullName, targetDirInfoFromDirInfoLink.FullName); + + // Verify targets infos via static methods + FileSystemInfo? targetFileInfoFromFile = File.ResolveLinkTarget(fileLinkPath, returnFinalTarget); + FileSystemInfo? targetFileInfoFromDirectory = Directory.ResolveLinkTarget(dirLinkPath, returnFinalTarget); + + Assert.True(targetFileInfoFromFile is FileInfo); + Assert.True(targetFileInfoFromDirectory is DirectoryInfo); + + Assert.Equal(expectedTargetFileInfoFullName, targetFileInfoFromFile.FullName); + Assert.Equal(expectedTargetDirectoryInfoFullName, targetFileInfoFromDirectory.FullName); + } + + + [Theory] + // false, false, false, false, false // Target is not in virtual drive + // false, false, false, true, false // Target is not in virtual drive + [InlineData(false, false, true, false, false)] // Immediate target expected, middle link is NOT in virtual drive + [InlineData(false, false, true, true, false)] // Final target expected, target is in virtual drive + // false, true, false, false, false // Target is not in virtual drive + // false, true, false, true, false // Target is not in virtual drive + [InlineData(false, true, true, false, true)] // Immediate target expected, target is in virtual drive + [InlineData(false, true, true, true, false)] // Final target expected, target is in virtual drive + // true, false, false, false, false // Target is not in virtual drive + // true, false, false, true, false // Target is not in virtual drive + [InlineData(true, false, true, false, false)] // Immediate target expected, middle link is NOT in virtual drive + [InlineData(true, false, true, true, false)] // Final target expected, target is in virtual drive + // true, true, false, false, false // Target is not in virtual drive + // true, true, false, true, false // Target is not in virtual drive + [InlineData(true, true, true, false, true)] // Immediate target expected, target is in virtual drive + [InlineData(true, true, true, true, false)] // Final target expected, target is in virtual drive + public void VirtualDrive_SymbolicLinks_WithIndirection( + bool isFirstLinkInVirtualDrive, + bool isMiddleLinkInVirtualDrive, + bool isTargetInVirtualDrive, + bool returnFinalTarget, + bool isExpectedTargetPathVirtual) + { + string firstLinkExpectedFolderPath = GetVirtualOrRealPath(isFirstLinkInVirtualDrive); + // File link + string fileLinkPath = Path.Join(firstLinkExpectedFolderPath, GetRandomLinkName()); + // Directory link + string dirLinkPath = Path.Join(firstLinkExpectedFolderPath, GetRandomLinkName()); + + string middleLinkExpectedFolderPath = GetVirtualOrRealPath(isMiddleLinkInVirtualDrive); + // File middle link + string fileMiddleLinkFileName = GetRandomLinkName(); + string fileMiddleLinkPath = Path.Join(middleLinkExpectedFolderPath, fileMiddleLinkFileName); + // Directory middle link + string dirMiddleLinkFileName = GetRandomLinkName(); + string dirMiddleLinkPath = Path.Join(middleLinkExpectedFolderPath, dirMiddleLinkFileName); + + string targetExpectedFolderPath = GetVirtualOrRealPath(isTargetInVirtualDrive); + // File final target + string fileFinalTargetFileName = GetRandomFileName(); + string fileFinalTargetPath = Path.Join(targetExpectedFolderPath, fileFinalTargetFileName); + // Directory final target + string dirFinalTargetFileName = GetRandomDirName(); + string dirFinalTargetPath = Path.Join(targetExpectedFolderPath, dirFinalTargetFileName); + + // Create targets + File.Create(fileFinalTargetPath).Dispose(); + Directory.CreateDirectory(dirFinalTargetPath); + + // Create initial links + FileInfo fileLinkInfo = new FileInfo(fileLinkPath); + fileLinkInfo.CreateAsSymbolicLink(fileMiddleLinkPath); + + DirectoryInfo dirLinkInfo = new DirectoryInfo(dirLinkPath); + dirLinkInfo.CreateAsSymbolicLink(dirMiddleLinkPath); + + // Create middle links + FileInfo fileMiddleLinkInfo = new FileInfo(fileMiddleLinkPath); + fileMiddleLinkInfo.CreateAsSymbolicLink(fileFinalTargetPath); + + DirectoryInfo dirMiddleLinkInfo = new DirectoryInfo(dirMiddleLinkPath); + dirMiddleLinkInfo.CreateAsSymbolicLink(dirFinalTargetPath); + + // The expected results depend on the target location and the value of returnFinalTarget + + // LinkTarget always retrieves the immediate target, so the expected value + // is always the path that was provided by the user for the middle link + + // Verify the LinkTarget values of the link infos + Assert.Equal(fileMiddleLinkPath, fileLinkInfo.LinkTarget); + Assert.Equal(dirMiddleLinkPath, dirLinkInfo.LinkTarget); + + // When the target is in a virtual drive, + // the expected target path is the real path, not the virtual path + // When returnFinalTarget is true, the expected target path is the + // resolved path from the final target in the chain of links + string expectedTargetPath = GetVirtualOrRealPath(isExpectedTargetPathVirtual); + + string expectedTargetFileInfoFullName = Path.Join(expectedTargetPath, + returnFinalTarget ? fileFinalTargetFileName : fileMiddleLinkFileName); + + string expectedTargetDirectoryInfoFullName = Path.Join(expectedTargetPath, + returnFinalTarget ? dirFinalTargetFileName : dirMiddleLinkFileName); + + // Verify target infos from link info instances + FileSystemInfo? targetFileInfoFromFileInfoLink = fileLinkInfo.ResolveLinkTarget(returnFinalTarget); + FileSystemInfo? targetDirInfoFromDirInfoLink = dirLinkInfo.ResolveLinkTarget(returnFinalTarget); + + Assert.True(targetFileInfoFromFileInfoLink is FileInfo); + Assert.True(targetDirInfoFromDirInfoLink is DirectoryInfo); + + Assert.Equal(expectedTargetFileInfoFullName, targetFileInfoFromFileInfoLink.FullName); + Assert.Equal(expectedTargetDirectoryInfoFullName, targetDirInfoFromDirInfoLink.FullName); + + // Verify targets infos via static methods + FileSystemInfo? targetFileInfoFromFile = File.ResolveLinkTarget(fileLinkPath, returnFinalTarget); + FileSystemInfo? targetFileInfoFromDirectory = Directory.ResolveLinkTarget(dirLinkPath, returnFinalTarget); + + Assert.True(targetFileInfoFromFile is FileInfo); + Assert.True(targetFileInfoFromDirectory is DirectoryInfo); + + Assert.Equal(expectedTargetFileInfoFullName, targetFileInfoFromFile.FullName); + Assert.Equal(expectedTargetDirectoryInfoFullName, targetFileInfoFromDirectory.FullName); + } + + private string GetVirtualOrRealPath(bool condition) => condition ? $"{VirtualDriveLetter}:" : VirtualDriveTargetDir; + + // Temporary Windows directory that can be mounted to a drive letter using the subst command + private string? _virtualDriveTargetDir = null; + private string VirtualDriveTargetDir + { + get + { + if (_virtualDriveTargetDir == null) + { + // Create a folder inside the temp directory so that it can be mounted to a drive letter with subst + _virtualDriveTargetDir = Path.Join(Path.GetTempPath(), GetRandomDirName()); + Directory.CreateDirectory(_virtualDriveTargetDir); + } + + return _virtualDriveTargetDir; + } + } + + // Windows drive letter that points to a mounted directory using the subst command + private char _virtualDriveLetter = default; + private char VirtualDriveLetter + { + get + { + if (_virtualDriveLetter == default) + { + // Mount the folder to a drive letter + _virtualDriveLetter = MountHelper.CreateVirtualDrive(VirtualDriveTargetDir); + } + return _virtualDriveLetter; + } + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs index b92de0ad38ae9b..d2bde47c3134b6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileSystem.Windows.cs @@ -499,32 +499,48 @@ internal static void CreateSymbolicLink(string path, string pathToTarget, bool i } Span bufferSpan = new(buffer); - success = MemoryMarshal.TryRead(bufferSpan, out Interop.Kernel32.REPARSE_DATA_BUFFER rdb); + success = MemoryMarshal.TryRead(bufferSpan, out Interop.Kernel32.SymbolicLinkReparseBuffer rbSymlink); Debug.Assert(success); - // Only symbolic links are supported at the moment. - if ((rdb.ReparseTag & Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK) == 0) - { - return null; - } - - // We use PrintName instead of SubstitutneName given that we don't want to return a NT path when the link wasn't created with such NT path. + // We use PrintName(Offset|Length) instead of SubstituteName(Offset|Length) given that we don't want to return + // an NT path when the link wasn't created with such NT path. // Unlike SubstituteName and GetFinalPathNameByHandle(), PrintName doesn't start with a prefix. // Another nuance is that SubstituteName does not contain redundant path segments while PrintName does. - // PrintName can ONLY return a NT path if the link was created explicitly targeting a file/folder in such way. e.g: mklink /D linkName \??\C:\path\to\target. - int printNameNameOffset = sizeof(Interop.Kernel32.REPARSE_DATA_BUFFER) + rdb.ReparseBufferSymbolicLink.PrintNameOffset; - int printNameNameLength = rdb.ReparseBufferSymbolicLink.PrintNameLength; + // PrintName can ONLY return a NT path if the link was created explicitly targeting a file/folder in such way. + // e.g: mklink /D linkName \??\C:\path\to\target. + + if (rbSymlink.ReparseTag == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK) + { + int printNameOffset = sizeof(Interop.Kernel32.SymbolicLinkReparseBuffer) + rbSymlink.PrintNameOffset; + int printNameLength = rbSymlink.PrintNameLength; + + Span targetPath = MemoryMarshal.Cast(bufferSpan.Slice(printNameOffset, printNameLength)); + Debug.Assert((rbSymlink.Flags & Interop.Kernel32.SYMLINK_FLAG_RELATIVE) == 0 || !PathInternal.IsExtended(targetPath)); - Span targetPath = MemoryMarshal.Cast(bufferSpan.Slice(printNameNameOffset, printNameNameLength)); - Debug.Assert((rdb.ReparseBufferSymbolicLink.Flags & Interop.Kernel32.SYMLINK_FLAG_RELATIVE) == 0 || !PathInternal.IsExtended(targetPath)); + if (returnFullPath && (rbSymlink.Flags & Interop.Kernel32.SYMLINK_FLAG_RELATIVE) != 0) + { + // Target path is relative and is for ResolveLinkTarget(), we need to append the link directory. + return Path.Join(Path.GetDirectoryName(linkPath.AsSpan()), targetPath); + } - if (returnFullPath && (rdb.ReparseBufferSymbolicLink.Flags & Interop.Kernel32.SYMLINK_FLAG_RELATIVE) != 0) + return targetPath.ToString(); + } + else if (rbSymlink.ReparseTag == Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT) { - // Target path is relative and is for ResolveLinkTarget(), we need to append the link directory. - return Path.Join(Path.GetDirectoryName(linkPath.AsSpan()), targetPath); + success = MemoryMarshal.TryRead(bufferSpan, out Interop.Kernel32.MountPointReparseBuffer rbMountPoint); + Debug.Assert(success); + + int printNameOffset = sizeof(Interop.Kernel32.MountPointReparseBuffer) + rbMountPoint.PrintNameOffset; + int printNameLength = rbMountPoint.PrintNameLength; + + Span targetPath = MemoryMarshal.Cast(bufferSpan.Slice(printNameOffset, printNameLength)); + + // Unlike symlinks, mount point paths cannot be relative + Debug.Assert(!PathInternal.IsPartiallyQualified(targetPath)); + return targetPath.ToString(); } - return targetPath.ToString(); + return null; } finally { @@ -539,8 +555,9 @@ internal static void CreateSymbolicLink(string path, string pathToTarget, bool i // The file or directory is not a reparse point. if ((data.dwFileAttributes & (uint)FileAttributes.ReparsePoint) == 0 || - // Only symbolic links are supported at the moment. - (data.dwReserved0 & Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK) == 0) + // Only symbolic links and mount points are supported at the moment. + ((data.dwReserved0 & Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_SYMLINK) == 0 && + (data.dwReserved0 & Interop.Kernel32.IOReparseOptions.IO_REPARSE_TAG_MOUNT_POINT) == 0)) { return null; } From 38e07e093e59fc48314dd763bcd0af1b4378dee6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 30 Aug 2021 10:57:32 +0200 Subject: [PATCH 09/13] [release/6.0-rc1] Update dependencies from dotnet/emsdk (#58316) * Update dependencies from https://github.com/dotnet/emsdk build 20210828.2 Microsoft.NET.Workload.Emscripten.Manifest-6.0.100 From Version 6.0.0-rc.1.21419.1 -> To Version 6.0.0-rc.1.21428.2 * Update dependencies from https://github.com/dotnet/emsdk build 20210829.1 Microsoft.NET.Workload.Emscripten.Manifest-6.0.100 From Version 6.0.0-rc.1.21419.1 -> To Version 6.0.0-rc.1.21429.1 Co-authored-by: dotnet-maestro[bot] --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 617ceb00112203..3313817ee2d406 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -8,9 +8,9 @@ https://github.com/dotnet/msquic 98129287d56a5e0348c291ce4260e630b4aa510d - + https://github.com/dotnet/emsdk - 74f858629aef569bf3b70b88183dca2ba2c2ad4e + 56ec8558558b3ed7b7fcf788ecf601e3230cc688 diff --git a/eng/Versions.props b/eng/Versions.props index a86e7cc942f824..38d8a7638d780e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -183,7 +183,7 @@ 11.1.0-alpha.1.21416.1 11.1.0-alpha.1.21416.1 - 6.0.0-rc.1.21419.1 + 6.0.0-rc.1.21429.1 $(MicrosoftNETWorkloadEmscriptenManifest60100Version) 1.1.87-gba258badda From 3f01d85ad81c01f9aea1ae5e23e77e17f0fd786d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 30 Aug 2021 10:59:29 +0200 Subject: [PATCH 10/13] [release/6.0-rc1] Update dependencies from dotnet/arcade (#58315) * Update dependencies from https://github.com/dotnet/arcade build 20210827.6 Microsoft.DotNet.XUnitExtensions , Microsoft.DotNet.VersionTools.Tasks , Microsoft.DotNet.Build.Tasks.Workloads , Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk , Microsoft.DotNet.Build.Tasks.Packaging , Microsoft.DotNet.Build.Tasks.Installers , Microsoft.DotNet.Build.Tasks.Feed , Microsoft.DotNet.Build.Tasks.Archives , Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.ApiCompat , Microsoft.DotNet.CodeAnalysis , Microsoft.DotNet.XUnitConsoleRunner , Microsoft.DotNet.GenFacades , Microsoft.DotNet.GenAPI , Microsoft.DotNet.RemoteExecutor , Microsoft.DotNet.PackageTesting , Microsoft.DotNet.Helix.Sdk , Microsoft.DotNet.SharedFramework.Sdk From Version 6.0.0-beta.21418.12 -> To Version 6.0.0-beta.21427.6 * Fix IDE0062 warning in NumberFormatInfo.cs Co-authored-by: dotnet-maestro[bot] Co-authored-by: Stephen Toub --- eng/Version.Details.xml | 72 +++++++++---------- eng/Versions.props | 28 ++++---- eng/common/build.sh | 5 +- eng/common/init-tools-native.sh | 2 +- eng/common/native/common-library.sh | 8 ++- .../post-build/sourcelink-validation.ps1 | 8 ++- eng/common/sdk-task.ps1 | 4 +- eng/common/templates/job/job.yml | 2 +- eng/common/tools.ps1 | 6 +- eng/common/tools.sh | 2 +- global.json | 8 +-- .../System/Globalization/NumberFormatInfo.cs | 8 +-- 12 files changed, 83 insertions(+), 70 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3313817ee2d406..8ae02260a1959a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,73 +14,73 @@ - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 https://github.com/microsoft/vstest @@ -202,9 +202,9 @@ https://github.com/dotnet/xharness e9669dc84ecd668d3bbb748758103e23b394ffef - + https://github.com/dotnet/arcade - ac8b7514ca8bcac1d071a16b7a92cb52f7058871 + 474307e526160c813c9fd58060eb8356ccca6099 https://dev.azure.com/dnceng/internal/_git/dotnet-optimization diff --git a/eng/Versions.props b/eng/Versions.props index 38d8a7638d780e..3f0a77ccbfde0e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -52,20 +52,20 @@ 1.0.0-rc.1.21404.21 - 6.0.0-beta.21418.12 - 6.0.0-beta.21418.12 - 6.0.0-beta.21418.12 - 6.0.0-beta.21418.12 - 6.0.0-beta.21418.12 - 6.0.0-beta.21418.12 - 2.5.1-beta.21418.12 - 6.0.0-beta.21418.12 - 6.0.0-beta.21418.12 - 6.0.0-beta.21418.12 - 6.0.0-beta.21418.12 - 6.0.0-beta.21418.12 - 6.0.0-beta.21418.12 - 6.0.0-beta.21418.12 + 6.0.0-beta.21427.6 + 6.0.0-beta.21427.6 + 6.0.0-beta.21427.6 + 6.0.0-beta.21427.6 + 6.0.0-beta.21427.6 + 6.0.0-beta.21427.6 + 2.5.1-beta.21427.6 + 6.0.0-beta.21427.6 + 6.0.0-beta.21427.6 + 6.0.0-beta.21427.6 + 6.0.0-beta.21427.6 + 6.0.0-beta.21427.6 + 6.0.0-beta.21427.6 + 6.0.0-beta.21427.6 6.0.0-preview.1.102 diff --git a/eng/common/build.sh b/eng/common/build.sh index 9d3042a943e4cf..bc07a1c6848243 100755 --- a/eng/common/build.sh +++ b/eng/common/build.sh @@ -187,7 +187,10 @@ function InitializeCustomToolset { } function Build { - TryLogClientIpAddress + + if [[ "$ci" == true ]]; then + TryLogClientIpAddress + fi InitializeToolset InitializeCustomToolset diff --git a/eng/common/init-tools-native.sh b/eng/common/init-tools-native.sh index 5bd205b5da3b79..3e6a8d6acf2f57 100755 --- a/eng/common/init-tools-native.sh +++ b/eng/common/init-tools-native.sh @@ -10,7 +10,7 @@ force=false download_retries=5 retry_wait_time_seconds=30 global_json_file="$(dirname "$(dirname "${scriptroot}")")/global.json" -declare -A native_assets +declare -a native_assets . $scriptroot/pipeline-logging-functions.sh . $scriptroot/native/common-library.sh diff --git a/eng/common/native/common-library.sh b/eng/common/native/common-library.sh index bf272dcf55a538..080c2c283ae468 100755 --- a/eng/common/native/common-library.sh +++ b/eng/common/native/common-library.sh @@ -148,8 +148,12 @@ function NewScriptShim { fi if [[ ! -f $tool_file_path ]]; then - Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Specified tool file path:'$tool_file_path' does not exist" - return 1 + # try to see if the path is lower cased + tool_file_path="$(echo $tool_file_path | tr "[:upper:]" "[:lower:]")" + if [[ ! -f $tool_file_path ]]; then + Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Specified tool file path:'$tool_file_path' does not exist" + return 1 + fi fi local shim_contents=$'#!/usr/bin/env bash\n' diff --git a/eng/common/post-build/sourcelink-validation.ps1 b/eng/common/post-build/sourcelink-validation.ps1 index 3b6fc953337362..e8ab29afeb3330 100644 --- a/eng/common/post-build/sourcelink-validation.ps1 +++ b/eng/common/post-build/sourcelink-validation.ps1 @@ -107,8 +107,12 @@ $ValidatePackage = { try { $Uri = $Link -as [System.URI] - # Only GitHub links are valid - if ($Uri.AbsoluteURI -ne $null -and ($Uri.Host -match 'github' -or $Uri.Host -match 'githubusercontent')) { + if ($Link -match "submodules") { + # Skip submodule links until sourcelink properly handles submodules + $Status = 200 + } + elseif ($Uri.AbsoluteURI -ne $null -and ($Uri.Host -match 'github' -or $Uri.Host -match 'githubusercontent')) { + # Only GitHub links are valid $Status = (Invoke-WebRequest -Uri $Link -UseBasicParsing -Method HEAD -TimeoutSec 5).StatusCode } else { diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1 index 7ffa3591e9ca0c..7ab9baac5c8d9a 100644 --- a/eng/common/sdk-task.ps1 +++ b/eng/common/sdk-task.ps1 @@ -83,7 +83,9 @@ try { } if ($restore) { - Try-LogClientIpAddress + if ($ci) { + Try-LogClientIpAddress + } Build 'Restore' } diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml index 8669679348024c..37dceb1bab0a93 100644 --- a/eng/common/templates/job/job.yml +++ b/eng/common/templates/job/job.yml @@ -103,7 +103,7 @@ jobs: - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - ${{ if eq(parameters.enableMicrobuild, 'true') }}: - - task: MicroBuildSigningPlugin@2 + - task: MicroBuildSigningPlugin@3 displayName: Install MicroBuild plugin inputs: signType: $(_SignType) diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index e607aa43697623..56ee4a577acab4 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -154,9 +154,6 @@ function InitializeDotNetCli([bool]$install, [bool]$createSdkLocationFile) { return $global:_DotNetInstallDir } - # In case of network error, try to log the current IP for reference - Try-LogClientIpAddress - # Don't resolve runtime, shared framework, or SDK from other locations to ensure build determinism $env:DOTNET_MULTILEVEL_LOOKUP=0 @@ -166,6 +163,9 @@ function InitializeDotNetCli([bool]$install, [bool]$createSdkLocationFile) { # Disable telemetry on CI. if ($ci) { $env:DOTNET_CLI_TELEMETRY_OPTOUT=1 + + # In case of network error, try to log the current IP for reference + Try-LogClientIpAddress } # Source Build uses DotNetCoreSdkDir variable diff --git a/eng/common/tools.sh b/eng/common/tools.sh index 3c5f3a12c0a6ed..41e323104df468 100755 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -402,7 +402,7 @@ function StopProcesses { function TryLogClientIpAddress () { echo 'Attempting to log this client''s IP for Azure Package feed telemetry purposes' if command -v curl > /dev/null; then - curl -s 'http://co1.msedge.net/fdv2/diagnostics.aspx' | grep ' IP: ' + curl -s 'http://co1.msedge.net/fdv2/diagnostics.aspx' | grep ' IP: ' || true fi } diff --git a/global.json b/global.json index 194c494ce541c0..103cec939e94b6 100644 --- a/global.json +++ b/global.json @@ -12,10 +12,10 @@ "python3": "3.7.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "6.0.0-beta.21418.12", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21418.12", - "Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.21418.12", - "Microsoft.DotNet.SharedFramework.Sdk": "6.0.0-beta.21418.12", + "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "6.0.0-beta.21427.6", + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21427.6", + "Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.21427.6", + "Microsoft.DotNet.SharedFramework.Sdk": "6.0.0-beta.21427.6", "Microsoft.Build.NoTargets": "3.1.0", "Microsoft.Build.Traversal": "3.0.23", "Microsoft.NET.Sdk.IL": "6.0.0-rc.1.21415.6" diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs index ee7c38e7777cfd..931e4b62e5a178 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/NumberFormatInfo.cs @@ -733,9 +733,9 @@ internal static void ValidateParseStyleInteger(NumberStyles style) if ((style & (InvalidNumberStyles | NumberStyles.AllowHexSpecifier)) != 0 && (style & ~NumberStyles.HexNumber) != 0) { - throwInvalid(style); + ThrowInvalid(style); - void throwInvalid(NumberStyles value) + static void ThrowInvalid(NumberStyles value) { if ((value & InvalidNumberStyles) != 0) { @@ -752,9 +752,9 @@ internal static void ValidateParseStyleFloatingPoint(NumberStyles style) // Check for undefined flags or hex number if ((style & (InvalidNumberStyles | NumberStyles.AllowHexSpecifier)) != 0) { - throwInvalid(style); + ThrowInvalid(style); - void throwInvalid(NumberStyles value) + static void ThrowInvalid(NumberStyles value) { if ((value & InvalidNumberStyles) != 0) { From 97b275994f37229effe538657a3bc6415af7c2e9 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 30 Aug 2021 14:32:44 +0200 Subject: [PATCH 11/13] Update Version.Details.xml --- eng/Version.Details.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4d0c1f37396749..f64a233da042a0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -8,9 +8,9 @@ https://github.com/dotnet/msquic 98129287d56a5e0348c291ce4260e630b4aa510d - + https://github.com/dotnet/emsdk - 56ec8558558b3ed7b7fcf788ecf601e3230cc688 + 416c127a39ed01b226b399bdc4c1d5e522578fe0 From ed2bbbfb9139d08817049ab5e027792ef57ca1af Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 30 Aug 2021 14:33:14 +0200 Subject: [PATCH 12/13] Update Versions.props --- eng/Versions.props | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index 86612b49119cd6..b5f9bf84e53bcc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,7 +24,8 @@ - 6.0.0-rc.1.21429.1 + 6.0.0-rc.2.21425.6 $(MicrosoftNETWorkloadEmscriptenManifest60100Version) 1.1.87-gba258badda From a7cb9f5f20fc0ca82c33c82e5d8757e9b0ff4610 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Mon, 30 Aug 2021 14:34:41 +0200 Subject: [PATCH 13/13] Update Versions.props --- eng/Versions.props | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index b5f9bf84e53bcc..c569074e9d42b6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -24,8 +24,7 @@