diff --git a/AspNetCore.sln b/AspNetCore.sln
index 0b72d2764f98..35ee80f4e8b3 100644
--- a/AspNetCore.sln
+++ b/AspNetCore.sln
@@ -1033,12 +1033,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Language.Test", "src\Razor\Microsoft.AspNetCore.Razor.Language\test\Microsoft.AspNetCore.Razor.Language.Test.csproj", "{313ADEF5-5A2D-4C11-8655-E227445144E2}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.AspNetCore.Razor.Tools", "Microsoft.AspNetCore.Razor.Tools", "{B9704650-5360-416C-9393-FAF707766AA8}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "rzc", "src\Razor\Microsoft.AspNetCore.Razor.Tools\src\rzc.csproj", "{4C84173F-5C1F-49A1-895A-C0CA11DE84B1}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Tools.Test", "src\Razor\Microsoft.AspNetCore.Razor.Tools\test\Microsoft.AspNetCore.Razor.Tools.Test.csproj", "{FE095F11-4CD2-406D-A2BB-1BE569603BF0}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.CodeAnalysis.Razor", "Microsoft.CodeAnalysis.Razor", "{3854EA4A-5530-4FEC-971E-B0CB45C5B19D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor", "src\Razor\Microsoft.CodeAnalysis.Razor\src\Microsoft.CodeAnalysis.Razor.csproj", "{AE06A841-F90D-486A-9DEF-70495DF4D28A}"
@@ -1055,12 +1049,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "perf", "perf", "{D510860C-B
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Performance", "src\Razor\perf\Microsoft.AspNetCore.Razor.Performance\Microsoft.AspNetCore.Razor.Performance.csproj", "{8ED505A5-A33A-401E-89BA-3AED7B73DD6A}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.NET.Sdk.Razor", "Microsoft.NET.Sdk.Razor", "{DA9E1AB0-0094-4777-BF3F-BC5596C3CDA9}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.Razor", "src\Razor\Microsoft.NET.Sdk.Razor\src\Microsoft.NET.Sdk.Razor.csproj", "{44B3F6C4-0F65-4649-B4CF-6CDC2094E061}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.Razor.Test", "src\Razor\Microsoft.NET.Sdk.Razor\test\Microsoft.NET.Sdk.Razor.Test.csproj", "{7CB23DCD-B416-4293-9848-224077F9E71D}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{06C916C7-67BF-45DC-9D0B-CEEF0C731451}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Test.Common", "src\Razor\test\Microsoft.AspNetCore.Razor.Test.Common\Microsoft.AspNetCore.Razor.Test.Common.csproj", "{69637901-CAD7-4335-81F4-92E03C4DA354}"
@@ -1075,8 +1063,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Test.MvcShim.Version2_X", "src\Razor\test\Microsoft.AspNetCore.Razor.Test.MvcShim.Version2_X\Microsoft.AspNetCore.Razor.Test.MvcShim.Version2_X.csproj", "{2A3B2388-F9F3-4F28-B008-2CD7862A86C4}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.Razor.IntegrationTests", "src\Razor\Microsoft.NET.Sdk.Razor\integrationtests\Microsoft.NET.Sdk.Razor.IntegrationTests.csproj", "{930CB054-3E69-4721-9F7E-01FB911AAF6A}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{CF9D35EC-CA9B-481D-BAAC-5D4654732AB9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthSamples.FunctionalTests", "src\Security\test\AuthSamples.FunctionalTests\AuthSamples.FunctionalTests.csproj", "{31B7D2B1-47AF-432B-BF07-73916EF238EE}"
@@ -5269,30 +5255,6 @@ Global
{313ADEF5-5A2D-4C11-8655-E227445144E2}.Release|x64.Build.0 = Release|Any CPU
{313ADEF5-5A2D-4C11-8655-E227445144E2}.Release|x86.ActiveCfg = Release|Any CPU
{313ADEF5-5A2D-4C11-8655-E227445144E2}.Release|x86.Build.0 = Release|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Debug|x64.ActiveCfg = Debug|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Debug|x64.Build.0 = Debug|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Debug|x86.ActiveCfg = Debug|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Debug|x86.Build.0 = Debug|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Release|Any CPU.Build.0 = Release|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Release|x64.ActiveCfg = Release|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Release|x64.Build.0 = Release|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Release|x86.ActiveCfg = Release|Any CPU
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1}.Release|x86.Build.0 = Release|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Debug|x64.ActiveCfg = Debug|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Debug|x64.Build.0 = Debug|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Debug|x86.ActiveCfg = Debug|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Debug|x86.Build.0 = Debug|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Release|Any CPU.Build.0 = Release|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Release|x64.ActiveCfg = Release|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Release|x64.Build.0 = Release|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Release|x86.ActiveCfg = Release|Any CPU
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0}.Release|x86.Build.0 = Release|Any CPU
{AE06A841-F90D-486A-9DEF-70495DF4D28A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AE06A841-F90D-486A-9DEF-70495DF4D28A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE06A841-F90D-486A-9DEF-70495DF4D28A}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -5353,30 +5315,6 @@ Global
{8ED505A5-A33A-401E-89BA-3AED7B73DD6A}.Release|x64.Build.0 = Release|Any CPU
{8ED505A5-A33A-401E-89BA-3AED7B73DD6A}.Release|x86.ActiveCfg = Release|Any CPU
{8ED505A5-A33A-401E-89BA-3AED7B73DD6A}.Release|x86.Build.0 = Release|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Debug|x64.ActiveCfg = Debug|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Debug|x64.Build.0 = Debug|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Debug|x86.ActiveCfg = Debug|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Debug|x86.Build.0 = Debug|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Release|Any CPU.Build.0 = Release|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Release|x64.ActiveCfg = Release|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Release|x64.Build.0 = Release|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Release|x86.ActiveCfg = Release|Any CPU
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061}.Release|x86.Build.0 = Release|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Debug|x64.ActiveCfg = Debug|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Debug|x64.Build.0 = Debug|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Debug|x86.ActiveCfg = Debug|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Debug|x86.Build.0 = Debug|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Release|Any CPU.Build.0 = Release|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Release|x64.ActiveCfg = Release|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Release|x64.Build.0 = Release|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Release|x86.ActiveCfg = Release|Any CPU
- {7CB23DCD-B416-4293-9848-224077F9E71D}.Release|x86.Build.0 = Release|Any CPU
{69637901-CAD7-4335-81F4-92E03C4DA354}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{69637901-CAD7-4335-81F4-92E03C4DA354}.Debug|Any CPU.Build.0 = Debug|Any CPU
{69637901-CAD7-4335-81F4-92E03C4DA354}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -5449,18 +5387,6 @@ Global
{2A3B2388-F9F3-4F28-B008-2CD7862A86C4}.Release|x64.Build.0 = Release|Any CPU
{2A3B2388-F9F3-4F28-B008-2CD7862A86C4}.Release|x86.ActiveCfg = Release|Any CPU
{2A3B2388-F9F3-4F28-B008-2CD7862A86C4}.Release|x86.Build.0 = Release|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Debug|x64.ActiveCfg = Debug|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Debug|x64.Build.0 = Debug|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Debug|x86.ActiveCfg = Debug|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Debug|x86.Build.0 = Debug|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Release|Any CPU.Build.0 = Release|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Release|x64.ActiveCfg = Release|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Release|x64.Build.0 = Release|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Release|x86.ActiveCfg = Release|Any CPU
- {930CB054-3E69-4721-9F7E-01FB911AAF6A}.Release|x86.Build.0 = Release|Any CPU
{31B7D2B1-47AF-432B-BF07-73916EF238EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{31B7D2B1-47AF-432B-BF07-73916EF238EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31B7D2B1-47AF-432B-BF07-73916EF238EE}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -7991,9 +7917,6 @@ Global
{1CBCF1F9-D90D-484E-A2E9-FD4E4174C05E} = {B27FBAC2-ADA3-4A05-B232-64011B6B2DA3}
{A6323D64-C883-46B6-BDA9-916009D44262} = {1CBCF1F9-D90D-484E-A2E9-FD4E4174C05E}
{313ADEF5-5A2D-4C11-8655-E227445144E2} = {1CBCF1F9-D90D-484E-A2E9-FD4E4174C05E}
- {B9704650-5360-416C-9393-FAF707766AA8} = {B27FBAC2-ADA3-4A05-B232-64011B6B2DA3}
- {4C84173F-5C1F-49A1-895A-C0CA11DE84B1} = {B9704650-5360-416C-9393-FAF707766AA8}
- {FE095F11-4CD2-406D-A2BB-1BE569603BF0} = {B9704650-5360-416C-9393-FAF707766AA8}
{3854EA4A-5530-4FEC-971E-B0CB45C5B19D} = {B27FBAC2-ADA3-4A05-B232-64011B6B2DA3}
{AE06A841-F90D-486A-9DEF-70495DF4D28A} = {3854EA4A-5530-4FEC-971E-B0CB45C5B19D}
{91A6A69B-21B4-4B05-B188-D0551573DD9B} = {3854EA4A-5530-4FEC-971E-B0CB45C5B19D}
@@ -8002,9 +7925,6 @@ Global
{8B37B987-B7A2-4A26-8CF1-7AC1E9FA7ADC} = {F6E6A63A-45BE-46BF-B9B4-DA3DDC8FE4B5}
{D510860C-B2DA-41D3-9137-81B029312E71} = {B27FBAC2-ADA3-4A05-B232-64011B6B2DA3}
{8ED505A5-A33A-401E-89BA-3AED7B73DD6A} = {D510860C-B2DA-41D3-9137-81B029312E71}
- {DA9E1AB0-0094-4777-BF3F-BC5596C3CDA9} = {B27FBAC2-ADA3-4A05-B232-64011B6B2DA3}
- {44B3F6C4-0F65-4649-B4CF-6CDC2094E061} = {DA9E1AB0-0094-4777-BF3F-BC5596C3CDA9}
- {7CB23DCD-B416-4293-9848-224077F9E71D} = {DA9E1AB0-0094-4777-BF3F-BC5596C3CDA9}
{06C916C7-67BF-45DC-9D0B-CEEF0C731451} = {B27FBAC2-ADA3-4A05-B232-64011B6B2DA3}
{69637901-CAD7-4335-81F4-92E03C4DA354} = {06C916C7-67BF-45DC-9D0B-CEEF0C731451}
{ED060C25-B7B2-414B-BDC7-A77FA0269C9F} = {06C916C7-67BF-45DC-9D0B-CEEF0C731451}
@@ -8012,7 +7932,6 @@ Global
{F8111E2B-650F-4A9A-9834-234B5F5DD79D} = {06C916C7-67BF-45DC-9D0B-CEEF0C731451}
{302EC23A-FD11-4F56-B3E9-0DEC7C177584} = {06C916C7-67BF-45DC-9D0B-CEEF0C731451}
{2A3B2388-F9F3-4F28-B008-2CD7862A86C4} = {06C916C7-67BF-45DC-9D0B-CEEF0C731451}
- {930CB054-3E69-4721-9F7E-01FB911AAF6A} = {DA9E1AB0-0094-4777-BF3F-BC5596C3CDA9}
{CF9D35EC-CA9B-481D-BAAC-5D4654732AB9} = {A39335E5-7A26-4CFD-BF3B-2CFE75113498}
{31B7D2B1-47AF-432B-BF07-73916EF238EE} = {CF9D35EC-CA9B-481D-BAAC-5D4654732AB9}
{C75B1FB3-6BB7-411A-B76C-06E5E0C3D957} = {A39335E5-7A26-4CFD-BF3B-2CFE75113498}
diff --git a/eng/ProjectReferences.props b/eng/ProjectReferences.props
index faf2d177965d..c3889fa6050a 100644
--- a/eng/ProjectReferences.props
+++ b/eng/ProjectReferences.props
@@ -101,9 +101,7 @@
-
-
diff --git a/eng/targets/CSharp.Common.props b/eng/targets/CSharp.Common.props
index 08e32152ae87..f6aee12dd4f2 100644
--- a/eng/targets/CSharp.Common.props
+++ b/eng/targets/CSharp.Common.props
@@ -12,30 +12,6 @@
-
- <_ReferenceLocalRazorSDK
- Condition="'$(UsingMicrosoftNETSdkWeb)' == 'true' OR '$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true' OR '$(RazorSdkCurrentVersionProps)' != '' OR '$(_RazorSdkImportsMicrosoftNetSdk)' == 'true'">true
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/eng/targets/GetRazorSDKDirectory.props b/eng/targets/GetRazorSDKDirectory.props
deleted file mode 100644
index 7089256236a1..000000000000
--- a/eng/targets/GetRazorSDKDirectory.props
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- $(ArtifactsBinDir)Microsoft.NET.Sdk.Razor\$(Configuration)\sdk-output\
-
-
\ No newline at end of file
diff --git a/global.json b/global.json
index bad2eec167f4..1e182bd10924 100644
--- a/global.json
+++ b/global.json
@@ -1,9 +1,9 @@
{
"sdk": {
- "version": "6.0.100-alpha.1.21063.4"
+ "version": "6.0.100-preview.1.21073.4"
},
"tools": {
- "dotnet": "6.0.100-alpha.1.21063.4",
+ "dotnet": "6.0.100-preview.1.21073.4",
"runtimes": {
"dotnet/x64": [
"2.1.23",
diff --git a/src/Framework/Framework.slnf b/src/Framework/Framework.slnf
index 542719a43272..93da2b67950f 100644
--- a/src/Framework/Framework.slnf
+++ b/src/Framework/Framework.slnf
@@ -73,9 +73,7 @@
"src\\ObjectPool\\src\\Microsoft.Extensions.ObjectPool.csproj",
"src\\Razor\\Microsoft.AspNetCore.Mvc.Razor.Extensions\\src\\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj",
"src\\Razor\\Microsoft.AspNetCore.Razor.Language\\src\\Microsoft.AspNetCore.Razor.Language.csproj",
- "src\\Razor\\Microsoft.AspNetCore.Razor.Tools\\src\\rzc.csproj",
"src\\Razor\\Microsoft.CodeAnalysis.Razor\\src\\Microsoft.CodeAnalysis.Razor.csproj",
- "src\\Razor\\Microsoft.NET.Sdk.Razor\\src\\Microsoft.NET.Sdk.Razor.csproj",
"src\\Razor\\Razor.Runtime\\src\\Microsoft.AspNetCore.Razor.Runtime.csproj",
"src\\Razor\\Razor\\src\\Microsoft.AspNetCore.Razor.csproj",
"src\\Security\\Authentication\\Cookies\\src\\Microsoft.AspNetCore.Authentication.Cookies.csproj",
@@ -101,4 +99,4 @@
"src\\WebEncoders\\src\\Microsoft.Extensions.WebEncoders.csproj"
]
}
-}
\ No newline at end of file
+}
diff --git a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj
index abb665a9f11e..9cf745603fff 100644
--- a/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj
+++ b/src/ProjectTemplates/BlazorTemplates.Tests/BlazorTemplates.Tests.csproj
@@ -38,7 +38,6 @@
-
diff --git a/src/ProjectTemplates/TestInfrastructure/Directory.Build.targets.in b/src/ProjectTemplates/TestInfrastructure/Directory.Build.targets.in
index 4bde976fefd2..fae5e359075b 100644
--- a/src/ProjectTemplates/TestInfrastructure/Directory.Build.targets.in
+++ b/src/ProjectTemplates/TestInfrastructure/Directory.Build.targets.in
@@ -6,16 +6,4 @@
$(MSBuildThisFileDirectory)runtimeconfig.norollforward.json
-
-
-
- $(ArtifactsBinDir)Microsoft.NET.Sdk.Razor\${Configuration}\sdk-output\
-
-
diff --git a/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj b/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
index 8acd61c2461f..0a83e99dcfab 100644
--- a/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
+++ b/src/ProjectTemplates/test/ProjectTemplates.Tests.csproj
@@ -2,7 +2,6 @@
-
$(DefaultNetCoreTargetFramework)
@@ -51,7 +50,6 @@
-
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Application.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Application.cs
deleted file mode 100644
index bc5d8fc4828e..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Application.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Threading;
-using Microsoft.CodeAnalysis;
-using Microsoft.Extensions.CommandLineUtils;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal class Application : CommandLineApplication
- {
- public Application(
- CancellationToken cancellationToken,
- ExtensionAssemblyLoader loader,
- ExtensionDependencyChecker checker,
- Func assemblyReferenceProvider,
- TextWriter output = null,
- TextWriter error = null)
- {
- CancellationToken = cancellationToken;
- Checker = checker;
- Loader = loader;
- AssemblyReferenceProvider = assemblyReferenceProvider;
- Out = output ?? Out;
- Error = error ?? Error;
-
- Name = "rzc";
- FullName = "Microsoft ASP.NET Core Razor CLI tool";
- Description = "CLI interface to perform Razor operations.";
- ShortVersionGetter = GetInformationalVersion;
-
- HelpOption("-?|-h|--help");
-
- Commands.Add(new ServerCommand(this));
- Commands.Add(new ShutdownCommand(this));
- Commands.Add(new DiscoverCommand(this));
- Commands.Add(new GenerateCommand(this));
- Commands.Add(new BrotliCompressCommand(this));
- Commands.Add(new RewriteCssCommand(this));
- }
-
- public CancellationToken CancellationToken { get; }
-
- public ExtensionAssemblyLoader Loader { get; }
-
- public ExtensionDependencyChecker Checker { get; }
-
- public Func AssemblyReferenceProvider { get; }
-
- public new int Execute(params string[] args)
- {
- try
- {
- return base.Execute(ExpandResponseFiles(args));
- }
- catch (AggregateException ex) when (ex.InnerException != null)
- {
- foreach (var innerException in ex.Flatten().InnerExceptions)
- {
- Error.WriteLine(innerException.Message);
- Error.WriteLine(innerException.StackTrace);
- }
- return 1;
- }
- catch (CommandParsingException ex)
- {
- // Don't show a call stack when we have unneeded arguments, just print the error message.
- // The code that throws this exception will print help, so no need to do it here.
- Error.WriteLine(ex.Message);
- return 1;
- }
- catch (OperationCanceledException)
- {
- // This is a cancellation, not a failure.
- Error.WriteLine("Cancelled");
- return 1;
- }
- catch (Exception ex)
- {
- Error.WriteLine(ex.Message);
- Error.WriteLine(ex.StackTrace);
- return 1;
- }
- }
-
- private string GetInformationalVersion()
- {
- var assembly = typeof(Application).Assembly;
- var attribute = assembly.GetCustomAttribute();
- return attribute.InformationalVersion;
- }
-
- private static string[] ExpandResponseFiles(string[] args)
- {
- var expandedArgs = new List(args.Length);
- foreach (var arg in args)
- {
- if (!arg.StartsWith("@", StringComparison.Ordinal))
- {
- expandedArgs.Add(arg);
- }
- else
- {
- var fileName = arg.Substring(1);
- expandedArgs.AddRange(File.ReadLines(fileName));
- }
- }
-
- return expandedArgs.ToArray();
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/BrotliCompressCommand.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/BrotliCompressCommand.cs
deleted file mode 100644
index ca758cd6d3eb..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/BrotliCompressCommand.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.IO;
-using System.IO.Compression;
-using System.Threading.Tasks;
-using Microsoft.Extensions.CommandLineUtils;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal class BrotliCompressCommand : CommandBase
- {
- public BrotliCompressCommand(Application parent)
- : base(parent, "brotli")
- {
- Sources = Option("-s", "files to compress", CommandOptionType.MultipleValue);
- Outputs = Option("-o", "Output file path", CommandOptionType.MultipleValue);
- CompressionLevelOption = Option("-c", "Compression level", CommandOptionType.SingleValue);
- }
-
- public CommandOption Sources { get; }
-
- public CommandOption Outputs { get; }
-
- public CommandOption CompressionLevelOption { get; }
-
- public CompressionLevel CompressionLevel { get; private set; } = CompressionLevel.Optimal;
-
- protected override bool ValidateArguments()
- {
- if (Sources.Values.Count != Outputs.Values.Count)
- {
- Error.WriteLine($"{Sources.Description} has {Sources.Values.Count}, but {Outputs.Description} has {Outputs.Values.Count} values.");
- return false;
- }
-
- if (CompressionLevelOption.HasValue())
- {
- if (!Enum.TryParse(CompressionLevelOption.Value(), out var value))
- {
- Error.WriteLine($"Invalid option {CompressionLevelOption.Value()} for {CompressionLevelOption.Template}.");
- return false;
- }
-
- CompressionLevel = value;
- }
-
- return true;
- }
-
- protected override Task ExecuteCoreAsync()
- {
- Parallel.For(0, Sources.Values.Count, i =>
- {
- var source = Sources.Values[i];
- var output = Outputs.Values[i];
-
- using var sourceStream = File.OpenRead(source);
- using var fileStream = new FileStream(output, FileMode.Create);
-
- using var stream = new BrotliStream(fileStream, CompressionLevel);
-
- sourceStream.CopyTo(stream);
- });
-
- return Task.FromResult(ExitCodeSuccess);
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CachingMetadataReference.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CachingMetadataReference.cs
deleted file mode 100644
index 0aeb381b21dc..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CachingMetadataReference.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using Microsoft.CodeAnalysis;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal sealed class CachingMetadataReference : PortableExecutableReference
- {
- private static readonly MetadataCache _metadataCache = new MetadataCache();
-
- public CachingMetadataReference(string fullPath, MetadataReferenceProperties properties)
- : base(properties, fullPath)
- {
- }
-
- protected override DocumentationProvider CreateDocumentationProvider()
- {
- return DocumentationProvider.Default;
- }
-
- protected override Metadata GetMetadataImpl()
- {
- return _metadataCache.GetMetadata(FilePath);
- }
-
- protected override PortableExecutableReference WithPropertiesImpl(MetadataReferenceProperties properties)
- {
- return new CachingMetadataReference(FilePath, properties);
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Client.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Client.cs
deleted file mode 100644
index cf94173337f9..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Client.cs
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.IO;
-using System.IO.Pipes;
-#if NETFRAMEWORK
-using System.Security.AccessControl;
-using System.Security.Principal;
-#endif
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal abstract class Client : IDisposable
- {
- private static int counter;
-
- // From https://github.com/dotnet/corefx/blob/29cd6a0b0ac2993cee23ebaf36ca3d4bce6dd75f/src/System.IO.Pipes/ref/System.IO.Pipes.cs#L93.
- // Using the enum value directly as this option is not available in netstandard.
- private const PipeOptions PipeOptionCurrentUserOnly = (PipeOptions)536870912;
-
- private static readonly PipeOptions _pipeOptions = GetPipeOptions();
-
- public abstract Stream Stream { get; }
-
- public abstract string Identifier { get; }
-
- public void Dispose()
- {
- Dispose(disposing: true);
- }
-
- public abstract Task WaitForDisconnectAsync(CancellationToken cancellationToken);
-
- protected virtual void Dispose(bool disposing)
- {
- }
-
- // Based on: https://github.com/dotnet/roslyn/blob/14aed138a01c448143b9acf0fe77a662e3dfe2f4/src/Compilers/Shared/BuildServerConnection.cs#L290
- public static async Task ConnectAsync(string pipeName, TimeSpan? timeout, CancellationToken cancellationToken)
- {
- var timeoutMilliseconds = timeout == null ? Timeout.Infinite : (int)timeout.Value.TotalMilliseconds;
-
- try
- {
- // Machine-local named pipes are named "\\.\pipe\".
- // We use the SHA1 of the directory the compiler exes live in as the pipe name.
- // The NamedPipeClientStream class handles the "\\.\pipe\" part for us.
- ServerLogger.Log("Attempt to open named pipe '{0}'", pipeName);
-
- var stream = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, _pipeOptions);
- cancellationToken.ThrowIfCancellationRequested();
-
- ServerLogger.Log("Attempt to connect named pipe '{0}'", pipeName);
- try
- {
- await stream.ConnectAsync(timeoutMilliseconds, cancellationToken);
- }
- catch (Exception e) when (e is IOException || e is TimeoutException)
- {
- // Note: IOException can also indicate timeout.
- // From docs:
- // - TimeoutException: Could not connect to the server within the specified timeout period.
- // - IOException: The server is connected to another client and the time-out period has expired.
- ServerLogger.Log($"Connecting to server timed out after {timeoutMilliseconds} ms");
- return null;
- }
-
- ServerLogger.Log("Named pipe '{0}' connected", pipeName);
- cancellationToken.ThrowIfCancellationRequested();
-
-#if NETFRAMEWORK
- // Verify that we own the pipe.
- if (!CheckPipeConnectionOwnership(stream))
- {
- ServerLogger.Log("Owner of named pipe is incorrect");
- return null;
- }
-#endif
-
- return new NamedPipeClient(stream, GetNextIdentifier());
- }
- catch (Exception e) when (!(e is TaskCanceledException || e is OperationCanceledException))
- {
- ServerLogger.LogException(e, "Exception while connecting to process");
- return null;
- }
- }
-
-#if NETFRAMEWORK
- ///
- /// Check to ensure that the named pipe server we connected to is owned by the same
- /// user.
- ///
- private static bool CheckPipeConnectionOwnership(NamedPipeClientStream pipeStream)
- {
- try
- {
- if (PlatformInformation.IsWindows)
- {
- using (var currentIdentity = WindowsIdentity.GetCurrent())
- {
- var currentOwner = currentIdentity.Owner;
- var remotePipeSecurity = GetPipeSecurity(pipeStream);
- var remoteOwner = remotePipeSecurity.GetOwner(typeof(SecurityIdentifier));
-
- return currentOwner.Equals(remoteOwner);
- }
- }
-
- // We don't need to verify on non-windows as that will be taken care of by the
- // PipeOptions.CurrentUserOnly flag.
- return false;
- }
- catch (Exception ex)
- {
- ServerLogger.LogException(ex, "Checking pipe connection");
- return false;
- }
- }
-
- private static ObjectSecurity GetPipeSecurity(PipeStream pipeStream)
- {
- return pipeStream.GetAccessControl();
- }
-#endif
-
- private static PipeOptions GetPipeOptions()
- {
- var options = PipeOptions.Asynchronous;
-
- if (Enum.IsDefined(typeof(PipeOptions), PipeOptionCurrentUserOnly))
- {
- return options | PipeOptionCurrentUserOnly;
- }
-
- return options;
- }
-
- private static string GetNextIdentifier()
- {
- var id = Interlocked.Increment(ref counter);
- return "clientconnection-" + id;
- }
-
- private class NamedPipeClient : Client
- {
- public NamedPipeClient(NamedPipeClientStream stream, string identifier)
- {
- Stream = stream;
- Identifier = identifier;
- }
-
- public override Stream Stream { get; }
-
- public override string Identifier { get; }
-
- public async override Task WaitForDisconnectAsync(CancellationToken cancellationToken)
- {
- if (!(Stream is PipeStream pipeStream))
- {
- return;
- }
-
- // We have to poll for disconnection by reading, PipeStream.IsConnected isn't reliable unless you
- // actually do a read - which will cause it to update its state.
- while (!cancellationToken.IsCancellationRequested && pipeStream.IsConnected)
- {
- await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken);
-
- try
- {
- ServerLogger.Log($"Before poking pipe {Identifier}.");
- await Stream.ReadAsync(Array.Empty(), 0, 0, cancellationToken);
- ServerLogger.Log($"After poking pipe {Identifier}.");
- }
- catch (OperationCanceledException)
- {
- }
- catch (Exception e)
- {
- // It is okay for this call to fail. Errors will be reflected in the
- // IsConnected property which will be read on the next iteration.
- ServerLogger.LogException(e, $"Error poking pipe {Identifier}.");
- }
- }
- }
-
- protected override void Dispose(bool disposing)
- {
- if (disposing)
- {
- Stream.Dispose();
- }
- }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CommandBase.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CommandBase.cs
deleted file mode 100644
index 91904ae9f54e..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CommandBase.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.CommandLineUtils;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal abstract class CommandBase : CommandLineApplication
- {
- public const int ExitCodeSuccess = 0;
- public const int ExitCodeFailure = 1;
- public const int ExitCodeFailureRazorError = 2;
-
- protected CommandBase(Application parent, string name)
- : base(throwOnUnexpectedArg: true)
- {
- if (parent == null)
- {
- throw new ArgumentNullException(nameof(parent));
- }
-
- base.Parent = parent;
- Name = name;
- Out = parent.Out ?? Out;
- Error = parent.Error ?? Error;
-
- Help = HelpOption("-?|-h|--help");
- OnExecute((Func>)ExecuteAsync);
- }
-
- protected new Application Parent => (Application)base.Parent;
-
- protected CancellationToken Cancelled => Parent?.CancellationToken ?? default;
-
- protected CommandOption Help { get; }
-
- protected virtual bool ValidateArguments()
- {
- return true;
- }
-
- protected abstract Task ExecuteCoreAsync();
-
- private async Task ExecuteAsync()
- {
- if (!ValidateArguments())
- {
- ShowHelp();
- return ExitCodeFailureRazorError;
- }
-
- return await ExecuteCoreAsync();
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CompilerHost.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CompilerHost.cs
deleted file mode 100644
index 0525beed061d..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CompilerHost.cs
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using Microsoft.CodeAnalysis;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal abstract class CompilerHost
- {
- public static CompilerHost Create()
- {
- return new DefaultCompilerHost();
- }
-
- public abstract ServerResponse Execute(ServerRequest request, CancellationToken cancellationToken);
-
- private class DefaultCompilerHost : CompilerHost
- {
- public DefaultCompilerHost()
- {
- // The loader needs to live for the lifetime of the server.
- //
- // This means that if a request tries to use a set of binaries that are inconsistent with what
- // the server already has, then it will be rejected to try again on the client.
- //
- // We also check each set of extensions for missing depenencies individually, so that we can
- // consistently reject a request that doesn't specify everything it needs. Otherwise the request
- // could succeed sometimes if it relies on transient state.
- Loader = new DefaultExtensionAssemblyLoader(Path.Combine(Path.GetTempPath(), "Razor-Server"));
-
- AssemblyReferenceProvider = (path, properties) => new CachingMetadataReference(path, properties);
- }
-
- public Func AssemblyReferenceProvider { get; }
-
- public ExtensionAssemblyLoader Loader { get; }
-
- public override ServerResponse Execute(ServerRequest request, CancellationToken cancellationToken)
- {
- if (!TryParseArguments(request, out var parsed))
- {
- return new RejectedServerResponse();
- }
-
- var exitCode = 0;
- var commandArgs = parsed.args.ToArray();
-
- var outputWriter = new StringWriter();
- var errorWriter = new StringWriter();
-
- var checker = new DefaultExtensionDependencyChecker(Loader, outputWriter, errorWriter);
- var app = new Application(cancellationToken, Loader, checker, AssemblyReferenceProvider, outputWriter, errorWriter);
-
- exitCode = app.Execute(commandArgs);
-
- var output = outputWriter.ToString();
- var error = errorWriter.ToString();
-
- outputWriter.Dispose();
- errorWriter.Dispose();
-
- // This will no-op if server logging is not enabled.
- ServerLogger.Log(output);
- ServerLogger.Log(error);
-
- return new CompletedServerResponse(exitCode, utf8output: false, output, error);
- }
-
- private bool TryParseArguments(ServerRequest request, out (string workingDirectory, string tempDirectory, string[] args) parsed)
- {
- string workingDirectory = null;
- string tempDirectory = null;
-
- var args = new List(request.Arguments.Count);
-
- for (var i = 0; i < request.Arguments.Count; i++)
- {
- var argument = request.Arguments[i];
- if (argument.Id == RequestArgument.ArgumentId.CurrentDirectory)
- {
- workingDirectory = argument.Value;
- }
- else if (argument.Id == RequestArgument.ArgumentId.TempDirectory)
- {
- tempDirectory = argument.Value;
- }
- else if (argument.Id == RequestArgument.ArgumentId.CommandLineArgument)
- {
- args.Add(argument.Value);
- }
- }
-
- ServerLogger.Log($"WorkingDirectory = '{workingDirectory}'");
- ServerLogger.Log($"TempDirectory = '{tempDirectory}'");
- for (var i = 0; i < args.Count; i++)
- {
- ServerLogger.Log($"Argument[{i}] = '{request.Arguments[i]}'");
- }
-
- if (string.IsNullOrEmpty(workingDirectory))
- {
- ServerLogger.Log($"Rejecting build due to missing working directory");
-
- parsed = default;
- return false;
- }
-
- if (string.IsNullOrEmpty(tempDirectory))
- {
- ServerLogger.Log($"Rejecting build due to missing temp directory");
-
- parsed = default;
- return false;
- }
-
- if (string.IsNullOrEmpty(tempDirectory))
- {
- ServerLogger.Log($"Rejecting build due to missing temp directory");
-
- parsed = default;
- return false;
- }
-
- parsed = (workingDirectory, tempDirectory, args.ToArray());
- return true;
- }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CompositeRazorProjectFileSystem.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CompositeRazorProjectFileSystem.cs
deleted file mode 100644
index a3d4fc71654b..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/CompositeRazorProjectFileSystem.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using Microsoft.AspNetCore.Razor.Language;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal class CompositeRazorProjectFileSystem : RazorProjectFileSystem
- {
- public CompositeRazorProjectFileSystem(IReadOnlyList fileSystems)
- {
- FileSystems = fileSystems ?? throw new ArgumentNullException(nameof(fileSystems));
- }
-
- public IReadOnlyList FileSystems { get; }
-
- public override IEnumerable EnumerateItems(string basePath)
- {
- foreach (var fileSystem in FileSystems)
- {
- foreach (var result in fileSystem.EnumerateItems(basePath))
- {
- yield return result;
- }
- }
- }
-
-
- public override RazorProjectItem GetItem(string path)
- {
- return GetItem(path, fileKind: null);
- }
-
- public override RazorProjectItem GetItem(string path, string fileKind)
- {
- RazorProjectItem razorProjectItem = null;
- foreach (var fileSystem in FileSystems)
- {
- razorProjectItem = fileSystem.GetItem(path, fileKind);
- if (razorProjectItem != null && razorProjectItem.Exists)
- {
- return razorProjectItem;
- }
- }
-
- return razorProjectItem;
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ConcurrentLruCache.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ConcurrentLruCache.cs
deleted file mode 100644
index 0220615ec2ba..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ConcurrentLruCache.cs
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- ///
- /// Cache with a fixed size that evicts the least recently used members.
- /// Thread-safe.
- /// This was taken from https://github.com/dotnet/roslyn/blob/749c0ec135d7d080658dc1aa794d15229c3d10d2/src/Compilers/Core/Portable/InternalUtilities/ConcurrentLruCache.cs.
- ///
- internal class ConcurrentLruCache
- {
- private readonly int _capacity;
-
- private readonly Dictionary _cache;
- private readonly LinkedList _nodeList;
- // This is a naive course-grained lock, it can probably be optimized
- private readonly object _lockObject = new object();
-
- public ConcurrentLruCache(int capacity)
- : this (capacity, EqualityComparer.Default)
- {
- }
-
- public ConcurrentLruCache(int capacity, IEqualityComparer comparer)
- {
- if (capacity <= 0)
- {
- throw new ArgumentOutOfRangeException(nameof(capacity));
- }
- _capacity = capacity;
- _cache = new Dictionary(capacity, comparer);
- _nodeList = new LinkedList();
- }
-
- ///
- /// Create cache from an array. The cache capacity will be the size
- /// of the array. All elements of the array will be added to the
- /// cache. If any duplicate keys are found in the array a
- /// will be thrown.
- ///
- public ConcurrentLruCache(KeyValuePair[] array)
- : this(array.Length)
- {
- foreach (var kvp in array)
- {
- UnsafeAdd(kvp.Key, kvp.Value);
- }
- }
-
- public int Count
- {
- get
- {
- lock (_lockObject)
- {
- return _cache.Count;
- }
- }
- }
-
- public void Add(TKey key, TValue value)
- {
- lock (_lockObject)
- {
- UnsafeAdd(key, value);
- }
- }
-
- public TValue GetOrAdd(TKey key, TValue value)
- {
- lock (_lockObject)
- {
- if (UnsafeTryGetValue(key, out var result))
- {
- return result;
- }
- else
- {
- UnsafeAdd(key, value);
- return value;
- }
- }
- }
-
- public bool TryGetValue(TKey key, out TValue value)
- {
- lock (_lockObject)
- {
- return UnsafeTryGetValue(key, out value);
- }
- }
-
- public bool Remove(TKey key)
- {
- lock (_lockObject)
- {
- return UnsafeRemove(key);
- }
- }
-
- ///
- /// For testing. Very expensive.
- ///
- internal IEnumerable> TestingEnumerable
- {
- get
- {
- lock (_lockObject)
- {
- foreach (var key in _nodeList)
- {
- var kvp = new KeyValuePair(key, _cache[key].Value);
- yield return kvp;
- }
- }
- }
- }
-
- ///
- /// Doesn't lock.
- ///
- private bool UnsafeTryGetValue(TKey key, out TValue value)
- {
- if (_cache.TryGetValue(key, out var result))
- {
- MoveNodeToTop(result.Node);
- value = result.Value;
- return true;
- }
- else
- {
- value = default(TValue);
- return false;
- }
- }
-
- private void MoveNodeToTop(LinkedListNode node)
- {
- if (!object.ReferenceEquals(_nodeList.First, node))
- {
- _nodeList.Remove(node);
- _nodeList.AddFirst(node);
- }
- }
-
- ///
- /// Expects non-empty cache. Does not lock.
- ///
- private void UnsafeEvictLastNode()
- {
- Debug.Assert(_capacity > 0);
- var lastNode = _nodeList.Last;
- _nodeList.Remove(lastNode);
- _cache.Remove(lastNode.Value);
- }
-
- private void UnsafeAddNodeToTop(TKey key, TValue value)
- {
- var node = new LinkedListNode(key);
- _cache.Add(key, new CacheValue(value, node));
- _nodeList.AddFirst(node);
- }
-
- ///
- /// Doesn't lock.
- ///
- private void UnsafeAdd(TKey key, TValue value)
- {
- if (_cache.TryGetValue(key, out var result))
- {
- throw new ArgumentException("Key already exists", nameof(key));
- }
- else
- {
- if (_cache.Count == _capacity)
- {
- UnsafeEvictLastNode();
- }
- UnsafeAddNodeToTop(key, value);
- }
- }
-
- private bool UnsafeRemove(TKey key)
- {
- _nodeList.Remove(key);
- return _cache.Remove(key);
- }
-
- private struct CacheValue
- {
- public CacheValue(TValue value, LinkedListNode node)
- {
- Value = value;
- Node = node;
- }
-
- public TValue Value { get; }
-
- public LinkedListNode Node { get; }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Connection.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Connection.cs
deleted file mode 100644
index 9acf1589c98d..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Connection.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal abstract class Connection : IDisposable
- {
- public string Identifier { get; protected set; }
-
- public Stream Stream { get; protected set; }
-
- public abstract Task WaitForDisconnectAsync(CancellationToken cancellationToken);
-
- public void Dispose()
- {
- Dispose(disposing: true);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ConnectionHost.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ConnectionHost.cs
deleted file mode 100644
index ee29a4a10b2a..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ConnectionHost.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.IO;
-using System.IO.Pipes;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- // Heavily influenced by:
- // https://github.com/dotnet/roslyn/blob/14aed138a01c448143b9acf0fe77a662e3dfe2f4/src/Compilers/Server/VBCSCompiler/NamedPipeClientConnection.cs#L17
- internal abstract class ConnectionHost
- {
- private static int counter;
-
- public abstract Task WaitForConnectionAsync(CancellationToken cancellationToken);
-
- public static ConnectionHost Create(string pipeName)
- {
- return new NamedPipeConnectionHost(pipeName);
- }
-
- private static string GetNextIdentifier()
- {
- var id = Interlocked.Increment(ref counter);
- return "connection-" + id;
- }
-
- private class NamedPipeConnectionHost : ConnectionHost
- {
- // Size of the buffers to use: 64K
- private const int PipeBufferSize = 0x10000;
-
- // From https://github.com/dotnet/corefx/blob/29cd6a0b0ac2993cee23ebaf36ca3d4bce6dd75f/src/System.IO.Pipes/ref/System.IO.Pipes.cs#L93.
- // Using the enum value directly as this option is not available in netstandard.
- private const PipeOptions PipeOptionCurrentUserOnly = (PipeOptions)536870912;
-
- private static readonly PipeOptions _pipeOptions = GetPipeOptions();
-
- public NamedPipeConnectionHost(string pipeName)
- {
- PipeName = pipeName;
- }
-
- public string PipeName { get; }
-
- public async override Task WaitForConnectionAsync(CancellationToken cancellationToken)
- {
- // Create the pipe and begin waiting for a connection. This doesn't block, but could fail
- // in certain circumstances, such as the OS refusing to create the pipe for some reason
- // or the pipe was disconnected before we starting listening.
- var pipeStream = new NamedPipeServerStream(
- PipeName,
- PipeDirection.InOut,
- NamedPipeServerStream.MaxAllowedServerInstances, // Maximum connections.
- PipeTransmissionMode.Byte,
- _pipeOptions,
- PipeBufferSize, // Default input buffer
- PipeBufferSize);// Default output buffer
-
- ServerLogger.Log("Waiting for new connection");
- await pipeStream.WaitForConnectionAsync(cancellationToken);
- ServerLogger.Log("Pipe connection detected.");
-
- if (Environment.Is64BitProcess || Memory.IsMemoryAvailable())
- {
- ServerLogger.Log("Memory available - accepting connection");
- return new NamedPipeConnection(pipeStream, GetNextIdentifier());
- }
-
- pipeStream.Close();
- throw new Exception("Insufficient resources to process new connection.");
- }
-
- private static PipeOptions GetPipeOptions()
- {
- var options = PipeOptions.Asynchronous | PipeOptions.WriteThrough;
-
- if (Enum.IsDefined(typeof(PipeOptions), PipeOptionCurrentUserOnly))
- {
- return options | PipeOptionCurrentUserOnly;
- }
-
- return options;
- }
- }
-
- private class NamedPipeConnection : Connection
- {
- public NamedPipeConnection(NamedPipeServerStream stream, string identifier)
- {
- Stream = stream;
- Identifier = identifier;
- }
-
- public async override Task WaitForDisconnectAsync(CancellationToken cancellationToken)
- {
- if (!(Stream is PipeStream pipeStream))
- {
- return;
- }
-
- // We have to poll for disconnection by reading, PipeStream.IsConnected isn't reliable unless you
- // actually do a read - which will cause it to update its state.
- while (!cancellationToken.IsCancellationRequested && pipeStream.IsConnected)
- {
- await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken);
-
- try
- {
- ServerLogger.Log($"Before poking pipe {Identifier}.");
- await Stream.ReadAsync(Array.Empty(), 0, 0, cancellationToken);
- ServerLogger.Log($"After poking pipe {Identifier}.");
- }
- catch (OperationCanceledException)
- {
- }
- catch (Exception e)
- {
- // It is okay for this call to fail. Errors will be reflected in the
- // IsConnected property which will be read on the next iteration.
- ServerLogger.LogException(e, $"Error poking pipe {Identifier}.");
- }
- }
- }
-
- protected override void Dispose(bool disposing)
- {
- ServerLogger.Log($"Pipe {Identifier}: Closing.");
-
- try
- {
- Stream.Dispose();
- }
- catch (Exception ex)
- {
- // The client connection failing to close isn't fatal to the server process. It is simply a client
- // for which we can no longer communicate and that's okay because the Close method indicates we are
- // done with the client already.
- var message = $"Pipe {Identifier}: Error closing pipe.";
- ServerLogger.LogException(ex, message);
- }
- }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ConnectionResult.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ConnectionResult.cs
deleted file mode 100644
index 6c2072561751..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ConnectionResult.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal struct ConnectionResult
- {
- public readonly Reason CloseReason;
- public readonly TimeSpan? KeepAlive;
-
- public ConnectionResult(Reason closeReason, TimeSpan? keepAlive = null)
- {
- CloseReason = closeReason;
- KeepAlive = keepAlive;
- }
-
- public enum Reason
- {
- ///
- /// There was an error creating the request object and a compilation was never created.
- ///
- CompilationNotStarted,
-
- ///
- /// The compilation completed and results were provided to the client.
- ///
- CompilationCompleted,
-
- ///
- /// The compilation process was initiated and the client disconnected before the results could be provided to them.
- ///
- ClientDisconnect,
-
- ///
- /// There was an unhandled exception processing the result.
- ///
- ClientException,
-
- ///
- /// There was a request from the client to shutdown the server.
- ///
- ClientShutdownRequest,
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DebugMode.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DebugMode.cs
deleted file mode 100644
index 5d38654c5259..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DebugMode.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Diagnostics;
-using System.Linq;
-using System.Threading;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal static class DebugMode
- {
- public static void HandleDebugSwitch(ref string[] args)
- {
- if (args.Length > 0 && string.Equals("--debug", args[0], StringComparison.OrdinalIgnoreCase))
- {
- args = args.Skip(1).ToArray();
-
- Console.WriteLine("Waiting for debugger in pid: {0}", Process.GetCurrentProcess().Id);
- while (!Debugger.IsAttached)
- {
- Thread.Sleep(TimeSpan.FromSeconds(3));
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DefaultExtensionAssemblyLoader.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DefaultExtensionAssemblyLoader.cs
deleted file mode 100644
index 05dc4a09eb69..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DefaultExtensionAssemblyLoader.cs
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright(c) .NET Foundation.All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.IO;
-using System.Reflection;
-using System.Reflection.Metadata;
-using System.Reflection.PortableExecutable;
-using System.Runtime.Loader;
-using Microsoft.CodeAnalysis;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal class DefaultExtensionAssemblyLoader : ExtensionAssemblyLoader
- {
- private readonly string _baseDirectory;
-
- private readonly object _lock = new object();
- private readonly Dictionary _loadedByPath;
- private readonly Dictionary _loadedByIdentity;
- private readonly Dictionary _identityCache;
- private readonly Dictionary> _wellKnownAssemblies;
-
- private ShadowCopyManager _shadowCopyManager;
-
- public DefaultExtensionAssemblyLoader(string baseDirectory)
- {
- _baseDirectory = baseDirectory;
-
- _loadedByPath = new Dictionary(StringComparer.OrdinalIgnoreCase);
- _loadedByIdentity = new Dictionary();
- _identityCache = new Dictionary(StringComparer.OrdinalIgnoreCase);
- _wellKnownAssemblies = new Dictionary>(StringComparer.OrdinalIgnoreCase);
-
- LoadContext = new ExtensionAssemblyLoadContext(AssemblyLoadContext.GetLoadContext(typeof(ExtensionAssemblyLoader).Assembly), this);
- }
-
- protected AssemblyLoadContext LoadContext { get; }
-
- public override void AddAssemblyLocation(string filePath)
- {
- if (filePath == null)
- {
- throw new ArgumentNullException(nameof(filePath));
- }
-
- if (!Path.IsPathRooted(filePath))
- {
- throw new ArgumentException(nameof(filePath));
- }
-
- var assemblyName = Path.GetFileNameWithoutExtension(filePath);
- lock (_lock)
- {
- if (!_wellKnownAssemblies.TryGetValue(assemblyName, out var paths))
- {
- paths = new List();
- _wellKnownAssemblies.Add(assemblyName, paths);
- }
-
- if (!paths.Contains(filePath))
- {
- paths.Add(filePath);
- }
- }
- }
-
- public override Assembly Load(string assemblyName)
- {
- if (!AssemblyIdentity.TryParseDisplayName(assemblyName, out var identity))
- {
- return null;
- }
-
- lock (_lock)
- {
- // First, check if this loader already loaded the requested assembly:
- if (_loadedByIdentity.TryGetValue(identity, out var assembly))
- {
- return assembly;
- }
-
- // Second, check if an assembly file of the same simple name was registered with the loader:
- if (_wellKnownAssemblies.TryGetValue(identity.Name, out var paths))
- {
- // Multiple assemblies of the same simple name but different identities might have been registered.
- // Load the one that matches the requested identity (if any).
- foreach (var path in paths)
- {
- var candidateIdentity = GetIdentity(path);
-
- if (identity.Equals(candidateIdentity))
- {
- return LoadFromPathUnsafe(path, candidateIdentity);
- }
- }
- }
-
- // We only support loading by name from 'well-known' paths. If you need to load something by
- // name and you get here, then that means we don't know where to look.
- return null;
- }
- }
-
- public override Assembly LoadFromPath(string filePath)
- {
- if (filePath == null)
- {
- throw new ArgumentNullException(nameof(filePath));
- }
-
- if (!Path.IsPathRooted(filePath))
- {
- throw new ArgumentException(nameof(filePath));
- }
-
- lock (_lock)
- {
- return LoadFromPathUnsafe(filePath, identity: null);
- }
- }
-
- private Assembly LoadFromPathUnsafe(string filePath, AssemblyIdentity identity)
- {
- // If we've already loaded the assembly by path there should be nothing else to do,
- // all of our data is up to date.
- if (_loadedByPath.TryGetValue(filePath, out var entry))
- {
- return entry.assembly;
- }
-
- // If we've already loaded the assembly by identity, then we might has some updating
- // to do.
- identity = identity ?? GetIdentity(filePath);
- if (identity != null && _loadedByIdentity.TryGetValue(identity, out var assembly))
- {
- // An assembly file might be replaced by another file with a different identity.
- // Last one wins.
- _loadedByPath[filePath] = (assembly, identity);
- return assembly;
- }
-
- // Ok we don't have this cached. Let's actually try to load the assembly.
- assembly = LoadFromPathUnsafeCore(CopyAssembly(filePath));
-
- identity = identity ?? AssemblyIdentity.FromAssemblyDefinition(assembly);
-
- // It's possible an assembly was loaded by two different paths. Just use the original then.
- if (_loadedByIdentity.TryGetValue(identity, out var duplicate))
- {
- assembly = duplicate;
- }
- else
- {
- _loadedByIdentity.Add(identity, assembly);
- }
-
- _loadedByPath[filePath] = (assembly, identity);
- return assembly;
- }
-
- private AssemblyIdentity GetIdentity(string filePath)
- {
- if (!_identityCache.TryGetValue(filePath, out var identity))
- {
- identity = ReadAssemblyIdentity(filePath);
- _identityCache.Add(filePath, identity);
- }
-
- return identity;
- }
-
- protected virtual string CopyAssembly(string filePath)
- {
- if (_baseDirectory == null)
- {
- // Don't shadow-copy when base directory is null. This means we're running as a CLI not
- // a server.
- return filePath;
- }
-
- if (_shadowCopyManager == null)
- {
- _shadowCopyManager = new ShadowCopyManager(_baseDirectory);
- }
-
- return _shadowCopyManager.AddAssembly(filePath);
- }
-
- protected virtual Assembly LoadFromPathUnsafeCore(string filePath)
- {
- return LoadContext.LoadFromAssemblyPath(filePath);
- }
-
- private static AssemblyIdentity ReadAssemblyIdentity(string filePath)
- {
- try
- {
- using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
- using (var reader = new PEReader(stream))
- {
- var metadataReader = reader.GetMetadataReader();
- return metadataReader.GetAssemblyIdentity();
- }
- }
- catch
- {
- }
-
- return null;
- }
-
- private class ExtensionAssemblyLoadContext : AssemblyLoadContext
- {
- private readonly AssemblyLoadContext _parent;
- private readonly DefaultExtensionAssemblyLoader _loader;
-
- public ExtensionAssemblyLoadContext(AssemblyLoadContext parent, DefaultExtensionAssemblyLoader loader)
- {
- _parent = parent;
- _loader = loader;
- }
-
- protected override Assembly Load(AssemblyName assemblyName)
- {
- // Try to load from well-known paths. This will be called when loading a dependency of an extension.
- var assembly = _loader.Load(assemblyName.ToString());
- if (assembly != null)
- {
- return assembly;
- }
-
- // If we don't have an entry, then fall back to the default load context. This allows extensions
- // to resolve assemblies that are provided by the host.
- return _parent.LoadFromAssemblyName(assemblyName);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DefaultExtensionDependencyChecker.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DefaultExtensionDependencyChecker.cs
deleted file mode 100644
index 0e363b83feea..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DefaultExtensionDependencyChecker.cs
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Reflection.Metadata;
-using System.Reflection.PortableExecutable;
-using Microsoft.CodeAnalysis;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal class DefaultExtensionDependencyChecker : ExtensionDependencyChecker
- {
- // These are treated as prefixes. So `Microsoft.CodeAnalysis.Razor` would be assumed to work.
- private static readonly string[] DefaultIgnoredAssemblies = new string[]
- {
- "mscorlib",
- "netstandard",
- "System",
- "Microsoft.CodeAnalysis",
- "Microsoft.AspNetCore.Razor.Language",
- };
-
- private readonly ExtensionAssemblyLoader _loader;
- private readonly TextWriter _output;
- private readonly TextWriter _error;
- private readonly string[] _ignoredAssemblies;
-
- public DefaultExtensionDependencyChecker(
- ExtensionAssemblyLoader loader,
- TextWriter output,
- TextWriter error,
- string[] ignoredAssemblies = null)
- {
- _loader = loader;
- _output = output;
- _error = error;
- _ignoredAssemblies = ignoredAssemblies ?? DefaultIgnoredAssemblies;
- }
-
- public override bool Check(IEnumerable assmblyFilePaths)
- {
- try
- {
- return CheckCore(assmblyFilePaths);
- }
- catch (Exception ex)
- {
- _error.WriteLine("Exception performing Extension dependency check:");
- _error.WriteLine(ex.ToString());
- return false;
- }
- }
-
- private bool CheckCore(IEnumerable assemblyFilePaths)
- {
- var items = assemblyFilePaths.Select(a => ExtensionVerificationItem.Create(a)).ToArray();
- var assemblies = new HashSet(items.Select(i => i.Identity));
-
- for (var i = 0; i < items.Length; i++)
- {
- var item = items[i];
- _output.WriteLine($"Verifying assembly at {item.FilePath}");
-
- if (!Path.IsPathRooted(item.FilePath))
- {
- _error.WriteLine($"The file path '{item.FilePath}' is not a rooted path. File paths must be absolute and fully-qualified.");
- return false;
- }
-
- foreach (var reference in item.References)
- {
- if (_ignoredAssemblies.Any(n => reference.Name.StartsWith(n, StringComparison.Ordinal)))
- {
- // This is on the allow list, keep going.
- continue;
- }
-
- if (assemblies.Contains(reference))
- {
- // This was also provided as a dependency, keep going.
- continue;
- }
-
- // If we get here we can't resolve this assembly. This is an error.
- _error.WriteLine($"Extension assembly '{item.Identity.Name}' depends on '{reference.ToString()} which is missing.");
- return false;
- }
- }
-
- // Assuming we get this far, the set of assemblies we have is at least a coherent set (barring
- // version conflicts). Register all of the paths with the loader so they can find each other by
- // name.
- for (var i = 0; i < items.Length; i++)
- {
- _loader.AddAssemblyLocation(items[i].FilePath);
- }
-
- // Now try to load everything. This has the side effect of resolving all of these items
- // in the loader's caches.
- for (var i = 0; i < items.Length; i++)
- {
- var item = items[i];
- item.Assembly = _loader.LoadFromPath(item.FilePath);
- }
-
- // Third, check that the MVIDs of the files on disk match the MVIDs of the loaded assemblies.
- for (var i = 0; i < items.Length; i++)
- {
- var item = items[i];
- if (item.Mvid != item.Assembly.ManifestModule.ModuleVersionId)
- {
- _error.WriteLine($"Extension assembly '{item.Identity.Name}' at '{item.FilePath}' has a different ModuleVersionId than loaded assembly '{item.Assembly.FullName}'");
- return false;
- }
- }
-
- return true;
- }
-
- private class ExtensionVerificationItem
- {
- public static ExtensionVerificationItem Create(string filePath)
- {
- using (var peReader = new PEReader(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)))
- {
- var metadataReader = peReader.GetMetadataReader();
- var identity = metadataReader.GetAssemblyIdentity();
- var mvid = metadataReader.GetGuid(metadataReader.GetModuleDefinition().Mvid);
- var references = metadataReader.GetReferencedAssembliesOrThrow();
-
- return new ExtensionVerificationItem(filePath, identity, mvid, references.ToArray());
- }
- }
-
- private ExtensionVerificationItem(string filePath, AssemblyIdentity identity, Guid mvid, AssemblyIdentity[] references)
- {
- FilePath = filePath;
- Identity = identity;
- Mvid = mvid;
- References = references;
- }
-
- public string FilePath { get; }
-
- public Assembly Assembly { get; set; }
-
- public AssemblyIdentity Identity { get; }
-
- public Guid Mvid { get; }
-
- public IReadOnlyList References { get; }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DefaultRequestDispatcher.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DefaultRequestDispatcher.cs
deleted file mode 100644
index 110494b24937..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DefaultRequestDispatcher.cs
+++ /dev/null
@@ -1,472 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Runtime;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- // Heavily influenced by:
- // https://github.com/dotnet/roslyn/blob/14aed138a01c448143b9acf0fe77a662e3dfe2f4/src/Compilers/Server/ServerShared/ServerDispatcher.cs#L15
- internal class DefaultRequestDispatcher : RequestDispatcher
- {
- private readonly CancellationToken _cancellationToken;
- private readonly CompilerHost _compilerHost;
- private readonly ConnectionHost _connectionHost;
- private readonly EventBus _eventBus;
-
- private KeepAlive _keepAlive;
- private State _state;
- private Task _timeoutTask;
- private Task _gcTask;
- private Task _listenTask;
- private CancellationTokenSource _listenCancellationTokenSource;
- private List> _connections = new List>();
-
- public DefaultRequestDispatcher(
- ConnectionHost connectionHost,
- CompilerHost compilerHost,
- CancellationToken cancellationToken,
- EventBus eventBus = null,
- TimeSpan? keepAlive = null)
- {
- _connectionHost = connectionHost;
- _compilerHost = compilerHost;
- _cancellationToken = cancellationToken;
-
- _eventBus = eventBus ?? EventBus.Default;
-
- var keepAliveTimeout = DefaultServerKeepAlive;
- if (keepAlive.HasValue)
- {
- keepAliveTimeout = keepAlive.Value;
- }
- _keepAlive = new KeepAlive(keepAliveTimeout, isDefault: true);
- }
-
- // The server accepts connections until we reach a state that requires a shutdown. At that
- // time no new connections will be accepted and the server will drain existing connections.
- //
- // The idea is that it's better to let clients fallback to in-proc (and slow down) than it is to keep
- // running in an undesired state.
- public override void Run()
- {
- _state = State.Running;
-
- try
- {
- Listen();
-
- do
- {
- Debug.Assert(_listenTask != null);
-
- MaybeCreateTimeoutTask();
- MaybeCreateGCTask();
- WaitForAnyCompletion(_cancellationToken);
- CheckCompletedTasks(_cancellationToken);
- }
- while (_connections.Count > 0 || _state == State.Running);
- }
- finally
- {
- _state = State.Completed;
- _gcTask = null;
- _timeoutTask = null;
-
- if (_listenTask != null)
- {
- CloseListenTask();
- }
- }
- }
-
-
- private void CheckCompletedTasks(CancellationToken cancellationToken)
- {
- if (cancellationToken.IsCancellationRequested)
- {
- HandleCancellation();
- return;
- }
-
- if (_listenTask.IsCompleted)
- {
- HandleCompletedListenTask(cancellationToken);
- }
-
- if (_timeoutTask?.IsCompleted == true)
- {
- HandleCompletedTimeoutTask();
- }
-
- if (_gcTask?.IsCompleted == true)
- {
- HandleCompletedGCTask();
- }
-
- HandleCompletedConnections();
- }
-
- private void HandleCancellation()
- {
- Debug.Assert(_listenTask != null);
-
- // If cancellation has been requested then the server needs to be in the process
- // of shutting down.
- _state = State.ShuttingDown;
-
- CloseListenTask();
-
- try
- {
- Task.WaitAll(_connections.ToArray());
- }
- catch
- {
- // It's expected that some will throw exceptions, in particular OperationCanceledException. It's
- // okay for them to throw so long as they complete.
- }
-
- HandleCompletedConnections();
- Debug.Assert(_connections.Count == 0);
- }
-
- ///
- /// The server farms out work to Task values and this method needs to wait until at least one of them
- /// has completed.
- ///
- private void WaitForAnyCompletion(CancellationToken cancellationToken)
- {
- var all = new List(_connections.Count + 3);
- all.AddRange(_connections);
- all.Add(_timeoutTask);
- all.Add(_listenTask);
- all.Add(_gcTask);
-
- try
- {
- var waitArray = all.Where(x => x != null).ToArray();
- Task.WaitAny(waitArray, cancellationToken);
- }
- catch (OperationCanceledException)
- {
- // Thrown when the provided cancellationToken is cancelled. This is handled in the caller,
- // here it just serves to break out of the WaitAny call.
- }
- }
-
- private void Listen()
- {
- Debug.Assert(_listenTask == null);
- Debug.Assert(_timeoutTask == null);
-
- _listenCancellationTokenSource = new CancellationTokenSource();
- _listenTask = _connectionHost.WaitForConnectionAsync(_listenCancellationTokenSource.Token);
- _eventBus.ConnectionListening();
- }
-
- private void CloseListenTask()
- {
- Debug.Assert(_listenTask != null);
-
- _listenCancellationTokenSource.Cancel();
- _listenCancellationTokenSource = null;
- _listenTask = null;
- }
-
- private void HandleCompletedListenTask(CancellationToken cancellationToken)
- {
- _eventBus.ConnectionReceived();
-
- // Don't accept any new connections once we're in shutdown mode, instead gracefully reject the request.
- // This should cause the client to run in process.
- var accept = _state == State.Running;
- var connectionTask = AcceptConnection(_listenTask, accept, cancellationToken);
- _connections.Add(connectionTask);
-
- // Timeout and GC are only done when there are no active connections. Now that we have a new
- // connection cancel out these tasks.
- _timeoutTask = null;
- _gcTask = null;
-
- // Begin listening again for new connections.
- _listenTask = null;
- Listen();
- }
-
- private void HandleCompletedTimeoutTask()
- {
- _eventBus.KeepAliveReached();
- _listenCancellationTokenSource.Cancel();
- _timeoutTask = null;
- _state = State.ShuttingDown;
- }
-
- private void HandleCompletedGCTask()
- {
- _gcTask = null;
- for (var i = 0; i < 10; i++)
- {
- GC.Collect();
- GC.WaitForPendingFinalizers();
- }
-
- GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
- GC.Collect();
- }
-
- private void MaybeCreateTimeoutTask()
- {
- // If there are no active clients running then the server needs to be in a timeout mode.
- if (_connections.Count == 0 && _timeoutTask == null)
- {
- Debug.Assert(_listenTask != null);
- _timeoutTask = Task.Delay(_keepAlive.TimeSpan);
- }
- }
-
- private void MaybeCreateGCTask()
- {
- if (_connections.Count == 0 && _gcTask == null)
- {
- _gcTask = Task.Delay(GCTimeout);
- }
- }
-
- ///
- /// Checks the completed connection objects.
- ///
- /// False if the server needs to begin shutting down
- private void HandleCompletedConnections()
- {
- var shutdown = false;
- var processedCount = 0;
- var i = 0;
- while (i < _connections.Count)
- {
- var current = _connections[i];
- if (!current.IsCompleted)
- {
- i++;
- continue;
- }
-
- _connections.RemoveAt(i);
- processedCount++;
-
- var result = current.Result;
- if (result.KeepAlive.HasValue)
- {
- var updated = _keepAlive.Update(result.KeepAlive.Value);
- if (updated.Equals(_keepAlive))
- {
- _eventBus.UpdateKeepAlive(updated.TimeSpan);
- }
- }
-
- switch (result.CloseReason)
- {
- case ConnectionResult.Reason.CompilationCompleted:
- case ConnectionResult.Reason.CompilationNotStarted:
- // These are all normal end states. Nothing to do here.
- break;
-
- case ConnectionResult.Reason.ClientDisconnect:
- // Have to assume the worst here which is user pressing Ctrl+C at the command line and
- // hence wanting all compilation to end.
- _eventBus.ConnectionRudelyEnded();
- shutdown = true;
- break;
-
- case ConnectionResult.Reason.ClientException:
- case ConnectionResult.Reason.ClientShutdownRequest:
- _eventBus.ConnectionRudelyEnded();
- shutdown = true;
- break;
-
- default:
- throw new InvalidOperationException($"Unexpected enum value {result.CloseReason}");
- }
- }
-
- if (processedCount > 0)
- {
- _eventBus.ConnectionCompleted(processedCount);
- }
-
- if (shutdown)
- {
- _state = State.ShuttingDown;
- }
- }
-
- internal async Task AcceptConnection(Task task, bool accept, CancellationToken cancellationToken)
- {
- Connection connection;
- try
- {
- connection = await task;
- }
- catch (Exception ex)
- {
- // Unable to establish a connection with the client. The client is responsible for
- // handling this case. Nothing else for us to do here.
- ServerLogger.LogException(ex, "Error creating client named pipe");
- return new ConnectionResult(ConnectionResult.Reason.CompilationNotStarted);
- }
-
- try
- {
- using (connection)
- {
- ServerRequest request;
- try
- {
- ServerLogger.Log("Begin reading request.");
- request = await ServerRequest.ReadAsync(connection.Stream, cancellationToken).ConfigureAwait(false);
- ServerLogger.Log("End reading request.");
- }
- catch (Exception e)
- {
- ServerLogger.LogException(e, "Error reading build request.");
- return new ConnectionResult(ConnectionResult.Reason.CompilationNotStarted);
- }
-
- if (request.IsShutdownRequest())
- {
- // Reply with the PID of this process so that the client can wait for it to exit.
- var response = new ShutdownServerResponse(Process.GetCurrentProcess().Id);
- await response.WriteAsync(connection.Stream, cancellationToken);
-
- // We can safely disconnect the client, then when this connection gets cleaned up by the event loop
- // the server will go to a shutdown state.
- return new ConnectionResult(ConnectionResult.Reason.ClientShutdownRequest);
- }
- else if (!accept)
- {
- // We're already in shutdown mode, respond gracefully so the client can run in-process.
- var response = new RejectedServerResponse();
- await response.WriteAsync(connection.Stream, cancellationToken).ConfigureAwait(false);
-
- return new ConnectionResult(ConnectionResult.Reason.CompilationNotStarted);
- }
- else
- {
- // If we get here then this is a real request that we will accept and process.
- //
- // Kick off both the compilation and a task to monitor the pipe for closing.
- var buildCancelled = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
-
- var watcher = connection.WaitForDisconnectAsync(buildCancelled.Token);
- var worker = ExecuteRequestAsync(request, buildCancelled.Token);
-
- // await will end when either the work is complete or the connection is closed.
- await Task.WhenAny(worker, watcher);
-
- // Do an 'await' on the completed task, preference being compilation, to force
- // any exceptions to be realized in this method for logging.
- ConnectionResult.Reason reason;
- if (worker.IsCompleted)
- {
- var response = await worker;
-
- try
- {
- ServerLogger.Log("Begin writing response.");
- await response.WriteAsync(connection.Stream, cancellationToken);
- ServerLogger.Log("End writing response.");
-
- reason = ConnectionResult.Reason.CompilationCompleted;
-
- _eventBus.CompilationCompleted();
- }
- catch
- {
- reason = ConnectionResult.Reason.ClientDisconnect;
- }
- }
- else
- {
- await watcher;
- reason = ConnectionResult.Reason.ClientDisconnect;
- }
-
- // Begin the tear down of the Task which didn't complete.
- buildCancelled.Cancel();
-
- return new ConnectionResult(reason, request.KeepAlive);
- }
- }
- }
- catch (Exception ex)
- {
- ServerLogger.LogException(ex, "Error handling connection");
- return new ConnectionResult(ConnectionResult.Reason.ClientException);
- }
- }
-
- private Task ExecuteRequestAsync(ServerRequest buildRequest, CancellationToken cancellationToken)
- {
- Func func = () =>
- {
- ServerLogger.Log("Begin processing request");
-
- var response = _compilerHost.Execute(buildRequest, cancellationToken);
-
- ServerLogger.Log("End processing request");
- return response;
- };
-
- var task = new Task(func, cancellationToken, TaskCreationOptions.LongRunning);
- task.Start();
- return task;
- }
-
- private enum State
- {
- ///
- /// Server running and accepting all requests
- ///
- Running,
-
- ///
- /// Server processing existing requests, responding to shutdown commands but is not accepting
- /// new build requests.
- ///
- ShuttingDown,
-
- ///
- /// Server is done.
- ///
- Completed,
- }
-
- private struct KeepAlive
- {
- public TimeSpan TimeSpan;
- public bool IsDefault;
-
- public KeepAlive(TimeSpan timeSpan, bool isDefault)
- {
- TimeSpan = timeSpan;
- IsDefault = isDefault;
- }
-
- public KeepAlive Update(TimeSpan timeSpan)
- {
- if (IsDefault || timeSpan > TimeSpan)
- {
- return new KeepAlive(timeSpan, isDefault: false);
- }
-
- return this;
- }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DiscoverCommand.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DiscoverCommand.cs
deleted file mode 100644
index 7ac1ea23c711..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/DiscoverCommand.cs
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Security.Cryptography;
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Razor.Language;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.Razor;
-using Microsoft.CodeAnalysis.Razor.Serialization;
-using Microsoft.Extensions.CommandLineUtils;
-using Newtonsoft.Json;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal class DiscoverCommand : CommandBase
- {
- public DiscoverCommand(Application parent)
- : base(parent, "discover")
- {
- Assemblies = Argument("assemblies", "assemblies to search for tag helpers", multipleValues: true);
- TagHelperManifest = Option("-o", "output file", CommandOptionType.SingleValue);
- ProjectDirectory = Option("-p", "project root directory", CommandOptionType.SingleValue);
- Version = Option("-v|--version", "Razor language version", CommandOptionType.SingleValue);
- Configuration = Option("-c", "Razor configuration name", CommandOptionType.SingleValue);
- ExtensionNames = Option("-n", "extension name", CommandOptionType.MultipleValue);
- ExtensionFilePaths = Option("-e", "extension file path", CommandOptionType.MultipleValue);
- }
-
- public CommandArgument Assemblies { get; }
-
- public CommandOption TagHelperManifest { get; }
-
- public CommandOption ProjectDirectory { get; }
-
- public CommandOption Version { get; }
-
- public CommandOption Configuration { get; }
-
- public CommandOption ExtensionNames { get; }
-
- public CommandOption ExtensionFilePaths { get; }
-
- protected override bool ValidateArguments()
- {
- if (string.IsNullOrEmpty(TagHelperManifest.Value()))
- {
- Error.WriteLine($"{TagHelperManifest.Description} must be specified.");
- return false;
- }
-
- if (Assemblies.Values.Count == 0)
- {
- Error.WriteLine($"{Assemblies.Name} must have at least one value.");
- return false;
- }
-
- if (string.IsNullOrEmpty(ProjectDirectory.Value()))
- {
- ProjectDirectory.Values.Add(Environment.CurrentDirectory);
- }
-
- if (string.IsNullOrEmpty(Version.Value()))
- {
- Error.WriteLine($"{Version.Description} must be specified.");
- return false;
- }
- else if (!RazorLanguageVersion.TryParse(Version.Value(), out _))
- {
- Error.WriteLine($"Invalid option {Version.Value()} for Razor language version --version; must be Latest or a valid version in range {RazorLanguageVersion.Version_1_0} to {RazorLanguageVersion.Latest}.");
- return false;
- }
-
- if (string.IsNullOrEmpty(Configuration.Value()))
- {
- Error.WriteLine($"{Configuration.Description} must be specified.");
- return false;
- }
-
- if (ExtensionNames.Values.Count != ExtensionFilePaths.Values.Count)
- {
- Error.WriteLine($"{ExtensionNames.Description} and {ExtensionFilePaths.Description} should have the same number of values.");
- }
-
- foreach (var filePath in ExtensionFilePaths.Values)
- {
- if (!Path.IsPathRooted(filePath))
- {
- Error.WriteLine($"Extension file paths must be fully-qualified, absolute paths.");
- return false;
- }
- }
-
- return true;
- }
-
- protected override Task ExecuteCoreAsync()
- {
- if (!Parent.Checker.Check(ExtensionFilePaths.Values))
- {
- Error.WriteLine($"Extenions could not be loaded. See output for details.");
- return Task.FromResult(ExitCodeFailure);
- }
-
- // Loading all of the extensions should succeed as the dependency checker will have already
- // loaded them.
- var extensions = new RazorExtension[ExtensionNames.Values.Count];
- for (var i = 0; i < ExtensionNames.Values.Count; i++)
- {
- extensions[i] = new AssemblyExtension(ExtensionNames.Values[i], Parent.Loader.LoadFromPath(ExtensionFilePaths.Values[i]));
- }
-
- var version = RazorLanguageVersion.Parse(Version.Value());
- var configuration = RazorConfiguration.Create(version, Configuration.Value(), extensions);
-
- var result = ExecuteCore(
- configuration: configuration,
- projectDirectory: ProjectDirectory.Value(),
- outputFilePath: TagHelperManifest.Value(),
- assemblies: Assemblies.Values.ToArray());
-
- return Task.FromResult(result);
- }
-
- private int ExecuteCore(RazorConfiguration configuration, string projectDirectory, string outputFilePath, string[] assemblies)
- {
- outputFilePath = Path.Combine(projectDirectory, outputFilePath);
-
- var metadataReferences = new MetadataReference[assemblies.Length];
- for (var i = 0; i < assemblies.Length; i++)
- {
- metadataReferences[i] = Parent.AssemblyReferenceProvider(assemblies[i], default(MetadataReferenceProperties));
- }
-
- var engine = RazorProjectEngine.Create(configuration, RazorProjectFileSystem.Empty, b =>
- {
- b.Features.Add(new DefaultMetadataReferenceFeature() { References = metadataReferences });
- b.Features.Add(new CompilationTagHelperFeature());
- b.Features.Add(new DefaultTagHelperDescriptorProvider());
-
- CompilerFeatures.Register(b);
- });
-
- var feature = engine.Engine.Features.OfType().Single();
- var tagHelpers = feature.GetDescriptors();
-
- using (var stream = new MemoryStream())
- {
- Serialize(stream, tagHelpers);
-
- stream.Position = 0;
-
- var newHash = Hash(stream);
- var existingHash = Hash(outputFilePath);
-
- if (!HashesEqual(newHash, existingHash))
- {
- stream.Position = 0;
- using (var output = File.Open(outputFilePath, FileMode.Create))
- {
- stream.CopyTo(output);
- }
- }
- }
-
- return ExitCodeSuccess;
- }
-
- private static byte[] Hash(string path)
- {
- if (!File.Exists(path))
- {
- return Array.Empty();
- }
-
- using (var stream = File.OpenRead(path))
- {
- return Hash(stream);
- }
- }
-
- private static byte[] Hash(Stream stream)
- {
- using (var sha = SHA256.Create())
- {
- sha.ComputeHash(stream);
- return sha.Hash;
- }
- }
-
- private bool HashesEqual(byte[] x, byte[] y)
- {
- if (x.Length != y.Length)
- {
- return false;
- }
-
- for (var i = 0; i < x.Length; i++)
- {
- if (x[i] != y[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
- private static void Serialize(Stream stream, IReadOnlyList tagHelpers)
- {
- using (var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 4096, leaveOpen: true))
- {
- var serializer = new JsonSerializer();
- serializer.Converters.Add(new TagHelperDescriptorJsonConverter());
- serializer.Converters.Add(new RazorDiagnosticJsonConverter());
-
- serializer.Serialize(writer, tagHelpers);
- }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/EventBus.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/EventBus.cs
deleted file mode 100644
index dacd5c07e798..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/EventBus.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal abstract class EventBus
- {
- public static readonly EventBus Default = new DefaultEventBus();
-
- ///
- /// Called when the server updates the keep alive value.
- ///
- public virtual void UpdateKeepAlive(TimeSpan timeSpan)
- {
- }
-
- ///
- /// Called each time the server listens for new connections.
- ///
- public virtual void ConnectionListening()
- {
- }
-
- ///
- /// Called when a connection to the server occurs.
- ///
- public virtual void ConnectionReceived()
- {
- }
-
- ///
- /// Called when one or more connections have completed processing. The number of connections
- /// processed is provided in .
- ///
- public virtual void ConnectionCompleted(int count)
- {
- }
-
- ///
- /// Called when a compilation is completed successfully and the response is written to the stream.
- ///
- public virtual void CompilationCompleted()
- {
- }
-
- ///
- /// Called when a bad client connection was detected and the server will be shutting down as a
- /// result.
- ///
- public virtual void ConnectionRudelyEnded()
- {
- }
-
- ///
- /// Called when the server is shutting down because the keep alive timeout was reached.
- ///
- public virtual void KeepAliveReached()
- {
- }
-
- private class DefaultEventBus : EventBus
- {
-
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ExtensionAssemblyLoader.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ExtensionAssemblyLoader.cs
deleted file mode 100644
index 071eec2f824b..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ExtensionAssemblyLoader.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright(c) .NET Foundation.All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Reflection;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal abstract class ExtensionAssemblyLoader
- {
- public abstract void AddAssemblyLocation(string filePath);
-
- public abstract Assembly Load(string assemblyName);
-
- public abstract Assembly LoadFromPath(string filePath);
- }
-}
\ No newline at end of file
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ExtensionDependencyChecker.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ExtensionDependencyChecker.cs
deleted file mode 100644
index 02fd86d9e827..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ExtensionDependencyChecker.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Collections.Generic;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal abstract class ExtensionDependencyChecker
- {
- public abstract bool Check(IEnumerable extensionFilePaths);
- }
-}
\ No newline at end of file
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/GenerateCommand.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/GenerateCommand.cs
deleted file mode 100644
index 229d62a0404f..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/GenerateCommand.cs
+++ /dev/null
@@ -1,425 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Razor.Language;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.Razor;
-using Microsoft.CodeAnalysis.Razor.Serialization;
-using Microsoft.Extensions.CommandLineUtils;
-using Newtonsoft.Json;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal class GenerateCommand : CommandBase
- {
- public GenerateCommand(Application parent)
- : base(parent, "generate")
- {
- Sources = Option("-s", ".cshtml files to compile", CommandOptionType.MultipleValue);
- Outputs = Option("-o", "Generated output file path", CommandOptionType.MultipleValue);
- RelativePaths = Option("-r", "Relative path", CommandOptionType.MultipleValue);
- FileKinds = Option("-k", "File kind", CommandOptionType.MultipleValue);
- CssScopeSources = Option("-cssscopedinput", ".razor file with scoped CSS", CommandOptionType.MultipleValue);
- CssScopeValues = Option("-cssscopevalue", "CSS scope value for .razor file with scoped CSS", CommandOptionType.MultipleValue);
- ProjectDirectory = Option("-p", "project root directory", CommandOptionType.SingleValue);
- TagHelperManifest = Option("-t", "tag helper manifest file", CommandOptionType.SingleValue);
- Version = Option("-v|--version", "Razor language version", CommandOptionType.SingleValue);
- Configuration = Option("-c", "Razor configuration name", CommandOptionType.SingleValue);
- ExtensionNames = Option("-n", "extension name", CommandOptionType.MultipleValue);
- ExtensionFilePaths = Option("-e", "extension file path", CommandOptionType.MultipleValue);
- RootNamespace = Option("--root-namespace", "root namespace for generated code", CommandOptionType.SingleValue);
- CSharpLanguageVersion = Option("--csharp-language-version", "csharp language version generated code", CommandOptionType.SingleValue);
- GenerateDeclaration = Option("--generate-declaration", "Generate declaration", CommandOptionType.NoValue);
- }
-
- public CommandOption Sources { get; }
-
- public CommandOption Outputs { get; }
-
- public CommandOption RelativePaths { get; }
-
- public CommandOption FileKinds { get; }
-
- public CommandOption CssScopeSources { get; }
-
- public CommandOption CssScopeValues { get; }
-
- public CommandOption ProjectDirectory { get; }
-
- public CommandOption TagHelperManifest { get; }
-
- public CommandOption Version { get; }
-
- public CommandOption Configuration { get; }
-
- public CommandOption ExtensionNames { get; }
-
- public CommandOption ExtensionFilePaths { get; }
-
- public CommandOption RootNamespace { get; }
-
- public CommandOption CSharpLanguageVersion { get; }
-
- public CommandOption GenerateDeclaration { get; }
-
- protected override Task ExecuteCoreAsync()
- {
- if (!Parent.Checker.Check(ExtensionFilePaths.Values))
- {
- Error.WriteLine($"Extensions could not be loaded. See output for details.");
- return Task.FromResult(ExitCodeFailure);
- }
-
- // Loading all of the extensions should succeed as the dependency checker will have already
- // loaded them.
- var extensions = new RazorExtension[ExtensionNames.Values.Count];
- for (var i = 0; i < ExtensionNames.Values.Count; i++)
- {
- extensions[i] = new AssemblyExtension(ExtensionNames.Values[i], Parent.Loader.LoadFromPath(ExtensionFilePaths.Values[i]));
- }
-
- var version = RazorLanguageVersion.Parse(Version.Value());
- var configuration = RazorConfiguration.Create(version, Configuration.Value(), extensions);
-
- var sourceItems = GetSourceItems(
- Sources.Values, Outputs.Values, RelativePaths.Values,
- FileKinds.Values, CssScopeSources.Values, CssScopeValues.Values);
-
- var result = ExecuteCore(
- configuration: configuration,
- projectDirectory: ProjectDirectory.Value(),
- tagHelperManifest: TagHelperManifest.Value(),
- sourceItems: sourceItems);
-
- return Task.FromResult(result);
- }
-
- protected override bool ValidateArguments()
- {
- if (Sources.Values.Count == 0)
- {
- Error.WriteLine($"{Sources.Description} should have at least one value.");
- return false;
- }
-
- if (Outputs.Values.Count != Sources.Values.Count)
- {
- Error.WriteLine($"{Sources.Description} has {Sources.Values.Count}, but {Outputs.Description} has {Outputs.Values.Count} values.");
- return false;
- }
-
- if (RelativePaths.Values.Count != Sources.Values.Count)
- {
- Error.WriteLine($"{Sources.Description} has {Sources.Values.Count}, but {RelativePaths.Description} has {RelativePaths.Values.Count} values.");
- return false;
- }
-
- if (FileKinds.Values.Count != 0 && FileKinds.Values.Count != Sources.Values.Count)
- {
- // 2.x tasks do not specify FileKinds - in which case, no values will be present. If a kind for one file is specified, we expect as many kind entries
- // as sources.
- Error.WriteLine($"{Sources.Description} has {Sources.Values.Count}, but {FileKinds.Description} has {FileKinds.Values.Count} values.");
- return false;
- }
-
- if (CssScopeSources.Values.Count != CssScopeValues.Values.Count)
- {
- // CssScopeSources and CssScopeValues arguments must appear as matched pairs
- Error.WriteLine($"{CssScopeSources.Description} has {CssScopeSources.Values.Count}, but {CssScopeValues.Description} has {CssScopeValues.Values.Count} values.");
- return false;
- }
-
- if (string.IsNullOrEmpty(ProjectDirectory.Value()))
- {
- ProjectDirectory.Values.Add(Environment.CurrentDirectory);
- }
-
- if (string.IsNullOrEmpty(Version.Value()))
- {
- Error.WriteLine($"{Version.Description} must be specified.");
- return false;
- }
- else if (!RazorLanguageVersion.TryParse(Version.Value(), out _))
- {
- Error.WriteLine($"Invalid option {Version.Value()} for Razor language version --version; must be Latest or a valid version in range {RazorLanguageVersion.Version_1_0} to {RazorLanguageVersion.Latest}.");
- return false;
- }
-
- if (string.IsNullOrEmpty(Configuration.Value()))
- {
- Error.WriteLine($"{Configuration.Description} must be specified.");
- return false;
- }
-
- if (ExtensionNames.Values.Count != ExtensionFilePaths.Values.Count)
- {
- Error.WriteLine($"{ExtensionNames.Description} and {ExtensionFilePaths.Description} should have the same number of values.");
- }
-
- foreach (var filePath in ExtensionFilePaths.Values)
- {
- if (!Path.IsPathRooted(filePath))
- {
- Error.WriteLine($"Extension file paths must be fully-qualified, absolute paths.");
- return false;
- }
- }
-
- return true;
- }
-
- private int ExecuteCore(
- RazorConfiguration configuration,
- string projectDirectory,
- string tagHelperManifest,
- SourceItem[] sourceItems)
- {
- tagHelperManifest = Path.Combine(projectDirectory, tagHelperManifest);
-
- var tagHelpers = GetTagHelpers(tagHelperManifest);
-
- var compositeFileSystem = new CompositeRazorProjectFileSystem(new[]
- {
- GetVirtualRazorProjectSystem(sourceItems),
- RazorProjectFileSystem.Create(projectDirectory),
- });
-
- var success = true;
-
- var engine = RazorProjectEngine.Create(configuration, compositeFileSystem, b =>
- {
- b.Features.Add(new StaticTagHelperFeature() { TagHelpers = tagHelpers, });
- b.Features.Add(new DefaultTypeNameFeature());
-
- if (GenerateDeclaration.HasValue())
- {
- b.Features.Add(new SetSuppressPrimaryMethodBodyOptionFeature());
- b.Features.Add(new SuppressChecksumOptionsFeature());
- }
-
- if (RootNamespace.HasValue())
- {
- b.SetRootNamespace(RootNamespace.Value());
- }
-
- if (CSharpLanguageVersion.HasValue())
- {
- // Only set the C# language version if one was specified, otherwise it defaults to whatever
- // value was set in the corresponding RazorConfiguration's extensions.
-
- var rawLanguageVersion = CSharpLanguageVersion.Value();
- if (LanguageVersionFacts.TryParse(rawLanguageVersion, out var csharpLanguageVersion))
- {
- b.SetCSharpLanguageVersion(csharpLanguageVersion);
- }
- else
- {
- success = false;
- Error.WriteLine($"Unknown C# language version {rawLanguageVersion}.");
- }
- }
- });
-
- var results = GenerateCode(engine, sourceItems);
- var isGeneratingDeclaration = GenerateDeclaration.HasValue();
-
- foreach (var result in results)
- {
- var errorCount = result.CSharpDocument.Diagnostics.Count;
- for (var i = 0; i < errorCount; i++)
- {
- var error = result.CSharpDocument.Diagnostics[i];
- if (error.Severity == RazorDiagnosticSeverity.Error)
- {
- success = false;
- }
-
- if (i < 100)
- {
- Error.WriteLine(error.ToString());
-
- // Only show the first 100 errors to prevent massive string allocations.
- if (i == 99)
- {
- Error.WriteLine($"And {errorCount - i + 1} more warnings/errors.");
- }
- }
- }
-
- if (success)
- {
- // Only output the file if we generated it without errors.
- var outputFilePath = result.InputItem.OutputPath;
- var generatedCode = result.CSharpDocument.GeneratedCode;
- if (isGeneratingDeclaration)
- {
- // When emiting declarations, only write if it the contents are different.
- // This allows build incrementalism to kick in when the declaration remains unchanged between builds.
- if (File.Exists(outputFilePath) &&
- string.Equals(File.ReadAllText(outputFilePath), generatedCode, StringComparison.Ordinal))
- {
- continue;
- }
- }
-
- File.WriteAllText(outputFilePath, result.CSharpDocument.GeneratedCode);
- }
- }
-
- return success ? ExitCodeSuccess : ExitCodeFailureRazorError;
- }
-
- private VirtualRazorProjectFileSystem GetVirtualRazorProjectSystem(SourceItem[] inputItems)
- {
- var project = new VirtualRazorProjectFileSystem();
- foreach (var item in inputItems)
- {
- var projectItem = new DefaultRazorProjectItem(
- basePath: "/",
- filePath: item.FilePath,
- relativePhysicalPath: item.RelativePhysicalPath,
- fileKind: item.FileKind,
- file: new FileInfo(item.SourcePath),
- cssScope: item.CssScope);
-
- project.Add(projectItem);
- }
-
- return project;
- }
-
- private IReadOnlyList GetTagHelpers(string tagHelperManifest)
- {
- if (!File.Exists(tagHelperManifest))
- {
- return Array.Empty();
- }
-
- using (var stream = File.OpenRead(tagHelperManifest))
- {
- var reader = new JsonTextReader(new StreamReader(stream));
-
- var serializer = new JsonSerializer();
- serializer.Converters.Add(new RazorDiagnosticJsonConverter());
- serializer.Converters.Add(new TagHelperDescriptorJsonConverter());
-
- var descriptors = serializer.Deserialize>(reader);
- return descriptors;
- }
- }
-
- private static SourceItem[] GetSourceItems(List sources, List outputs, List relativePath, List fileKinds, List cssScopeSources, List cssScopeValues)
- {
- var cssScopeAssociations = new Dictionary(StringComparer.OrdinalIgnoreCase);
- for (var cssScopeSourceIndex = 0; cssScopeSourceIndex < cssScopeSources.Count; cssScopeSourceIndex++)
- {
- cssScopeAssociations.Add(cssScopeSources[cssScopeSourceIndex], cssScopeSourceIndex);
- }
-
- var items = new SourceItem[sources.Count];
- for (var i = 0; i < items.Length; i++)
- {
- var fileKind = fileKinds.Count > 0 ? fileKinds[i] : "mvc";
- if (Language.FileKinds.IsComponent(fileKind))
- {
- fileKind = Language.FileKinds.GetComponentFileKindFromFilePath(sources[i]);
- }
-
- var cssScopeValue = cssScopeAssociations.TryGetValue(sources[i], out var cssScopeIndex)
- ? cssScopeValues[cssScopeIndex]
- : null;
-
- items[i] = new SourceItem(sources[i], outputs[i], relativePath[i], fileKind, cssScopeValue);
- }
-
- return items;
- }
-
- private OutputItem[] GenerateCode(RazorProjectEngine engine, SourceItem[] inputs)
- {
- var outputs = new OutputItem[inputs.Length];
- Parallel.For(0, outputs.Length, new ParallelOptions() { MaxDegreeOfParallelism = Debugger.IsAttached ? 1 : 4 }, i =>
- {
- var inputItem = inputs[i];
-
- var codeDocument = engine.Process(engine.FileSystem.GetItem(inputItem.FilePath, inputItem.FileKind));
- var csharpDocument = codeDocument.GetCSharpDocument();
- outputs[i] = new OutputItem(inputItem, csharpDocument);
- });
-
- return outputs;
- }
-
- private struct OutputItem
- {
- public OutputItem(
- SourceItem inputItem,
- RazorCSharpDocument cSharpDocument)
- {
- InputItem = inputItem;
- CSharpDocument = cSharpDocument;
- }
-
- public SourceItem InputItem { get; }
-
- public RazorCSharpDocument CSharpDocument { get; }
- }
-
- private readonly struct SourceItem
- {
- public SourceItem(string sourcePath, string outputPath, string physicalRelativePath, string fileKind, string cssScope)
- {
- SourcePath = sourcePath;
- OutputPath = outputPath;
- RelativePhysicalPath = physicalRelativePath;
- FilePath = '/' + physicalRelativePath
- .Replace(Path.DirectorySeparatorChar, '/')
- .Replace("//", "/");
- FileKind = fileKind;
- CssScope = cssScope;
- }
-
- public string SourcePath { get; }
-
- public string OutputPath { get; }
-
- public string RelativePhysicalPath { get; }
-
- public string FilePath { get; }
-
- public string FileKind { get; }
-
- public string CssScope { get; }
- }
-
- private class StaticTagHelperFeature : ITagHelperFeature
- {
- public RazorEngine Engine { get; set; }
-
- public IReadOnlyList TagHelpers { get; set; }
-
- public IReadOnlyList GetDescriptors() => TagHelpers;
- }
-
- private class SetSuppressPrimaryMethodBodyOptionFeature : RazorEngineFeatureBase, IConfigureRazorCodeGenerationOptionsFeature
- {
- public int Order { get; set; }
-
- public void Configure(RazorCodeGenerationOptionsBuilder options)
- {
- if (options == null)
- {
- throw new ArgumentNullException(nameof(options));
- }
-
- options.SuppressPrimaryMethodBody = true;
- }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Memory.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Memory.cs
deleted file mode 100644
index e0187ed633b7..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Memory.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal static class Memory
- {
- public static bool IsMemoryAvailable()
- {
- return true;
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/MetadataCache.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/MetadataCache.cs
deleted file mode 100644
index b0f9fd025e7c..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/MetadataCache.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Reflection.PortableExecutable;
-using Microsoft.CodeAnalysis;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal class MetadataCache
- {
- // Store 1000 entries -- arbitrary number
- private const int CacheSize = 1000;
- private readonly ConcurrentLruCache _metadataCache =
- new ConcurrentLruCache(CacheSize, StringComparer.OrdinalIgnoreCase);
-
- // For testing purposes only.
- internal ConcurrentLruCache Cache => _metadataCache;
-
- internal Metadata GetMetadata(string fullPath)
- {
- var timestamp = GetFileTimeStamp(fullPath);
-
- // Check if we have an entry in the dictionary.
- if (_metadataCache.TryGetValue(fullPath, out var entry))
- {
- if (timestamp.HasValue && timestamp.Value == entry.Timestamp)
- {
- // The file has not changed since we cached it. Return the cached entry.
- return entry.Metadata;
- }
- else
- {
- // The file has changed recently. Remove the cache entry.
- _metadataCache.Remove(fullPath);
- }
- }
-
- Metadata metadata;
- using (var fileStream = File.OpenRead(fullPath))
- {
- metadata = AssemblyMetadata.CreateFromStream(fileStream, PEStreamOptions.PrefetchMetadata);
- }
-
- _metadataCache.GetOrAdd(fullPath, new MetadataCacheEntry(timestamp.Value, metadata));
-
- return metadata;
- }
-
- private static DateTime? GetFileTimeStamp(string fullPath)
- {
- try
- {
- Debug.Assert(Path.IsPathRooted(fullPath));
-
- return File.GetLastWriteTimeUtc(fullPath);
- }
- catch (Exception e)
- {
- // There are several exceptions that can occur here: NotSupportedException or PathTooLongException
- // for a bad path, UnauthorizedAccessException for access denied, etc. Rather than listing them all,
- // just catch all exceptions and log.
- ServerLogger.LogException(e, $"Error getting timestamp of file {fullPath}.");
-
- return null;
- }
- }
-
- internal struct MetadataCacheEntry
- {
- public MetadataCacheEntry(DateTime timestamp, Metadata metadata)
- {
- Debug.Assert(timestamp.Kind == DateTimeKind.Utc);
-
- Timestamp = timestamp;
- Metadata = metadata;
- }
-
- public DateTime Timestamp { get; }
-
- public Metadata Metadata { get; }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/MetadataReaderExtensions.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/MetadataReaderExtensions.cs
deleted file mode 100644
index 7becdaca4143..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/MetadataReaderExtensions.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Reflection;
-using System.Reflection.Metadata;
-using Microsoft.CodeAnalysis;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal static class MetadataReaderExtensions
- {
- internal static AssemblyIdentity GetAssemblyIdentity(this MetadataReader reader)
- {
- if (!reader.IsAssembly)
- {
- throw new BadImageFormatException();
- }
-
- var definition = reader.GetAssemblyDefinition();
-
- return CreateAssemblyIdentity(
- reader,
- definition.Version,
- definition.Flags,
- definition.PublicKey,
- definition.Name,
- definition.Culture,
- isReference: false);
- }
-
- internal static AssemblyIdentity[] GetReferencedAssembliesOrThrow(this MetadataReader reader)
- {
- var references = new List(reader.AssemblyReferences.Count);
-
- foreach (var referenceHandle in reader.AssemblyReferences)
- {
- var reference = reader.GetAssemblyReference(referenceHandle);
- references.Add(CreateAssemblyIdentity(
- reader,
- reference.Version,
- reference.Flags,
- reference.PublicKeyOrToken,
- reference.Name,
- reference.Culture,
- isReference: true));
- }
-
- return references.ToArray();
- }
-
- private static AssemblyIdentity CreateAssemblyIdentity(
- MetadataReader reader,
- Version version,
- AssemblyFlags flags,
- BlobHandle publicKey,
- StringHandle name,
- StringHandle culture,
- bool isReference)
- {
- var publicKeyOrToken = reader.GetBlobContent(publicKey);
- bool hasPublicKey;
-
- if (isReference)
- {
- hasPublicKey = (flags & AssemblyFlags.PublicKey) != 0;
- }
- else
- {
- // Assembly definitions never contain a public key token, they only can have a full key or nothing,
- // so the flag AssemblyFlags.PublicKey does not make sense for them and is ignored.
- // See Ecma-335, Partition II Metadata, 22.2 "Assembly : 0x20".
- // This also corresponds to the behavior of the native C# compiler and sn.exe tool.
- hasPublicKey = !publicKeyOrToken.IsEmpty;
- }
-
- if (publicKeyOrToken.IsEmpty)
- {
- publicKeyOrToken = default;
- }
-
- return new AssemblyIdentity(
- name: reader.GetString(name),
- version: version,
- cultureName: culture.IsNil ? null : reader.GetString(culture),
- publicKeyOrToken: publicKeyOrToken,
- hasPublicKey: hasPublicKey,
- isRetargetable: (flags & AssemblyFlags.Retargetable) != 0,
- contentType: (AssemblyContentType)((int)(flags & AssemblyFlags.ContentTypeMask) >> 9));
- }
- }
-}
\ No newline at end of file
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/MutexName.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/MutexName.cs
deleted file mode 100644
index e12888080b4b..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/MutexName.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal static class MutexName
- {
- public static string GetClientMutexName(string pipeName)
- {
- return $"{pipeName}.client";
- }
-
- public static string GetServerMutexName(string pipeName)
- {
- // We want to prefix this with Global\ because we want this mutex to be visible
- // across terminal sessions which is useful for cases like shutdown.
- // https://msdn.microsoft.com/en-us/library/system.threading.mutex(v=vs.110).aspx#Remarks
- // This still wouldn't allow other users to access the server because the pipe will fail to connect.
- return $"Global\\{pipeName}.server";
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/PipeName.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/PipeName.cs
deleted file mode 100644
index 23fc72f90ca8..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/PipeName.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.IO;
-using System.Security.Cryptography;
-using System.Text;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal static class PipeName
- {
- // We want each pipe to unique and predictable based on the inputs of:
- // - user (security)
- // - path of tool on disk (version)
- //
- // This allows us to meet the security and version compat requirements just by selecting a pipe name.
- //
- // This is similar to (and based on) the code used by Roslyn in VBCSCompiler:
- // https://github.com/dotnet/roslyn/blob/c273b6a9f19570a344c274ae89185b3a2b64d93d/src/Compilers/Shared/BuildServerConnection.cs#L528
- public static string ComputeDefault(string toolDirectory = null)
- {
- if (string.IsNullOrEmpty(toolDirectory))
- {
- // This can be null in cases where we don't have a way of knowing the tool assembly path like when someone manually
- // invokes the cli tool without passing in a pipe name as argument.
- toolDirectory = AppDomain.CurrentDomain.BaseDirectory;
- }
-
- // Include a prefix so we can't conflict with VBCSCompiler if we somehow end up in the same directory.
- // That would be a pretty wacky bug to try and unravel.
- var baseName = ComputeBaseName("Razor:" + toolDirectory);
-
- // Prefix with username
- var userName = Environment.UserName;
- if (userName == null)
- {
- return null;
- }
-
- return $"{userName}.{baseName}";
- }
-
- private static string ComputeBaseName(string baseDirectory)
- {
- // Normalize away trailing slashes. File APIs are not consistent about including it, so it's
- // best to normalize and avoid ending up with two servers running accidentally.
- baseDirectory = baseDirectory.TrimEnd(Path.DirectorySeparatorChar);
-
- using (var sha = SHA256.Create())
- {
- var bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(baseDirectory));
- return Convert.ToBase64String(bytes)
- .Substring(0, 25) // We only have ~50 total characters on Mac, so strip that down
- .Replace("/", "_")
- .Replace("=", string.Empty);
- }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Program.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Program.cs
deleted file mode 100644
index 3cd93a2335a8..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Program.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.IO;
-using System.Threading;
-using Microsoft.CodeAnalysis;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal static class Program
- {
- public static int Main(string[] args)
- {
- DebugMode.HandleDebugSwitch(ref args);
-
- var cancel = new CancellationTokenSource();
- Console.CancelKeyPress += (sender, e) => { cancel.Cancel(); };
-
- var outputWriter = new StringWriter();
- var errorWriter = new StringWriter();
-
- // Prevent shadow copying.
- var loader = new DefaultExtensionAssemblyLoader(baseDirectory: null);
- var checker = new DefaultExtensionDependencyChecker(loader, outputWriter, errorWriter);
-
- var application = new Application(
- cancel.Token,
- loader,
- checker,
- (path, properties) => MetadataReference.CreateFromFile(path, properties),
- outputWriter,
- errorWriter);
-
- var result = application.Execute(args);
-
- var output = outputWriter.ToString();
- var error = errorWriter.ToString();
-
- outputWriter.Dispose();
- errorWriter.Dispose();
-
- Console.Write(output);
- Console.Error.Write(error);
-
- // This will no-op if server logging is not enabled.
- ServerLogger.Log(output);
- ServerLogger.Log(error);
-
- return result;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Properties/AssemblyInfo.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Properties/AssemblyInfo.cs
deleted file mode 100644
index 9cc0f63be190..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Runtime.CompilerServices;
-
-[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Tools.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
-[assembly: InternalsVisibleTo("Microsoft.NET.Sdk.Razor.IntegrationTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
-[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
-
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/RequestDispatcher.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/RequestDispatcher.cs
deleted file mode 100644
index 1b46d1cbf74d..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/RequestDispatcher.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Threading;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal abstract class RequestDispatcher
- {
- ///
- /// Default time the server will stay alive after the last request disconnects.
- ///
- public static readonly TimeSpan DefaultServerKeepAlive = TimeSpan.FromMinutes(10);
-
- ///
- /// Time to delay after the last connection before initiating a garbage collection
- /// in the server.
- ///
- public static readonly TimeSpan GCTimeout = TimeSpan.FromSeconds(30);
-
- public abstract void Run();
-
- public static RequestDispatcher Create(ConnectionHost connectionHost, CompilerHost compilerHost, CancellationToken cancellationToken, EventBus eventBus, TimeSpan? keepAlive = null)
- {
- return new DefaultRequestDispatcher(connectionHost, compilerHost, cancellationToken, eventBus, keepAlive);
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/RewriteCssCommand.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/RewriteCssCommand.cs
deleted file mode 100644
index ca227514887c..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/RewriteCssCommand.cs
+++ /dev/null
@@ -1,432 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Razor.Language;
-using Microsoft.CodeAnalysis.Text;
-using Microsoft.Css.Parser.Parser;
-using Microsoft.Css.Parser.Tokens;
-using Microsoft.Css.Parser.TreeItems;
-using Microsoft.Css.Parser.TreeItems.AtDirectives;
-using Microsoft.Css.Parser.TreeItems.Selectors;
-using Microsoft.Extensions.CommandLineUtils;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal class RewriteCssCommand : CommandBase
- {
- private const string DeepCombinatorText = "::deep";
- private readonly static TimeSpan _regexTimeout = TimeSpan.FromSeconds(1);
- private readonly static Regex _deepCombinatorRegex = new Regex($@"^{DeepCombinatorText}\s*", RegexOptions.None, _regexTimeout);
- private readonly static Regex _trailingCombinatorRegex = new Regex(@"\s+[\>\+\~]$", RegexOptions.None, _regexTimeout);
-
- public RewriteCssCommand(Application parent)
- : base(parent, "rewritecss")
- {
- Sources = Option("-s", "Files to rewrite", CommandOptionType.MultipleValue);
- Outputs = Option("-o", "Output file paths", CommandOptionType.MultipleValue);
- CssScopes = Option("-c", "CSS scope identifiers", CommandOptionType.MultipleValue);
- }
-
- public CommandOption Sources { get; }
-
- public CommandOption Outputs { get; }
-
- public CommandOption CssScopes { get; }
-
- protected override bool ValidateArguments()
- {
- if (Sources.Values.Count != Outputs.Values.Count)
- {
- Error.WriteLine($"{Sources.Description} has {Sources.Values.Count}, but {Outputs.Description} has {Outputs.Values.Count} values.");
- return false;
- }
-
- if (Sources.Values.Count != CssScopes.Values.Count)
- {
- Error.WriteLine($"{Sources.Description} has {Sources.Values.Count}, but {CssScopes.Description} has {CssScopes.Values.Count} values.");
- return false;
- }
-
- return true;
- }
-
- protected override Task ExecuteCoreAsync()
- {
- var allDiagnostics = new ConcurrentQueue();
-
- Parallel.For(0, Sources.Values.Count, i =>
- {
- var source = Sources.Values[i];
- var output = Outputs.Values[i];
- var cssScope = CssScopes.Values[i];
-
- using var inputSourceStream = new FileStream(source, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
- var inputSourceText = SourceText.From(inputSourceStream);
-
- var rewrittenCss = AddScopeToSelectors(source, inputSourceText, cssScope, out var diagnostics);
- if (diagnostics.Any())
- {
- foreach (var diagnostic in diagnostics)
- {
- allDiagnostics.Enqueue(diagnostic);
- }
- }
- else
- {
- File.WriteAllText(output, rewrittenCss);
- }
- });
-
- foreach (var diagnostic in allDiagnostics)
- {
- Error.WriteLine(diagnostic.ToString());
- }
-
- return Task.FromResult(allDiagnostics.Any() ? ExitCodeFailure : ExitCodeSuccess);
- }
-
- // Public for tests
- public static string AddScopeToSelectors(string filePath, string inputSource, string cssScope, out IEnumerable diagnostics)
- => AddScopeToSelectors(filePath, SourceText.From(inputSource), cssScope, out diagnostics);
-
- private static string AddScopeToSelectors(string filePath, SourceText inputSourceText, string cssScope, out IEnumerable diagnostics)
- {
- var cssParser = new DefaultParserFactory().CreateParser();
- var inputText = inputSourceText.ToString();
- var stylesheet = cssParser.Parse(inputText, insertComments: false);
-
- var resultBuilder = new StringBuilder();
- var previousInsertionPosition = 0;
- var foundDiagnostics = new List();
-
- var ensureNoImportsVisitor = new EnsureNoImports(filePath, inputSourceText, stylesheet, foundDiagnostics);
- ensureNoImportsVisitor.Visit();
-
- var scopeInsertionPositionsVisitor = new FindScopeInsertionEdits(stylesheet);
- scopeInsertionPositionsVisitor.Visit();
- foreach (var edit in scopeInsertionPositionsVisitor.Edits)
- {
- resultBuilder.Append(inputText.Substring(previousInsertionPosition, edit.Position - previousInsertionPosition));
- previousInsertionPosition = edit.Position;
-
- switch (edit)
- {
- case InsertSelectorScopeEdit _:
- resultBuilder.AppendFormat(CultureInfo.InvariantCulture, "[{0}]", cssScope);
- break;
- case InsertKeyframesNameScopeEdit _:
- resultBuilder.AppendFormat(CultureInfo.InvariantCulture, "-{0}", cssScope);
- break;
- case DeleteContentEdit deleteContentEdit:
- previousInsertionPosition += deleteContentEdit.DeleteLength;
- break;
- default:
- throw new NotImplementedException($"Unknown edit type: '{edit}'");
- }
- }
-
- resultBuilder.Append(inputText.Substring(previousInsertionPosition));
-
- diagnostics = foundDiagnostics;
- return resultBuilder.ToString();
- }
-
- private static bool TryFindKeyframesIdentifier(AtDirective atDirective, out ParseItem identifier)
- {
- var keyword = atDirective.Keyword;
- if (string.Equals(keyword?.Text, "keyframes", StringComparison.OrdinalIgnoreCase))
- {
- var nextSiblingText = keyword.NextSibling?.Text;
- if (!string.IsNullOrEmpty(nextSiblingText))
- {
- identifier = keyword.NextSibling;
- return true;
- }
- }
-
- identifier = null;
- return false;
- }
-
- private class FindScopeInsertionEdits : Visitor
- {
- public List Edits { get; } = new List();
-
- private readonly HashSet _keyframeIdentifiers;
-
- public FindScopeInsertionEdits(ComplexItem root) : base(root)
- {
- // Before we start, we need to know the full set of keyframe names declared in this document
- var keyframesIdentifiersVisitor = new FindKeyframesIdentifiersVisitor(root);
- keyframesIdentifiersVisitor.Visit();
- _keyframeIdentifiers = keyframesIdentifiersVisitor.KeyframesIdentifiers
- .Select(x => x.Text)
- .ToHashSet(StringComparer.Ordinal); // Keyframe names are case-sensitive
- }
-
- protected override void VisitSelector(Selector selector)
- {
- // For a ruleset like ".first child, .second { ... }", we'll see two selectors:
- // ".first child," containing two simple selectors: ".first" and "child"
- // ".second", containing one simple selector: ".second"
- // Our goal is to insert immediately after the final simple selector within each selector
-
- // If there's a deep combinator among the sequence of simple selectors, we consider that to signal
- // the end of the set of simple selectors for us to look at, plus we strip it out
- var allSimpleSelectors = selector.Children.OfType();
- var firstDeepCombinator = allSimpleSelectors.FirstOrDefault(s => _deepCombinatorRegex.IsMatch(s.Text));
-
- var lastSimpleSelector = allSimpleSelectors.TakeWhile(s => s != firstDeepCombinator).LastOrDefault();
- if (lastSimpleSelector != null)
- {
- Edits.Add(new InsertSelectorScopeEdit { Position = FindPositionToInsertInSelector(lastSimpleSelector) });
- }
- else if (firstDeepCombinator != null)
- {
- // For a leading deep combinator, we want to insert the scope attribute at the start
- // Otherwise the result would be a CSS rule that isn't scoped at all
- Edits.Add(new InsertSelectorScopeEdit { Position = firstDeepCombinator.Start });
- }
-
- // Also remove the deep combinator if we matched one
- if (firstDeepCombinator != null)
- {
- Edits.Add(new DeleteContentEdit { Position = firstDeepCombinator.Start, DeleteLength = DeepCombinatorText.Length });
- }
- }
-
- private int FindPositionToInsertInSelector(SimpleSelector lastSimpleSelector)
- {
- var children = lastSimpleSelector.Children;
- for (var i = 0; i < children.Count; i++)
- {
- switch (children[i])
- {
- // Selectors like "a > ::deep b" get parsed as [[a][>]][::deep][b], and we want to
- // insert right after the "a". So if we're processing a SimpleSelector like [[a][>]],
- // consider the ">" to signal the "insert before" position.
- case TokenItem t when IsTrailingCombinator(t.TokenType):
-
- // Similarly selectors like "a::before" get parsed as [[a][::before]], and we want to
- // insert right after the "a". So if we're processing a SimpleSelector like [[a][::before]],
- // consider the pseudoelement to signal the "insert before" position.
- case PseudoElementSelector:
- case PseudoElementFunctionSelector:
- case PseudoClassSelector s when IsSingleColonPseudoElement(s):
- // Insert after the previous token if there is one, otherwise before the whole thing
- return i > 0 ? children[i - 1].AfterEnd : lastSimpleSelector.Start;
- }
- }
-
- // Since we didn't find any children that signal the insert-before position,
- // insert after the whole thing
- return lastSimpleSelector.AfterEnd;
- }
-
- private static bool IsSingleColonPseudoElement(PseudoClassSelector selector)
- {
- // See https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements
- // Normally, pseudoelements require a double-colon prefix. However the following "original set"
- // of pseudoelements also support single-colon prefixes for back-compatibility with older versions
- // of the W3C spec. Our CSS parser sees them as pseudoselectors rather than pseudoelements, so
- // we have to special-case them. The single-colon option doesn't exist for other more modern
- // pseudoelements.
- var selectorText = selector.Text;
- return string.Equals(selectorText, ":after", StringComparison.OrdinalIgnoreCase)
- || string.Equals(selectorText, ":before", StringComparison.OrdinalIgnoreCase)
- || string.Equals(selectorText, ":first-letter", StringComparison.OrdinalIgnoreCase)
- || string.Equals(selectorText, ":first-line", StringComparison.OrdinalIgnoreCase);
- }
-
- private static bool IsTrailingCombinator(CssTokenType tokenType)
- {
- switch (tokenType)
- {
- case CssTokenType.Plus:
- case CssTokenType.Tilde:
- case CssTokenType.Greater:
- return true;
- default:
- return false;
- }
- }
-
- protected override void VisitAtDirective(AtDirective item)
- {
- // Whenever we see "@keyframes something { ... }", we want to insert right after "something"
- if (TryFindKeyframesIdentifier(item, out var identifier))
- {
- Edits.Add(new InsertKeyframesNameScopeEdit { Position = identifier.AfterEnd });
- }
- else
- {
- VisitDefault(item);
- }
- }
-
- protected override void VisitDeclaration(Declaration item)
- {
- switch (item.PropertyNameText)
- {
- case "animation":
- case "animation-name":
- // The first two tokens are and (otherwise we wouldn't be here).
- // After that, any of the subsequent tokens might be the animation name.
- // Unfortunately the rules for determining which token is the animation name are very
- // complex - https://developer.mozilla.org/en-US/docs/Web/CSS/animation#Syntax
- // Fortunately we only want to rewrite animation names that are explicitly declared in
- // the same document (we don't want to add scopes to references to global keyframes)
- // so it's sufficient just to match known animation names.
- var animationNameTokens = item.Children.Skip(2).OfType()
- .Where(x => x.TokenType == CssTokenType.Identifier && _keyframeIdentifiers.Contains(x.Text));
- foreach (var token in animationNameTokens)
- {
- Edits.Add(new InsertKeyframesNameScopeEdit { Position = token.AfterEnd });
- }
- break;
- default:
- // We don't need to do anything else with other declaration types
- break;
- }
- }
- }
-
- private class FindKeyframesIdentifiersVisitor : Visitor
- {
- public FindKeyframesIdentifiersVisitor(ComplexItem root) : base(root)
- {
- }
-
- public List KeyframesIdentifiers { get; } = new List();
-
- protected override void VisitAtDirective(AtDirective item)
- {
- if (TryFindKeyframesIdentifier(item, out var identifier))
- {
- KeyframesIdentifiers.Add(identifier);
- }
- else
- {
- VisitDefault(item);
- }
- }
- }
-
- private class EnsureNoImports : Visitor
- {
- private readonly string _filePath;
- private readonly SourceText _sourceText;
- private readonly List _diagnostics;
-
- public EnsureNoImports(string filePath, SourceText sourceText, ComplexItem root, List diagnostics) : base(root)
- {
- _filePath = filePath;
- _sourceText = sourceText;
- _diagnostics = diagnostics;
- }
-
- protected override void VisitAtDirective(AtDirective item)
- {
- if (item.Children.Count >= 2
- && item.Children[0] is TokenItem firstChild
- && firstChild.TokenType == CssTokenType.At
- && item.Children[1] is TokenItem secondChild
- && string.Equals(secondChild.Text, "import", StringComparison.OrdinalIgnoreCase))
- {
- var linePosition = _sourceText.Lines.GetLinePosition(item.Start);
- var sourceSpan = new SourceSpan(_filePath, item.Start, linePosition.Line, linePosition.Character, item.Length);
- _diagnostics.Add(RazorDiagnosticFactory.CreateCssRewriting_ImportNotAllowed(sourceSpan));
- }
-
- base.VisitAtDirective(item);
- }
- }
-
- private class Visitor
- {
- private readonly ComplexItem _root;
-
- public Visitor(ComplexItem root)
- {
- _root = root ?? throw new ArgumentNullException(nameof(root));
- }
-
- public void Visit()
- {
- VisitDefault(_root);
- }
-
- protected virtual void VisitSelector(Selector item)
- {
- VisitDefault(item);
- }
-
- protected virtual void VisitAtDirective(AtDirective item)
- {
- VisitDefault(item);
- }
-
- protected virtual void VisitDeclaration(Declaration item)
- {
- VisitDefault(item);
- }
-
- protected virtual void VisitDefault(ParseItem item)
- {
- if (item is ComplexItem complexItem)
- {
- VisitDescendants(complexItem);
- }
- }
-
- private void VisitDescendants(ComplexItem container)
- {
- foreach (var child in container.Children)
- {
- switch (child)
- {
- case Selector selector:
- VisitSelector(selector);
- break;
- case AtDirective atDirective:
- VisitAtDirective(atDirective);
- break;
- case Declaration declaration:
- VisitDeclaration(declaration);
- break;
- default:
- VisitDefault(child);
- break;
- }
- }
- }
- }
-
- private abstract class CssEdit
- {
- public int Position { get; set; }
- }
-
- private class InsertSelectorScopeEdit : CssEdit
- {
- }
-
- private class InsertKeyframesNameScopeEdit : CssEdit
- {
- }
-
- private class DeleteContentEdit : CssEdit
- {
- public int DeleteLength { get; set; }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerCommand.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerCommand.cs
deleted file mode 100644
index 64e2abe3b419..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerCommand.cs
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Reflection;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.CommandLineUtils;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal class ServerCommand : CommandBase
- {
- public ServerCommand(Application parent)
- : base(parent, "server")
- {
- Pipe = Option("-p|--pipe", "name of named pipe", CommandOptionType.SingleValue);
- KeepAlive = Option("-k|--keep-alive", "sets the default idle timeout for the server in seconds", CommandOptionType.SingleValue);
- }
-
- // For testing purposes only.
- internal ServerCommand(Application parent, string pipeName, int? keepAlive = null)
- : this(parent)
- {
- if (!string.IsNullOrEmpty(pipeName))
- {
- Pipe.Values.Add(pipeName);
- }
-
- if (keepAlive.HasValue)
- {
- KeepAlive.Values.Add(keepAlive.Value.ToString(CultureInfo.InvariantCulture));
- }
- }
-
- public CommandOption Pipe { get; }
-
- public CommandOption KeepAlive { get; }
-
- protected override bool ValidateArguments()
- {
- if (string.IsNullOrEmpty(Pipe.Value()))
- {
- Pipe.Values.Add(PipeName.ComputeDefault());
- }
-
- return true;
- }
-
- protected override Task ExecuteCoreAsync()
- {
- // Make sure there's only one server with the same identity at a time.
- var serverMutexName = MutexName.GetServerMutexName(Pipe.Value());
- Mutex serverMutex = null;
- var holdsMutex = false;
-
- try
- {
- serverMutex = new Mutex(initiallyOwned: true, name: serverMutexName, createdNew: out holdsMutex);
- }
- catch (Exception ex)
- {
- // The Mutex constructor can throw in certain cases. One specific example is docker containers
- // where the /tmp directory is restricted. In those cases there is no reliable way to execute
- // the server and we need to fall back to the command line.
- // Example: https://github.com/dotnet/roslyn/issues/24124
-
- Error.Write($"Server mutex creation failed. {ex.Message}");
-
- return Task.FromResult(-1);
- }
-
- if (!holdsMutex)
- {
- // Another server is running, just exit.
- Error.Write("Another server already running...");
- return Task.FromResult(1);
- }
-
- FileStream pidFileStream = null;
- try
- {
- try
- {
- // Write the process and pipe information to a file in a well-known location.
- pidFileStream = WritePidFile();
- }
- catch (Exception ex)
- {
- // Something happened when trying to write to the pid file. Log and move on.
- ServerLogger.LogException(ex, "Failed to create PID file.");
- }
-
- TimeSpan? keepAlive = null;
- if (KeepAlive.HasValue() && int.TryParse(KeepAlive.Value(), out var result))
- {
- // Keep alive times are specified in seconds
- keepAlive = TimeSpan.FromSeconds(result);
- }
-
- var host = ConnectionHost.Create(Pipe.Value());
-
- var compilerHost = CompilerHost.Create();
- ExecuteServerCore(host, compilerHost, Cancelled, eventBus: null, keepAlive: keepAlive);
- }
- finally
- {
- serverMutex.ReleaseMutex();
- serverMutex.Dispose();
- pidFileStream?.Close();
- }
-
- return Task.FromResult(0);
- }
-
- protected virtual void ExecuteServerCore(ConnectionHost host, CompilerHost compilerHost, CancellationToken cancellationToken, EventBus eventBus, TimeSpan? keepAlive)
- {
- var dispatcher = RequestDispatcher.Create(host, compilerHost, cancellationToken, eventBus, keepAlive);
- dispatcher.Run();
- }
-
- protected virtual FileStream WritePidFile()
- {
- var path = GetPidFilePath(env => Environment.GetEnvironmentVariable(env));
- return WritePidFile(path);
- }
-
- // Internal for testing.
- internal virtual FileStream WritePidFile(string directoryPath)
- {
- if (string.IsNullOrEmpty(directoryPath))
- {
- // Invalid path. Bail.
- return null;
- }
-
- // To make all the running rzc servers more discoverable, We want to write the process Id and pipe name to a file.
- // The file contents will be in the following format,
- //
- //
- // rzc
- // path/to/rzc.dll
- //
-
- const int DefaultBufferSize = 4096;
- var processId = Process.GetCurrentProcess().Id;
- var fileName = $"rzc-{processId}";
-
- // Make sure the directory exists.
- Directory.CreateDirectory(directoryPath);
-
- var path = Path.Combine(directoryPath, fileName);
- var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, DefaultBufferSize, FileOptions.DeleteOnClose);
-
- using (var writer = new StreamWriter(fileStream, Encoding.UTF8, DefaultBufferSize, leaveOpen: true))
- {
- var rzcPath = Assembly.GetExecutingAssembly().Location;
- var content = $"{processId}{Environment.NewLine}rzc{Environment.NewLine}{rzcPath}{Environment.NewLine}{Pipe.Value()}";
- writer.Write(content);
- }
-
- return fileStream;
- }
-
- // Internal for testing.
- internal virtual string GetPidFilePath(Func getEnvironmentVariable)
- {
- var path = getEnvironmentVariable("DOTNET_BUILD_PIDFILE_DIRECTORY");
- if (string.IsNullOrEmpty(path))
- {
- var homeEnvVariable = PlatformInformation.IsWindows ? "USERPROFILE" : "HOME";
- var homePath = getEnvironmentVariable(homeEnvVariable);
- if (string.IsNullOrEmpty(homePath))
- {
- // Couldn't locate the user profile directory. Bail.
- return null;
- }
-
- path = Path.Combine(homePath, ".dotnet", "pids", "build");
- }
-
- return path;
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/CompletedServerResponse.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/CompletedServerResponse.cs
deleted file mode 100644
index 98a64dba8ffe..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/CompletedServerResponse.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.IO;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- ///
- /// Represents a Response from the server. A response is as follows.
- ///
- /// Field Name Type Size (bytes)
- /// --------------------------------------------------
- /// Length UInteger 4
- /// ReturnCode Integer 4
- /// Output String Variable
- /// ErrorOutput String Variable
- ///
- /// Strings are encoded via a character count prefix as a
- /// 32-bit integer, followed by an array of characters.
- ///
- ///
- internal sealed class CompletedServerResponse : ServerResponse
- {
- public readonly int ReturnCode;
- public readonly bool Utf8Output;
- public readonly string Output;
- public readonly string ErrorOutput;
-
- public CompletedServerResponse(int returnCode, bool utf8output, string output, string error)
- {
- ReturnCode = returnCode;
- Utf8Output = utf8output;
- Output = output;
- ErrorOutput = error;
- }
-
- public override ResponseType Type => ResponseType.Completed;
-
- public static CompletedServerResponse Create(BinaryReader reader)
- {
- var returnCode = reader.ReadInt32();
- var utf8Output = reader.ReadBoolean();
- var output = ServerProtocol.ReadLengthPrefixedString(reader);
- var errorOutput = ServerProtocol.ReadLengthPrefixedString(reader);
-
- return new CompletedServerResponse(returnCode, utf8Output, output, errorOutput);
- }
-
- protected override void AddResponseBody(BinaryWriter writer)
- {
- writer.Write(ReturnCode);
- writer.Write(Utf8Output);
- ServerProtocol.WriteLengthPrefixedString(writer, Output);
- ServerProtocol.WriteLengthPrefixedString(writer, ErrorOutput);
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/MismatchedVersionServerResponse.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/MismatchedVersionServerResponse.cs
deleted file mode 100644
index 57293797e9e8..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/MismatchedVersionServerResponse.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.IO;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal sealed class MismatchedVersionServerResponse : ServerResponse
- {
- public override ResponseType Type => ResponseType.MismatchedVersion;
-
- ///
- /// MismatchedVersion has no body.
- ///
- protected override void AddResponseBody(BinaryWriter writer) { }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/NativeMethods.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/NativeMethods.cs
deleted file mode 100644
index 73a7363ecbd6..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/NativeMethods.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- internal struct STARTUPINFO
- {
- internal Int32 cb;
- internal string lpReserved;
- internal string lpDesktop;
- internal string lpTitle;
- internal Int32 dwX;
- internal Int32 dwY;
- internal Int32 dwXSize;
- internal Int32 dwYSize;
- internal Int32 dwXCountChars;
- internal Int32 dwYCountChars;
- internal Int32 dwFillAttribute;
- internal Int32 dwFlags;
- internal Int16 wShowWindow;
- internal Int16 cbReserved2;
- internal IntPtr lpReserved2;
- internal IntPtr hStdInput;
- internal IntPtr hStdOutput;
- internal IntPtr hStdError;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct PROCESS_INFORMATION
- {
- public IntPtr hProcess;
- public IntPtr hThread;
- public int dwProcessId;
- public int dwThreadId;
- }
-
- ///
- /// Interop methods.
- ///
- internal static class NativeMethods
- {
- #region Constants
-
- internal static readonly IntPtr NullPtr = IntPtr.Zero;
- internal static readonly IntPtr InvalidIntPtr = new IntPtr((int)-1);
-
- internal const uint NORMAL_PRIORITY_CLASS = 0x0020;
- internal const uint CREATE_NO_WINDOW = 0x08000000;
- internal const Int32 STARTF_USESTDHANDLES = 0x00000100;
- internal const int ERROR_SUCCESS = 0;
-
- #endregion
-
- //------------------------------------------------------------------------------
- // CloseHandle
- //------------------------------------------------------------------------------
- [DllImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool CloseHandle(IntPtr hObject);
-
- //------------------------------------------------------------------------------
- // CreateProcess
- //------------------------------------------------------------------------------
- [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool CreateProcess
- (
- string lpApplicationName,
- [In, Out]StringBuilder lpCommandLine,
- IntPtr lpProcessAttributes,
- IntPtr lpThreadAttributes,
- [In, MarshalAs(UnmanagedType.Bool)]
- bool bInheritHandles,
- uint dwCreationFlags,
- IntPtr lpEnvironment,
- string lpCurrentDirectory,
- [In] ref STARTUPINFO lpStartupInfo,
- out PROCESS_INFORMATION lpProcessInformation
- );
-
- [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
- internal static extern IntPtr GetCommandLine();
- }
-}
\ No newline at end of file
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/RejectedServerResponse.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/RejectedServerResponse.cs
deleted file mode 100644
index 2b6e3e894b05..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/RejectedServerResponse.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.IO;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal sealed class RejectedServerResponse : ServerResponse
- {
- public override ResponseType Type => ResponseType.Rejected;
-
- ///
- /// RejectedResponse has no body.
- ///
- protected override void AddResponseBody(BinaryWriter writer) { }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/RequestArgument.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/RequestArgument.cs
deleted file mode 100644
index 96e9ae0312ff..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/RequestArgument.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.IO;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- ///
- /// A command line argument to the compilation.
- /// An argument is formatted as follows:
- ///
- /// Field Name Type Size (bytes)
- /// --------------------------------------------------
- /// ID UInteger 4
- /// Index UInteger 4
- /// Value String Variable
- ///
- /// Strings are encoded via a length prefix as a signed
- /// 32-bit integer, followed by an array of characters.
- ///
- internal readonly struct RequestArgument
- {
- public readonly ArgumentId Id;
- public readonly int ArgumentIndex;
- public readonly string Value;
-
- public RequestArgument(ArgumentId argumentId, int argumentIndex, string value)
- {
- Id = argumentId;
- ArgumentIndex = argumentIndex;
- Value = value;
- }
-
- public static RequestArgument ReadFromBinaryReader(BinaryReader reader)
- {
- var argId = (ArgumentId)reader.ReadInt32();
- var argIndex = reader.ReadInt32();
- var value = ServerProtocol.ReadLengthPrefixedString(reader);
- return new RequestArgument(argId, argIndex, value);
- }
-
- public void WriteToBinaryWriter(BinaryWriter writer)
- {
- writer.Write((int)Id);
- writer.Write(ArgumentIndex);
- ServerProtocol.WriteLengthPrefixedString(writer, Value);
- }
-
- public enum ArgumentId
- {
- // The current directory of the client
- CurrentDirectory = 0x51147221,
-
- // A comment line argument. The argument index indicates which one (0 .. N)
- CommandLineArgument,
-
- // Request a longer keep alive time for the server
- KeepAlive,
-
- // Request a server shutdown from the client
- Shutdown,
-
- // The directory to use for temporary operations.
- TempDirectory,
- }
-
- public override string ToString()
- {
- return $"{Id} {Value}";
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerConnection.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerConnection.cs
deleted file mode 100644
index c46dae4394ae..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerConnection.cs
+++ /dev/null
@@ -1,390 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.CommandLineUtils;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal static class ServerConnection
- {
- private const string ServerName = "rzc.dll";
-
- // Spend up to 1s connecting to existing process (existing processes should be always responsive).
- private const int TimeOutMsExistingProcess = 1000;
-
- // Spend up to 20s connecting to a new process, to allow time for it to start.
- private const int TimeOutMsNewProcess = 20000;
-
- // Custom delegate that contains an out param to use with TryCreateServerCore method.
- private delegate TResult TryCreateServerCoreDelegate(T1 arg1, T2 arg2, out T3 arg3, T4 arg4);
-
- public static bool WasServerMutexOpen(string mutexName)
- {
- Mutex mutex = null;
- var open = false;
- try
- {
- open = Mutex.TryOpenExisting(mutexName, out mutex);
- }
- catch
- {
- // In the case an exception occurred trying to open the Mutex then
- // the assumption is that it's not open.
- }
-
- mutex?.Dispose();
-
- return open;
- }
-
- ///
- /// Gets the value of the temporary path for the current environment assuming the working directory
- /// is . This function must emulate as
- /// closely as possible.
- ///
- public static string GetTempPath(string workingDir)
- {
- if (PlatformInformation.IsUnix)
- {
- // Unix temp path is fine: it does not use the working directory
- // (it uses ${TMPDIR} if set, otherwise, it returns /tmp)
- return Path.GetTempPath();
- }
-
- var tmp = Environment.GetEnvironmentVariable("TMP");
- if (Path.IsPathRooted(tmp))
- {
- return tmp;
- }
-
- var temp = Environment.GetEnvironmentVariable("TEMP");
- if (Path.IsPathRooted(temp))
- {
- return temp;
- }
-
- if (!string.IsNullOrEmpty(workingDir))
- {
- if (!string.IsNullOrEmpty(tmp))
- {
- return Path.Combine(workingDir, tmp);
- }
-
- if (!string.IsNullOrEmpty(temp))
- {
- return Path.Combine(workingDir, temp);
- }
- }
-
- var userProfile = Environment.GetEnvironmentVariable("USERPROFILE");
- if (Path.IsPathRooted(userProfile))
- {
- return userProfile;
- }
-
- return Environment.GetEnvironmentVariable("SYSTEMROOT");
- }
-
- public static Task RunOnServer(
- string pipeName,
- IList arguments,
- ServerPaths serverPaths,
- CancellationToken cancellationToken,
- string keepAlive = null,
- bool debug = false)
- {
- if (string.IsNullOrEmpty(pipeName))
- {
- pipeName = PipeName.ComputeDefault(serverPaths.ClientDirectory);
- }
-
- return RunOnServerCore(
- arguments,
- serverPaths,
- pipeName: pipeName,
- keepAlive: keepAlive,
- timeoutOverride: null,
- tryCreateServerFunc: TryCreateServerCore,
- cancellationToken: cancellationToken,
- debug: debug);
- }
-
- private static async Task RunOnServerCore(
- IList arguments,
- ServerPaths serverPaths,
- string pipeName,
- string keepAlive,
- int? timeoutOverride,
- TryCreateServerCoreDelegate tryCreateServerFunc,
- CancellationToken cancellationToken,
- bool debug)
- {
- if (pipeName == null)
- {
- return new RejectedServerResponse();
- }
-
- if (serverPaths.TempDirectory == null)
- {
- return new RejectedServerResponse();
- }
-
- var clientDir = serverPaths.ClientDirectory;
- var timeoutNewProcess = timeoutOverride ?? TimeOutMsNewProcess;
- var timeoutExistingProcess = timeoutOverride ?? TimeOutMsExistingProcess;
- var clientMutexName = MutexName.GetClientMutexName(pipeName);
- Task pipeTask = null;
-
- Mutex clientMutex = null;
- var holdsMutex = false;
-
- try
- {
- try
- {
- clientMutex = new Mutex(initiallyOwned: true, name: clientMutexName, createdNew: out holdsMutex);
- }
- catch (Exception ex)
- {
- // The Mutex constructor can throw in certain cases. One specific example is docker containers
- // where the /tmp directory is restricted. In those cases there is no reliable way to execute
- // the server and we need to fall back to the command line.
- // Example: https://github.com/dotnet/roslyn/issues/24124
-
- ServerLogger.LogException(ex, "Client mutex creation failed.");
-
- return new RejectedServerResponse();
- }
-
- if (!holdsMutex)
- {
- try
- {
- holdsMutex = clientMutex.WaitOne(timeoutNewProcess);
-
- if (!holdsMutex)
- {
- return new RejectedServerResponse();
- }
- }
- catch (AbandonedMutexException)
- {
- holdsMutex = true;
- }
- }
-
- // Check for an already running server
- var serverMutexName = MutexName.GetServerMutexName(pipeName);
- var wasServerRunning = WasServerMutexOpen(serverMutexName);
- var timeout = wasServerRunning ? timeoutExistingProcess : timeoutNewProcess;
-
- if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName, out var _, debug))
- {
- pipeTask = Client.ConnectAsync(pipeName, TimeSpan.FromMilliseconds(timeout), cancellationToken);
- }
- }
- finally
- {
- if (holdsMutex)
- {
- clientMutex?.ReleaseMutex();
- }
-
- clientMutex?.Dispose();
- }
-
- if (pipeTask != null)
- {
- var client = await pipeTask.ConfigureAwait(false);
- if (client != null)
- {
- var request = ServerRequest.Create(
- serverPaths.WorkingDirectory,
- serverPaths.TempDirectory,
- arguments,
- keepAlive);
-
- return await TryProcessRequest(client, request, cancellationToken).ConfigureAwait(false);
- }
- }
-
- return new RejectedServerResponse();
- }
-
- ///
- /// Try to process the request using the server. Returns a null-containing Task if a response
- /// from the server cannot be retrieved.
- ///
- private static async Task TryProcessRequest(
- Client client,
- ServerRequest request,
- CancellationToken cancellationToken)
- {
- ServerResponse response;
- using (client)
- {
- // Write the request
- try
- {
- ServerLogger.Log("Begin writing request");
- await request.WriteAsync(client.Stream, cancellationToken).ConfigureAwait(false);
- ServerLogger.Log("End writing request");
- }
- catch (Exception e)
- {
- ServerLogger.LogException(e, "Error writing build request.");
- return new RejectedServerResponse();
- }
-
- // Wait for the compilation and a monitor to detect if the server disconnects
- var serverCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
-
- ServerLogger.Log("Begin reading response");
-
- var responseTask = ServerResponse.ReadAsync(client.Stream, serverCts.Token);
- var monitorTask = client.WaitForDisconnectAsync(serverCts.Token);
- await Task.WhenAny(new[] { responseTask, monitorTask }).ConfigureAwait(false);
-
- ServerLogger.Log("End reading response");
-
- if (responseTask.IsCompleted)
- {
- // await the task to log any exceptions
- try
- {
- response = await responseTask.ConfigureAwait(false);
- }
- catch (Exception e)
- {
- ServerLogger.LogException(e, "Error reading response");
- response = new RejectedServerResponse();
- }
- }
- else
- {
- ServerLogger.Log("Server disconnect");
- response = new RejectedServerResponse();
- }
-
- // Cancel whatever task is still around
- serverCts.Cancel();
- Debug.Assert(response != null);
- return response;
- }
- }
-
- // Internal for testing.
- internal static bool TryCreateServerCore(string clientDir, string pipeName, out int? processId, bool debug = false)
- {
- processId = null;
-
- // The server should be in the same directory as the client
- var expectedCompilerPath = Path.Combine(clientDir, ServerName);
- var expectedPath = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH") ?? "dotnet";
- var argumentList = new string[]
- {
- expectedCompilerPath,
- debug ? "--debug" : "",
- "server",
- "-p",
- pipeName
- };
- var processArguments = ArgumentEscaper.EscapeAndConcatenate(argumentList);
-
- if (!File.Exists(expectedCompilerPath))
- {
- return false;
- }
-
- if (PlatformInformation.IsWindows)
- {
- // Currently, there isn't a way to use the Process class to create a process without
- // inheriting handles(stdin/stdout/stderr) from its parent. This might cause the parent process
- // to block on those handles. So we use P/Invoke. This code was taken from MSBuild task starting code.
- // The work to customize this behavior is being tracked by https://github.com/dotnet/corefx/issues/306.
-
- var startInfo = new STARTUPINFO();
- startInfo.cb = Marshal.SizeOf(startInfo);
- startInfo.hStdError = NativeMethods.InvalidIntPtr;
- startInfo.hStdInput = NativeMethods.InvalidIntPtr;
- startInfo.hStdOutput = NativeMethods.InvalidIntPtr;
- startInfo.dwFlags = NativeMethods.STARTF_USESTDHANDLES;
- var dwCreationFlags = NativeMethods.NORMAL_PRIORITY_CLASS | NativeMethods.CREATE_NO_WINDOW;
-
- ServerLogger.Log("Attempting to create process '{0}'", expectedPath);
-
- var builder = new StringBuilder($@"""{expectedPath}"" {processArguments}");
-
- var success = NativeMethods.CreateProcess(
- lpApplicationName: null,
- lpCommandLine: builder,
- lpProcessAttributes: NativeMethods.NullPtr,
- lpThreadAttributes: NativeMethods.NullPtr,
- bInheritHandles: false,
- dwCreationFlags: dwCreationFlags,
- lpEnvironment: NativeMethods.NullPtr, // Inherit environment
- lpCurrentDirectory: clientDir,
- lpStartupInfo: ref startInfo,
- lpProcessInformation: out var processInfo);
-
- if (success)
- {
- ServerLogger.Log("Successfully created process with process id {0}", processInfo.dwProcessId);
- NativeMethods.CloseHandle(processInfo.hProcess);
- NativeMethods.CloseHandle(processInfo.hThread);
- processId = processInfo.dwProcessId;
- }
- else
- {
- ServerLogger.Log("Failed to create process. GetLastError={0}", Marshal.GetLastWin32Error());
- }
- return success;
- }
- else
- {
- try
- {
- var startInfo = new ProcessStartInfo()
- {
- FileName = expectedPath,
- Arguments = processArguments,
- UseShellExecute = false,
- WorkingDirectory = clientDir,
- RedirectStandardInput = true,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- };
-
- var process = Process.Start(startInfo);
- processId = process.Id;
-
- return true;
- }
- catch
- {
- return false;
- }
- }
- }
- }
-
- ///
- /// This class provides simple properties for determining whether the current platform is Windows or Unix-based.
- /// We intentionally do not use System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(...) because
- /// it incorrectly reports 'true' for 'Windows' in desktop builds running on Unix-based platforms via Mono.
- ///
- internal static class PlatformInformation
- {
- public static bool IsWindows => Path.DirectorySeparatorChar == '\\';
- public static bool IsUnix => Path.DirectorySeparatorChar == '/';
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerLogger.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerLogger.cs
deleted file mode 100644
index 49d38e07d970..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerLogger.cs
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Threading;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- ///
- /// Class for logging information about what happens in the server and client parts of the
- /// Razor command line compiler and build tasks. Useful for debugging what is going on.
- ///
- ///
- /// To use the logging, set the environment variable RAZORBUILDSERVER_LOG to the name
- /// of a file to log to. This file is logged to by both client and server components.
- ///
- internal class ServerLogger
- {
- // Environment variable, if set, to enable logging and set the file to log to.
- private const string EnvironmentVariable = "RAZORBUILDSERVER_LOG";
-
- private static readonly Stream s_loggingStream;
- private static string s_prefix = "---";
-
- ///
- /// Static class initializer that initializes logging.
- ///
- static ServerLogger()
- {
- s_loggingStream = null;
-
- try
- {
- // Check if the environment
- var loggingFileName = Environment.GetEnvironmentVariable(EnvironmentVariable);
-
- if (loggingFileName != null)
- {
- IsLoggingEnabled = true;
-
- // If the environment variable contains the path of a currently existing directory,
- // then use a process-specific name for the log file and put it in that directory.
- // Otherwise, assume that the environment variable specifies the name of the log file.
- if (Directory.Exists(loggingFileName))
- {
- loggingFileName = Path.Combine(loggingFileName, $"razorserver.{GetCurrentProcessId()}.log");
- }
-
- // Open allowing sharing. We allow multiple processes to log to the same file, so we use share mode to allow that.
- s_loggingStream = new FileStream(loggingFileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
- }
- }
- catch (Exception e)
- {
- LogException(e, "Failed to create logging stream");
- }
- }
-
- public static bool IsLoggingEnabled { get; }
-
- ///
- /// Set the logging prefix that describes our role.
- /// Typically a 3-letter abbreviation. If logging happens before this, it's logged with "---".
- ///
- public static void Initialize(string outputPrefix)
- {
- s_prefix = outputPrefix;
- }
-
- ///
- /// Log an exception. Also logs information about inner exceptions.
- ///
- public static void LogException(Exception e, string reason)
- {
- if (IsLoggingEnabled)
- {
- Log("Exception '{0}' occurred during '{1}'. Stack trace:\r\n{2}", e.Message, reason, e.StackTrace);
-
- var innerExceptionLevel = 0;
-
- e = e.InnerException;
- while (e != null)
- {
- Log("Inner exception[{0}] '{1}'. Stack trace: \r\n{1}", innerExceptionLevel, e.Message, e.StackTrace);
- e = e.InnerException;
- innerExceptionLevel += 1;
- }
- }
- }
-
- ///
- /// Log a line of text to the logging file, with string.Format arguments.
- ///
- public static void Log(string format, params object[] arguments)
- {
- if (IsLoggingEnabled)
- {
- Log(string.Format(CultureInfo.InvariantCulture, format, arguments));
- }
- }
-
- ///
- /// Log a line of text to the logging file.
- ///
- ///
- public static void Log(string message)
- {
- if (IsLoggingEnabled)
- {
- var prefix = GetLoggingPrefix();
-
- var output = prefix + message + "\r\n";
- var bytes = Encoding.UTF8.GetBytes(output);
-
- // Because multiple processes might be logging to the same file, we always seek to the end,
- // write, and flush.
- s_loggingStream.Seek(0, SeekOrigin.End);
- s_loggingStream.Write(bytes, 0, bytes.Length);
- s_loggingStream.Flush();
- }
- }
-
- private static int GetCurrentProcessId()
- {
- var process = Process.GetCurrentProcess();
- return process.Id;
- }
-
- private static int GetCurrentThreadId()
- {
- return Environment.CurrentManagedThreadId;
- }
-
- ///
- /// Get the string that prefixes all log entries. Shows the process, thread, and time.
- ///
- private static string GetLoggingPrefix()
- {
- return string.Format(CultureInfo.InvariantCulture, "{0} PID={1} TID={2} Ticks={3}: ", s_prefix, GetCurrentProcessId(), GetCurrentThreadId(), Environment.TickCount);
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerPaths.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerPaths.cs
deleted file mode 100644
index 37cd4a58c445..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerPaths.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.IO;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal struct ServerPaths
- {
- internal ServerPaths(string clientDir, string workingDir, string tempDir)
- {
- ClientDirectory = clientDir;
- WorkingDirectory = workingDir;
- TempDirectory = tempDir;
- }
-
- ///
- /// The path which contains the Razor compiler binaries and response files.
- ///
- internal string ClientDirectory { get; }
-
- ///
- /// The path in which the Razor compilation takes place.
- ///
- internal string WorkingDirectory { get; }
-
- ///
- /// The temporary directory a compilation should use instead of . The latter
- /// relies on global state individual compilations should ignore.
- ///
- internal string TempDirectory { get; }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerProtocol.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerProtocol.cs
deleted file mode 100644
index 940dda2845ff..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerProtocol.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal static class ServerProtocol
- {
- ///
- /// The version number for this protocol.
- ///
- public static readonly uint ProtocolVersion = 2;
-
- ///
- /// Read a string from the Reader where the string is encoded
- /// as a length prefix (signed 32-bit integer) followed by
- /// a sequence of characters.
- ///
- public static string ReadLengthPrefixedString(BinaryReader reader)
- {
- var length = reader.ReadInt32();
- return new string(reader.ReadChars(length));
- }
-
- ///
- /// Write a string to the Writer where the string is encoded
- /// as a length prefix (signed 32-bit integer) follows by
- /// a sequence of characters.
- ///
- public static void WriteLengthPrefixedString(BinaryWriter writer, string value)
- {
- writer.Write(value.Length);
- writer.Write(value.ToCharArray());
- }
-
- ///
- /// This task does not complete until we are completely done reading.
- ///
- internal static async Task ReadAllAsync(
- Stream stream,
- byte[] buffer,
- int count,
- CancellationToken cancellationToken)
- {
- var totalBytesRead = 0;
- do
- {
- ServerLogger.Log("Attempting to read {0} bytes from the stream", count - totalBytesRead);
- var bytesRead = await stream.ReadAsync(
- buffer,
- totalBytesRead,
- count - totalBytesRead,
- cancellationToken)
- .ConfigureAwait(false);
-
- if (bytesRead == 0)
- {
- ServerLogger.Log("Unexpected -- read 0 bytes from the stream.");
- throw new EndOfStreamException("Reached end of stream before end of read.");
- }
- ServerLogger.Log("Read {0} bytes", bytesRead);
- totalBytesRead += bytesRead;
- } while (totalBytesRead < count);
- ServerLogger.Log("Finished read");
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerRequest.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerRequest.cs
deleted file mode 100644
index 34b6a39eb934..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerRequest.cs
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-// After the server pipe is connected, it forks off a thread to handle the connection, and creates
-// a new instance of the pipe to listen for new clients. When it gets a request, it validates
-// the security and elevation level of the client. If that fails, it disconnects the client. Otherwise,
-// it handles the request, sends a response (described by Response class) back to the client, then
-// disconnects the pipe and ends the thread.
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- ///
- /// Represents a request from the client. A request is as follows.
- ///
- /// Field Name Type Size (bytes)
- /// ----------------------------------------------------
- /// Length Integer 4
- /// Argument Count UInteger 4
- /// Arguments Argument[] Variable
- ///
- /// See for the format of an
- /// Argument.
- ///
- ///
- internal class ServerRequest
- {
- public ServerRequest(uint protocolVersion, IEnumerable arguments)
- {
- ProtocolVersion = protocolVersion;
- Arguments = new ReadOnlyCollection(arguments.ToList());
-
- if (Arguments.Count > ushort.MaxValue)
- {
- throw new ArgumentOutOfRangeException(
- nameof(arguments),
- $"Too many arguments: maximum of {ushort.MaxValue} arguments allowed.");
- }
- }
-
- public uint ProtocolVersion { get; }
-
- public ReadOnlyCollection Arguments { get; }
-
- public TimeSpan? KeepAlive
- {
- get
- {
- TimeSpan? keepAlive = null;
- foreach (var argument in Arguments)
- {
- if (argument.Id == RequestArgument.ArgumentId.KeepAlive)
- {
- // If the value is not a valid integer for any reason, ignore it and continue with the current timeout.
- // The client is responsible for validating the argument.
- if (int.TryParse(argument.Value, out var result))
- {
- // Keep alive times are specified in seconds
- keepAlive = TimeSpan.FromSeconds(result);
- }
- }
- }
-
- return keepAlive;
- }
- }
-
- public bool IsShutdownRequest()
- {
- return Arguments.Count >= 1 && Arguments[0].Id == RequestArgument.ArgumentId.Shutdown;
- }
-
- public static ServerRequest Create(
- string workingDirectory,
- string tempDirectory,
- IList args,
- string keepAlive = null)
- {
- ServerLogger.Log("Creating ServerRequest");
- ServerLogger.Log($"Working directory: {workingDirectory}");
- ServerLogger.Log($"Temp directory: {tempDirectory}");
-
- var requestLength = args.Count + 1;
- var requestArgs = new List(requestLength)
- {
- new RequestArgument(RequestArgument.ArgumentId.CurrentDirectory, 0, workingDirectory),
- new RequestArgument(RequestArgument.ArgumentId.TempDirectory, 0, tempDirectory)
- };
-
- if (keepAlive != null)
- {
- requestArgs.Add(new RequestArgument(RequestArgument.ArgumentId.KeepAlive, 0, keepAlive));
- }
-
- for (var i = 0; i < args.Count; ++i)
- {
- var arg = args[i];
- ServerLogger.Log($"argument[{i}] = {arg}");
- requestArgs.Add(new RequestArgument(RequestArgument.ArgumentId.CommandLineArgument, i, arg));
- }
-
- return new ServerRequest(ServerProtocol.ProtocolVersion, requestArgs);
- }
-
- public static ServerRequest CreateShutdown()
- {
- var requestArgs = new[]
- {
- new RequestArgument(RequestArgument.ArgumentId.Shutdown, argumentIndex: 0, value: ""),
- new RequestArgument(RequestArgument.ArgumentId.CommandLineArgument, argumentIndex: 1, value: "shutdown"),
- };
- return new ServerRequest(ServerProtocol.ProtocolVersion, requestArgs);
- }
-
- ///
- /// Read a Request from the given stream.
- ///
- /// The total request size must be less than 1MB.
- ///
- /// null if the Request was too large, the Request otherwise.
- public static async Task ReadAsync(Stream inStream, CancellationToken cancellationToken)
- {
- // Read the length of the request
- var lengthBuffer = new byte[4];
- ServerLogger.Log("Reading length of request");
- await ServerProtocol.ReadAllAsync(inStream, lengthBuffer, 4, cancellationToken).ConfigureAwait(false);
- var length = BitConverter.ToInt32(lengthBuffer, 0);
-
- // Back out if the request is > 1MB
- if (length > 0x100000)
- {
- ServerLogger.Log("Request is over 1MB in length, cancelling read.");
- return null;
- }
-
- cancellationToken.ThrowIfCancellationRequested();
-
- // Read the full request
- var requestBuffer = new byte[length];
- await ServerProtocol.ReadAllAsync(inStream, requestBuffer, length, cancellationToken).ConfigureAwait(false);
-
- cancellationToken.ThrowIfCancellationRequested();
-
- ServerLogger.Log("Parsing request");
- // Parse the request into the Request data structure.
- using (var reader = new BinaryReader(new MemoryStream(requestBuffer), Encoding.Unicode))
- {
- var protocolVersion = reader.ReadUInt32();
- var argumentCount = reader.ReadUInt32();
-
- var argumentsBuilder = new List((int)argumentCount);
-
- for (var i = 0; i < argumentCount; i++)
- {
- cancellationToken.ThrowIfCancellationRequested();
- argumentsBuilder.Add(RequestArgument.ReadFromBinaryReader(reader));
- }
-
- return new ServerRequest(protocolVersion, argumentsBuilder);
- }
- }
-
- ///
- /// Write a Request to the stream.
- ///
- public async Task WriteAsync(Stream outStream, CancellationToken cancellationToken = default(CancellationToken))
- {
- using (var memoryStream = new MemoryStream())
- using (var writer = new BinaryWriter(memoryStream, Encoding.Unicode))
- {
- // Format the request.
- ServerLogger.Log("Formatting request");
- writer.Write(ProtocolVersion);
- writer.Write(Arguments.Count);
- foreach (var arg in Arguments)
- {
- cancellationToken.ThrowIfCancellationRequested();
- arg.WriteToBinaryWriter(writer);
- }
- writer.Flush();
-
- cancellationToken.ThrowIfCancellationRequested();
-
- // Write the length of the request
- var length = checked((int)memoryStream.Length);
-
- // Back out if the request is > 1 MB
- if (memoryStream.Length > 0x100000)
- {
- ServerLogger.Log("Request is over 1MB in length, cancelling write");
- throw new ArgumentOutOfRangeException();
- }
-
- // Send the request to the server
- ServerLogger.Log("Writing length of request.");
- await outStream
- .WriteAsync(BitConverter.GetBytes(length), 0, 4, cancellationToken)
- .ConfigureAwait(false);
-
- ServerLogger.Log("Writing request of size {0}", length);
- // Write the request
- memoryStream.Position = 0;
- await memoryStream
- .CopyToAsync(outStream, bufferSize: length, cancellationToken: cancellationToken)
- .ConfigureAwait(false);
- }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerResponse.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerResponse.cs
deleted file mode 100644
index 66eb1e63f338..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ServerResponse.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.IO;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-
-// After the server pipe is connected, it forks off a thread to handle the connection, and creates
-// a new instance of the pipe to listen for new clients. When it gets a request, it validates
-// the security and elevation level of the client. If that fails, it disconnects the client. Otherwise,
-// it handles the request, sends a response (described by Response class) back to the client, then
-// disconnects the pipe and ends the thread.
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- ///
- /// Base class for all possible responses to a request.
- /// The ResponseType enum should list all possible response types
- /// and ReadResponse creates the appropriate response subclass based
- /// on the response type sent by the client.
- /// The format of a response is:
- ///
- /// Field Name Field Type Size (bytes)
- /// -------------------------------------------------
- /// responseLength int (positive) 4
- /// responseType enum ResponseType 4
- /// responseBody Response subclass variable
- ///
- internal abstract class ServerResponse
- {
- public enum ResponseType
- {
- // The client and server are using incompatible protocol versions.
- MismatchedVersion,
-
- // The build request completed on the server and the results are contained
- // in the message.
- Completed,
-
- // The shutdown request completed and the server process information is
- // contained in the message.
- Shutdown,
-
- // The request was rejected by the server.
- Rejected,
- }
-
- public abstract ResponseType Type { get; }
-
- public async Task WriteAsync(Stream outStream, CancellationToken cancellationToken)
- {
- using (var memoryStream = new MemoryStream())
- using (var writer = new BinaryWriter(memoryStream, Encoding.Unicode))
- {
- // Format the response
- ServerLogger.Log("Formatting Response");
- writer.Write((int)Type);
-
- AddResponseBody(writer);
- writer.Flush();
-
- cancellationToken.ThrowIfCancellationRequested();
-
- // Send the response to the client
-
- // Write the length of the response
- var length = checked((int)memoryStream.Length);
-
- ServerLogger.Log("Writing response length");
- // There is no way to know the number of bytes written to
- // the pipe stream. We just have to assume all of them are written.
- await outStream
- .WriteAsync(BitConverter.GetBytes(length), 0, 4, cancellationToken)
- .ConfigureAwait(false);
-
- // Write the response
- ServerLogger.Log("Writing response of size {0}", length);
- memoryStream.Position = 0;
- await memoryStream
- .CopyToAsync(outStream, bufferSize: length, cancellationToken: cancellationToken)
- .ConfigureAwait(false);
- }
- }
-
- protected abstract void AddResponseBody(BinaryWriter writer);
-
- ///
- /// May throw exceptions if there are pipe problems.
- ///
- ///
- ///
- ///
- public static async Task ReadAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
- {
- ServerLogger.Log("Reading response length");
- // Read the response length
- var lengthBuffer = new byte[4];
- await ServerProtocol.ReadAllAsync(stream, lengthBuffer, 4, cancellationToken).ConfigureAwait(false);
- var length = BitConverter.ToUInt32(lengthBuffer, 0);
-
- // Read the response
- ServerLogger.Log("Reading response of length {0}", length);
- var responseBuffer = new byte[length];
- await ServerProtocol.ReadAllAsync(
- stream,
- responseBuffer,
- responseBuffer.Length,
- cancellationToken)
- .ConfigureAwait(false);
-
- using (var reader = new BinaryReader(new MemoryStream(responseBuffer), Encoding.Unicode))
- {
- var responseType = (ResponseType)reader.ReadInt32();
-
- switch (responseType)
- {
- case ResponseType.Completed:
- return CompletedServerResponse.Create(reader);
- case ResponseType.MismatchedVersion:
- return new MismatchedVersionServerResponse();
- case ResponseType.Shutdown:
- return ShutdownServerResponse.Create(reader);
- case ResponseType.Rejected:
- return new RejectedServerResponse();
- default:
- throw new InvalidOperationException("Received invalid response type from server.");
- }
- }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ShutdownServerResponse.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ShutdownServerResponse.cs
deleted file mode 100644
index dbf94e1628ae..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ServerProtocol/ShutdownServerResponse.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.IO;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal sealed class ShutdownServerResponse : ServerResponse
- {
- public readonly int ServerProcessId;
-
- public ShutdownServerResponse(int serverProcessId)
- {
- ServerProcessId = serverProcessId;
- }
-
- public override ResponseType Type => ResponseType.Shutdown;
-
- protected override void AddResponseBody(BinaryWriter writer)
- {
- writer.Write(ServerProcessId);
- }
-
- public static ShutdownServerResponse Create(BinaryReader reader)
- {
- var serverProcessId = reader.ReadInt32();
- return new ShutdownServerResponse(serverProcessId);
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ShadowCopyManager.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ShadowCopyManager.cs
deleted file mode 100644
index 7cfebc5b5060..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ShadowCopyManager.cs
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright(c) .NET Foundation.All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- // Note that this class has no thread-safety guarantees. The caller should use a lock
- // if concurrency is required.
- internal class ShadowCopyManager : IDisposable
- {
- // Note that this class uses the *existance* of the Mutex to lock a directory.
- //
- // Nothing in this code actually ever acquires the Mutex, we just try to see if it exists
- // already.
- private readonly Mutex _mutex;
-
- private int _counter;
-
- public ShadowCopyManager(string baseDirectory = null)
- {
- BaseDirectory = baseDirectory ?? Path.Combine(Path.GetTempPath(), "Razor", "ShadowCopy");
-
- var guid = Guid.NewGuid().ToString("N").ToLowerInvariant();
- UniqueDirectory = Path.Combine(BaseDirectory, guid);
-
- _mutex = new Mutex(initiallyOwned: false, name: guid);
-
- Directory.CreateDirectory(UniqueDirectory);
- }
-
- public string BaseDirectory { get; }
-
- public string UniqueDirectory { get; }
-
- public string AddAssembly(string filePath)
- {
- var assemblyDirectory = CreateUniqueDirectory();
-
- var destination = Path.Combine(assemblyDirectory, Path.GetFileName(filePath));
- CopyFile(filePath, destination);
-
- var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath);
- var resourcesNameWithoutExtension = fileNameWithoutExtension + ".resources";
- var resourcesNameWithExtension = resourcesNameWithoutExtension + ".dll";
-
- foreach (var directory in Directory.EnumerateDirectories(Path.GetDirectoryName(filePath)))
- {
- var directoryName = Path.GetFileName(directory);
-
- var resourcesPath = Path.Combine(directory, resourcesNameWithExtension);
- if (File.Exists(resourcesPath))
- {
- var resourcesShadowCopyPath = Path.Combine(assemblyDirectory, directoryName, resourcesNameWithExtension);
- CopyFile(resourcesPath, resourcesShadowCopyPath);
- }
-
- resourcesPath = Path.Combine(directory, resourcesNameWithoutExtension, resourcesNameWithExtension);
- if (File.Exists(resourcesPath))
- {
- var resourcesShadowCopyPath = Path.Combine(assemblyDirectory, directoryName, resourcesNameWithoutExtension, resourcesNameWithExtension);
- CopyFile(resourcesPath, resourcesShadowCopyPath);
- }
- }
-
- return destination;
- }
-
- public void Dispose()
- {
- _mutex.ReleaseMutex();
- }
-
- public Task PurgeUnusedDirectoriesAsync()
- {
- return Task.Run((Action)PurgeUnusedDirectories);
- }
-
- private string CreateUniqueDirectory()
- {
- var id = _counter++;
-
- var directory = Path.Combine(UniqueDirectory, id.ToString(CultureInfo.InvariantCulture));
- Directory.CreateDirectory(directory);
- return directory;
- }
-
- private void CopyFile(string originalPath, string shadowCopyPath)
- {
- var directory = Path.GetDirectoryName(shadowCopyPath);
- Directory.CreateDirectory(directory);
-
- File.Copy(originalPath, shadowCopyPath);
-
- MakeWritable(new FileInfo(shadowCopyPath));
- }
-
- private void MakeWritable(string directoryPath)
- {
- var directory = new DirectoryInfo(directoryPath);
-
- foreach (var file in directory.EnumerateFiles(searchPattern: "*", searchOption: SearchOption.AllDirectories))
- {
- MakeWritable(file);
- }
- }
-
- private void MakeWritable(FileInfo file)
- {
- try
- {
- if (file.IsReadOnly)
- {
- file.IsReadOnly = false;
- }
- }
- catch
- {
- // There are many reasons this could fail. Ignore it and keep going.
- }
- }
-
- private void PurgeUnusedDirectories()
- {
- IEnumerable directories;
- try
- {
- directories = Directory.EnumerateDirectories(BaseDirectory);
- }
- catch (DirectoryNotFoundException)
- {
- return;
- }
-
- foreach (var directory in directories)
- {
- Mutex mutex = null;
- try
- {
- // We only want to try deleting the directory if no-one else is currently using it.
- //
- // Note that the mutex name is the name of the directory. This is OK because we're using
- // GUIDs as directory/mutex names.
- if (!Mutex.TryOpenExisting(Path.GetFileName(directory).ToLowerInvariant(), out mutex))
- {
- MakeWritable(directory);
- Directory.Delete(directory, recursive: true);
- }
- }
- catch
- {
- // If something goes wrong we will leave it to the next run to clean up.
- // Just swallow the exception and move on.
- }
- finally
- {
- if (mutex != null)
- {
- mutex.Dispose();
- }
- }
- }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ShutdownCommand.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ShutdownCommand.cs
deleted file mode 100644
index 443f454f770b..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/ShutdownCommand.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.CommandLineUtils;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal class ShutdownCommand : CommandBase
- {
- public ShutdownCommand(Application parent)
- : base(parent, "shutdown")
- {
- Pipe = Option("-p|--pipe", "name of named pipe", CommandOptionType.SingleValue);
- Wait = Option("-w|--wait", "wait for shutdown", CommandOptionType.NoValue);
- }
-
- public CommandOption Pipe { get; }
-
- public CommandOption Wait { get; }
-
- protected override bool ValidateArguments()
- {
- if (string.IsNullOrEmpty(Pipe.Value()))
- {
- Pipe.Values.Add(PipeName.ComputeDefault());
- }
-
- return true;
- }
-
- protected async override Task ExecuteCoreAsync()
- {
- if (!IsServerRunning())
- {
- // server isn't running right now
- Out.Write("Server is not running.");
- return 0;
- }
-
- try
- {
- using (var client = await Client.ConnectAsync(Pipe.Value(), timeout: TimeSpan.FromSeconds(5), cancellationToken: Cancelled))
- {
- if (client == null)
- {
- throw new InvalidOperationException("Couldn't connect to the server.");
- }
-
- var request = ServerRequest.CreateShutdown();
- await request.WriteAsync(client.Stream, Cancelled).ConfigureAwait(false);
-
- var response = ((ShutdownServerResponse)await ServerResponse.ReadAsync(client.Stream, Cancelled));
-
- if (Wait.HasValue())
- {
- try
- {
- var process = Process.GetProcessById(response.ServerProcessId);
- process.WaitForExit();
- }
- catch (Exception ex)
- {
- // There is an inherent race here with the server process. If it has already shutdown
- // by the time we try to access it then the operation has succeeded.
- Error.Write(ex);
- }
-
- Out.Write("Server pid:{0} shut down completed.", response.ServerProcessId);
- }
- }
- }
- catch (Exception ex) when (IsServerRunning())
- {
- // Ignore an exception that occurred while the server was shutting down.
- Error.Write(ex);
- }
-
- return 0;
- }
-
- private bool IsServerRunning()
- {
- if (Mutex.TryOpenExisting(MutexName.GetServerMutexName(Pipe.Value()), out var mutex))
- {
- mutex.Dispose();
- return true;
- }
-
- return false;
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/runtimeconfig.template.json b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/runtimeconfig.template.json
deleted file mode 100644
index 2c73f3989069..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/runtimeconfig.template.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "rollForwardOnNoCandidateFx": 2
-}
\ No newline at end of file
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/rzc.csproj b/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/rzc.csproj
deleted file mode 100644
index 279c92930bdc..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/src/rzc.csproj
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
- Razor is a markup syntax for adding server-side logic to web pages. This assembly contains infrastructure supporting Razor MSBuild integration.
- $(DefaultNetCoreTargetFramework)
- Exe
- rzc
-
-
- false
- false
-
-
- false
-
-
-
- false
-
-
-
-
- Shared\TagHelperDescriptorJsonConverter.cs
-
-
- Shared\RazorDiagnosticJsonConverter.cs
-
-
- Shared\JsonReaderExtensions.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $(ProjectRuntimeConfigFileName)
- PreserveNewest
-
-
-
-
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/CompositeRazorProjectFileSystemTest.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/CompositeRazorProjectFileSystemTest.cs
deleted file mode 100644
index 01a3e1b6a852..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/CompositeRazorProjectFileSystemTest.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Linq;
-using Microsoft.AspNetCore.Razor.Language;
-using Moq;
-using Xunit;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- public class CompositeRazorProjectFileSystemTest
- {
- [Fact]
- public void EnumerateItems_ReturnsResultsFromAllFileSystems()
- {
- // Arrange
- var basePath = "base-path";
- var file1 = new TestRazorProjectItem("file1");
- var file2 = new TestRazorProjectItem("file2");
- var file3 = new TestRazorProjectItem("file3");
- var fileSystem1 = Mock.Of(
- f => f.EnumerateItems(basePath) == new[] { file1 });
- var fileSystem2 = Mock.Of(
- f => f.EnumerateItems(basePath) == Enumerable.Empty());
- var fileSystem3 = Mock.Of(
- f => f.EnumerateItems(basePath) == new[] { file2, file3, });
-
- var compositeRazorProjectFileSystem = new CompositeRazorProjectFileSystem(new[] { fileSystem1, fileSystem2, fileSystem3 });
-
- // Act
- var result = compositeRazorProjectFileSystem.EnumerateItems(basePath);
-
- // Assert
- Assert.Equal(new[] { file1, file2, file3 }, result);
- }
-
- [Fact]
- public void EnumerateItems_ReturnsEmptySequence_IfNoFileSystemReturnsResults()
- {
- // Arrange
- var basePath = "base-path";
- var fileSystem1 = Mock.Of(
- f => f.EnumerateItems(basePath) == Enumerable.Empty());
- var fileSystem2 = Mock.Of(
- f => f.EnumerateItems(basePath) == Enumerable.Empty());
-
- var compositeRazorProjectFileSystem = new CompositeRazorProjectFileSystem(new[] { fileSystem1, fileSystem2 });
-
- // Act
- var result = compositeRazorProjectFileSystem.EnumerateItems(basePath);
-
- // Assert
- Assert.Empty(result);
- }
-
- [Fact]
- public void GetItem_ReturnsFirstInstanceThatExists()
- {
- // Arrange
- var basePath = "base-path";
- var filePath = "file-path";
- var file1 = new NotFoundProjectItem(basePath, filePath, fileKind: null);
- var file2 = new TestRazorProjectItem(filePath);
- RazorProjectItem nullItem = null;
- var fileSystem1 = Mock.Of(
- f => f.GetItem(filePath, null) == file1);
- var fileSystem2 = Mock.Of(
- f => f.GetItem(filePath, null) == nullItem);
- var fileSystem3 = Mock.Of(
- f => f.GetItem(filePath, null) == file2);
-
- var compositeRazorProjectFileSystem = new CompositeRazorProjectFileSystem(new[] { fileSystem1, fileSystem2, fileSystem3 });
-
- // Act
- var result = compositeRazorProjectFileSystem.GetItem(filePath, fileKind: null);
-
- // Assert
- Assert.Same(file2, result);
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/ConcurrentLruCacheTest.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/ConcurrentLruCacheTest.cs
deleted file mode 100644
index 77ad2f0cf478..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/ConcurrentLruCacheTest.cs
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Xunit;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- public class ConcurrentLruCacheTest
- {
- [Fact]
- public void ConcurrentLruCache_HoldsCapacity()
- {
- // Arrange
- var input = GetKeyValueArray(Enumerable.Range(1, 3));
- var expected = input.Reverse();
-
- // Act
- var cache = new ConcurrentLruCache(input);
-
- // Assert
- Assert.Equal(expected, cache.TestingEnumerable);
- }
-
- [Fact]
- public void Add_ThrowsIfKeyExists()
- {
- // Arrange
- var input = GetKeyValueArray(Enumerable.Range(1, 3));
- var cache = new ConcurrentLruCache(input);
-
- // Act & Assert
- var exception = Assert.Throws(() => cache.Add(1, 1));
- Assert.StartsWith("Key already exists", exception.Message);
- }
-
- [Fact]
- public void GetOrAdd_AddsIfKeyDoesNotExist()
- {
- // Arrange
- var input = GetKeyValueArray(Enumerable.Range(1, 3));
- var expected = GetKeyValueArray(Enumerable.Range(2, 3)).Reverse();
- var cache = new ConcurrentLruCache(input);
-
- // Act
- cache.GetOrAdd(4, 4);
-
- // Assert
- Assert.Equal(expected, cache.TestingEnumerable);
- }
-
- [Fact]
- public void Remove_RemovesEntry()
- {
- // Arrange
- var input = GetKeyValueArray(Enumerable.Range(1, 3));
- var expected = GetKeyValueArray(Enumerable.Range(1, 2)).Reverse();
- var cache = new ConcurrentLruCache(input);
-
- // Act
- var result = cache.Remove(3);
-
- // Assert
- Assert.True(result);
- Assert.Equal(expected, cache.TestingEnumerable);
- }
-
- [Fact]
- public void Remove_KeyNotFound_ReturnsFalse()
- {
- // Arrange
- var input = GetKeyValueArray(Enumerable.Range(1, 3));
- var cache = new ConcurrentLruCache(input);
-
- // Act
- var result = cache.Remove(4);
-
- // Assert
- Assert.False(result);
- }
-
- [Fact]
- public void Add_NoRead_EvictsLastNode()
- {
- // Arrange
- var input = GetKeyValueArray(Enumerable.Range(1, 3));
- var expected = GetKeyValueArray(Enumerable.Range(2, 3)).Reverse();
- var cache = new ConcurrentLruCache(input);
-
- // Act
- cache.Add(4, 4);
-
- // Assert
- Assert.Equal(expected, cache.TestingEnumerable);
- }
-
- [Fact]
- public void Add_ReadLastNode_EvictsSecondOldestNode()
- {
- // Arrange
- var input = GetKeyValueArray(Enumerable.Range(1, 3));
- var expected = GetKeyValueArray(new int[] { 4, 1, 3 });
- var cache = new ConcurrentLruCache(input);
-
- // Act
- cache.GetOrAdd(1, 1); // Read to make this MRU
- cache.Add(4, 4); // Add a new node
-
- // Assert
- Assert.Equal(expected, cache.TestingEnumerable);
- }
-
- private KeyValuePair[] GetKeyValueArray(IEnumerable inputArray)
- {
- return inputArray.Select(v => new KeyValuePair(v, v)).ToArray();
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/DefaultExtensionAssemblyLoaderTest.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/DefaultExtensionAssemblyLoaderTest.cs
deleted file mode 100644
index 2997bd08b3c5..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/DefaultExtensionAssemblyLoaderTest.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.IO;
-using System.Text;
-using Xunit;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- public class DefaultExtensionAssemblyLoaderTest
- {
- [Fact]
- public void LoadFromPath_CanLoadAssembly()
- {
- using (var directory = TempDirectory.Create())
- {
- // Arrange
- var alphaFilePath = LoaderTestResources.Alpha.WriteToFile(directory.DirectoryPath, "Alpha.dll");
-
- var loader = new TestDefaultExtensionAssemblyLoader(Path.Combine(directory.DirectoryPath, "shadow"));
-
- // Act
- var assembly = loader.LoadFromPath(alphaFilePath);
-
- // Assert
- Assert.NotNull(assembly);
- }
- }
-
- [Fact]
- public void LoadFromPath_DoesNotAddDuplicates_AfterLoadingByName()
- {
- using (var directory = TempDirectory.Create())
- {
- // Arrange
- var alphaFilePath = LoaderTestResources.Alpha.WriteToFile(directory.DirectoryPath, "Alpha.dll");
- var alphaFilePath2 = LoaderTestResources.Alpha.WriteToFile(directory.DirectoryPath, "Alpha2.dll");
-
- var loader = new TestDefaultExtensionAssemblyLoader(Path.Combine(directory.DirectoryPath, "shadow"));
- loader.AddAssemblyLocation(alphaFilePath);
-
- var assembly1 = loader.Load("Alpha");
-
- // Act
- var assembly2 = loader.LoadFromPath(alphaFilePath2);
-
- // Assert
- Assert.Same(assembly1, assembly2);
- }
- }
-
- [Fact]
- public void LoadFromPath_DoesNotAddDuplicates_AfterLoadingByPath()
- {
- using (var directory = TempDirectory.Create())
- {
- // Arrange
- var alphaFilePath = LoaderTestResources.Alpha.WriteToFile(directory.DirectoryPath, "Alpha.dll");
- var alphaFilePath2 = LoaderTestResources.Alpha.WriteToFile(directory.DirectoryPath, "Alpha2.dll");
-
- var loader = new TestDefaultExtensionAssemblyLoader(Path.Combine(directory.DirectoryPath, "shadow"));
- var assembly1 = loader.LoadFromPath(alphaFilePath);
-
- // Act
- var assembly2 = loader.LoadFromPath(alphaFilePath2);
-
- // Assert
- Assert.Same(assembly1, assembly2);
- }
- }
-
- [Fact]
- public void Load_CanLoadAssemblyByName_AfterLoadingByPath()
- {
- using (var directory = TempDirectory.Create())
- {
- // Arrange
- var alphaFilePath = LoaderTestResources.Alpha.WriteToFile(directory.DirectoryPath, "Alpha.dll");
-
- var loader = new TestDefaultExtensionAssemblyLoader(Path.Combine(directory.DirectoryPath, "shadow"));
- var assembly1 = loader.LoadFromPath(alphaFilePath);
-
- // Act
- var assembly2 = loader.Load(assembly1.FullName);
-
- // Assert
- Assert.Same(assembly1, assembly2);
- }
- }
-
- [Fact]
- public void LoadFromPath_WithDependencyPathsSpecified_CanLoadAssemblyDependencies()
- {
- using (var directory = TempDirectory.Create())
- {
- // Arrange
- var alphaFilePath = LoaderTestResources.Alpha.WriteToFile(directory.DirectoryPath, "Alpha.dll");
- var betaFilePath = LoaderTestResources.Beta.WriteToFile(directory.DirectoryPath, "Beta.dll");
- var gammaFilePath = LoaderTestResources.Gamma.WriteToFile(directory.DirectoryPath, "Gamma.dll");
- var deltaFilePath = LoaderTestResources.Delta.WriteToFile(directory.DirectoryPath, "Delta.dll");
-
- var loader = new TestDefaultExtensionAssemblyLoader(Path.Combine(directory.DirectoryPath, "shadow"));
- loader.AddAssemblyLocation(gammaFilePath);
- loader.AddAssemblyLocation(deltaFilePath);
-
- // Act
- var alpha = loader.LoadFromPath(alphaFilePath);
- var beta = loader.LoadFromPath(betaFilePath);
-
- // Assert
- var builder = new StringBuilder();
-
- var a = alpha.CreateInstance("Alpha.A");
- a.GetType().GetMethod("Write").Invoke(a, new object[] { builder, "Test A" });
-
- var b = beta.CreateInstance("Beta.B");
- b.GetType().GetMethod("Write").Invoke(b, new object[] { builder, "Test B" });
- var expected = @"Delta: Gamma: Alpha: Test A
-Delta: Gamma: Beta: Test B
-";
-
- var actual = builder.ToString();
-
- Assert.Equal(expected, actual, ignoreLineEndingDifferences: true);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/DefaultExtensionDependencyCheckerTest.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/DefaultExtensionDependencyCheckerTest.cs
deleted file mode 100644
index b9b9c8ac1150..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/DefaultExtensionDependencyCheckerTest.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.IO;
-using Moq;
-using Xunit;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- public class DefaultExtensionDependencyCheckerTest
- {
- [Fact]
- public void Check_ReturnsFalse_WithMissingDependency()
- {
- using (var directory = TempDirectory.Create())
- {
- // Arrange
- var output = new StringWriter();
-
- var alphaFilePath = LoaderTestResources.Alpha.WriteToFile(directory.DirectoryPath, "Alpha.dll");
-
- var loader = new TestDefaultExtensionAssemblyLoader(Path.Combine(directory.DirectoryPath, "shadow"));
- var checker = new DefaultExtensionDependencyChecker(loader, output, output);
-
- // Act
- var result = checker.Check(new[] { alphaFilePath, });
-
- // Assert
- Assert.False(result, "Check should not have passed: " + output.ToString());
- }
- }
-
- [Fact]
- public void Check_ReturnsTrue_WithAllDependenciesProvided()
- {
- using (var directory = TempDirectory.Create())
- {
- // Arrange
- var output = new StringWriter();
-
- var alphaFilePath = LoaderTestResources.Alpha.WriteToFile(directory.DirectoryPath, "Alpha.dll");
- var betaFilePath = LoaderTestResources.Beta.WriteToFile(directory.DirectoryPath, "Beta.dll");
- var gammaFilePath = LoaderTestResources.Gamma.WriteToFile(directory.DirectoryPath, "Gamma.dll");
- var deltaFilePath = LoaderTestResources.Delta.WriteToFile(directory.DirectoryPath, "Delta.dll");
-
- var loader = new TestDefaultExtensionAssemblyLoader(Path.Combine(directory.DirectoryPath, "shadow"));
- var checker = new DefaultExtensionDependencyChecker(loader, output, output);
-
- // Act
- var result = checker.Check(new[] { alphaFilePath, betaFilePath, gammaFilePath, deltaFilePath, });
-
- // Assert
- Assert.True(result, "Check should have passed: " + output.ToString());
- }
- }
-
- [Fact]
- public void Check_ReturnsFalse_WhenAssemblyHasDifferentMVID()
- {
- using (var directory = TempDirectory.Create())
- {
- // Arrange
- var output = new StringWriter();
-
- // Load Beta.dll from the future Alpha.dll path to prime the assembly loader
- var alphaFilePath = LoaderTestResources.Beta.WriteToFile(directory.DirectoryPath, "Alpha.dll");
- var betaFilePath = LoaderTestResources.Beta.WriteToFile(directory.DirectoryPath, "Beta.dll");
- var gammaFilePath = LoaderTestResources.Gamma.WriteToFile(directory.DirectoryPath, "Gamma.dll");
- var deltaFilePath = LoaderTestResources.Delta.WriteToFile(directory.DirectoryPath, "Delta.dll");
-
- var loader = new TestDefaultExtensionAssemblyLoader(Path.Combine(directory.DirectoryPath, "shadow"));
- var checker = new DefaultExtensionDependencyChecker(loader, output, output);
-
- // This will cause the loader to cache some inconsistent information.
- loader.LoadFromPath(alphaFilePath);
- LoaderTestResources.Alpha.WriteToFile(directory.DirectoryPath, "Alpha.dll");
-
- // Act
- var result = checker.Check(new[] { alphaFilePath, gammaFilePath, deltaFilePath, });
-
- // Assert
- Assert.False(result, "Check should not have passed: " + output.ToString());
- }
- }
-
- [Fact]
- public void Check_ReturnsFalse_WhenLoaderThrows()
- {
- using (var directory = TempDirectory.Create())
- {
- // Arrange
- var output = new StringWriter();
-
- var deltaFilePath = LoaderTestResources.Delta.WriteToFile(directory.DirectoryPath, "Delta.dll");
-
- var loader = new Mock();
- loader
- .Setup(l => l.LoadFromPath(It.IsAny()))
- .Throws(new InvalidOperationException());
- var checker = new DefaultExtensionDependencyChecker(loader.Object, output, output);
-
- // Act
- var result = checker.Check(new[] { deltaFilePath, });
-
- // Assert
- Assert.False(result, "Check should not have passed: " + output.ToString());
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/DefaultRequestDispatcherTest.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/DefaultRequestDispatcherTest.cs
deleted file mode 100644
index c852648dc2ff..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/DefaultRequestDispatcherTest.cs
+++ /dev/null
@@ -1,572 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Moq;
-using Xunit;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- public class DefaultRequestDispatcherTest
- {
- private static ServerRequest EmptyServerRequest => new ServerRequest(1, Array.Empty());
-
- private static ServerResponse EmptyServerResponse => new CompletedServerResponse(
- returnCode: 0,
- utf8output: false,
- output: string.Empty,
- error: string.Empty);
-
- [Fact]
- public async Task AcceptConnection_ReadingRequestFails_ClosesConnection()
- {
- // Arrange
- var stream = Mock.Of();
- var compilerHost = CreateCompilerHost();
- var connectionHost = CreateConnectionHost();
- var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None);
- var connection = CreateConnection(stream);
-
- // Act
- var result = await dispatcher.AcceptConnection(
- Task.FromResult(connection), accept: true, cancellationToken: CancellationToken.None);
-
- // Assert
- Assert.Equal(ConnectionResult.Reason.CompilationNotStarted, result.CloseReason);
- }
-
- ///
- /// A failure to write the results to the client is considered a client disconnection. Any error
- /// from when the build starts to when the write completes should be handled this way.
- ///
- [Fact]
- public async Task AcceptConnection_WritingResultsFails_ClosesConnection()
- {
- // Arrange
- var memoryStream = new MemoryStream();
- await EmptyServerRequest.WriteAsync(memoryStream, CancellationToken.None).ConfigureAwait(true);
- memoryStream.Position = 0;
-
- var stream = new Mock(MockBehavior.Strict);
- stream
- .Setup(x => x.ReadAsync(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
- .Returns((byte[] array, int start, int length, CancellationToken ct) => memoryStream.ReadAsync(array, start, length, ct));
-
- var connection = CreateConnection(stream.Object);
- var compilerHost = CreateCompilerHost(c =>
- {
- c.ExecuteFunc = (req, ct) =>
- {
- return EmptyServerResponse;
- };
- });
- var connectionHost = CreateConnectionHost();
- var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None);
-
- // Act
- // We expect WriteAsync to fail because the mock stream doesn't have a corresponding setup.
- var connectionResult = await dispatcher.AcceptConnection(
- Task.FromResult(connection), accept: true, cancellationToken: CancellationToken.None);
-
- // Assert
- Assert.Equal(ConnectionResult.Reason.ClientDisconnect, connectionResult.CloseReason);
- Assert.Null(connectionResult.KeepAlive);
- }
-
- ///
- /// Ensure the Connection correctly handles the case where a client disconnects while in the
- /// middle of executing a request.
- ///
- [Fact]
- public async Task AcceptConnection_ClientDisconnectsWhenExecutingRequest_ClosesConnection()
- {
- // Arrange
- var connectionHost = Mock.Of();
-
- // Fake a long running task here that we can validate later on.
- var buildTaskSource = new TaskCompletionSource();
- var buildTaskCancellationToken = default(CancellationToken);
- var compilerHost = CreateCompilerHost(c =>
- {
- c.ExecuteFunc = (req, ct) =>
- {
- Task.WaitAll(buildTaskSource.Task);
- return EmptyServerResponse;
- };
- });
-
- var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None);
- var readyTaskSource = new TaskCompletionSource();
- var disconnectTaskSource = new TaskCompletionSource();
- var connectionTask = CreateConnectionWithEmptyServerRequest(c =>
- {
- c.WaitForDisconnectAsyncFunc = (ct) =>
- {
- buildTaskCancellationToken = ct;
- readyTaskSource.SetResult(true);
- return disconnectTaskSource.Task;
- };
- });
-
- var handleTask = dispatcher.AcceptConnection(
- connectionTask, accept: true, cancellationToken: CancellationToken.None);
-
- // Wait until WaitForDisconnectAsync task is actually created and running.
- await readyTaskSource.Task.ConfigureAwait(false);
-
- // Act
- // Now simulate a disconnect by the client.
- disconnectTaskSource.SetResult(true);
- var connectionResult = await handleTask;
- buildTaskSource.SetResult(true);
-
- // Assert
- Assert.Equal(ConnectionResult.Reason.ClientDisconnect, connectionResult.CloseReason);
- Assert.Null(connectionResult.KeepAlive);
- Assert.True(buildTaskCancellationToken.IsCancellationRequested);
- }
-
- [Fact]
- public async Task AcceptConnection_AcceptFalse_RejectsBuildRequest()
- {
- // Arrange
- var stream = new TestableStream();
- await EmptyServerRequest.WriteAsync(stream.ReadStream, CancellationToken.None);
- stream.ReadStream.Position = 0;
-
- var connection = CreateConnection(stream);
- var connectionHost = CreateConnectionHost();
- var compilerHost = CreateCompilerHost();
- var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None);
-
- // Act
- var connectionResult = await dispatcher.AcceptConnection(
- Task.FromResult(connection), accept: false, cancellationToken: CancellationToken.None);
-
- // Assert
- Assert.Equal(ConnectionResult.Reason.CompilationNotStarted, connectionResult.CloseReason);
- stream.WriteStream.Position = 0;
- var response = await ServerResponse.ReadAsync(stream.WriteStream).ConfigureAwait(false);
- Assert.Equal(ServerResponse.ResponseType.Rejected, response.Type);
- }
-
- [Fact]
- public async Task AcceptConnection_ShutdownRequest_ReturnsShutdownResponse()
- {
- // Arrange
- var stream = new TestableStream();
- await ServerRequest.CreateShutdown().WriteAsync(stream.ReadStream, CancellationToken.None);
- stream.ReadStream.Position = 0;
-
- var connection = CreateConnection(stream);
- var connectionHost = CreateConnectionHost();
- var compilerHost = CreateCompilerHost();
- var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None);
-
- // Act
- var connectionResult = await dispatcher.AcceptConnection(
- Task.FromResult(connection), accept: true, cancellationToken: CancellationToken.None);
-
- // Assert
- Assert.Equal(ConnectionResult.Reason.ClientShutdownRequest, connectionResult.CloseReason);
- stream.WriteStream.Position = 0;
- var response = await ServerResponse.ReadAsync(stream.WriteStream).ConfigureAwait(false);
- Assert.Equal(ServerResponse.ResponseType.Shutdown, response.Type);
- }
-
- [Fact]
- public async Task AcceptConnection_ConnectionHostThrowsWhenConnecting_ClosesConnection()
- {
- // Arrange
- var connectionHost = new Mock(MockBehavior.Strict);
- connectionHost.Setup(c => c.WaitForConnectionAsync(It.IsAny())).Throws(new Exception());
- var compilerHost = CreateCompilerHost();
- var dispatcher = new DefaultRequestDispatcher(connectionHost.Object, compilerHost, CancellationToken.None);
- var connection = CreateConnection(Mock.Of());
-
- // Act
- var connectionResult = await dispatcher.AcceptConnection(
- Task.FromResult(connection), accept: true, cancellationToken: CancellationToken.None);
-
- // Assert
- Assert.Equal(ConnectionResult.Reason.CompilationNotStarted, connectionResult.CloseReason);
- Assert.Null(connectionResult.KeepAlive);
- }
-
- [Fact]
- public async Task AcceptConnection_ClientConnectionThrowsWhenConnecting_ClosesConnection()
- {
- // Arrange
- var compilerHost = CreateCompilerHost();
- var connectionHost = CreateConnectionHost();
- var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None);
- var connectionTask = Task.FromException(new Exception());
-
- // Act
- var connectionResult = await dispatcher.AcceptConnection(
- connectionTask, accept: true, cancellationToken: CancellationToken.None);
-
- // Assert
- Assert.Equal(ConnectionResult.Reason.CompilationNotStarted, connectionResult.CloseReason);
- Assert.Null(connectionResult.KeepAlive);
- }
-
- [Fact]
- public async Task Dispatcher_ClientConnectionThrowsWhenExecutingRequest_ClosesConnection()
- {
- // Arrange
- var called = false;
- var connectionTask = CreateConnectionWithEmptyServerRequest(c =>
- {
- c.WaitForDisconnectAsyncFunc = (ct) =>
- {
- called = true;
- throw new Exception();
- };
- });
-
- var compilerHost = CreateCompilerHost();
- var connectionHost = CreateConnectionHost();
- var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None);
-
- // Act
- var connectionResult = await dispatcher.AcceptConnection(
- connectionTask, accept: true, cancellationToken: CancellationToken.None);
-
- // Assert
- Assert.True(called);
- Assert.Equal(ConnectionResult.Reason.ClientException, connectionResult.CloseReason);
- Assert.Null(connectionResult.KeepAlive);
- }
-
- [Fact]
- public void Dispatcher_NoConnections_HitsKeepAliveTimeout()
- {
- // Arrange
- var keepAlive = TimeSpan.FromSeconds(3);
- var compilerHost = CreateCompilerHost();
- var connectionHost = new Mock();
- connectionHost
- .Setup(x => x.WaitForConnectionAsync(It.IsAny()))
- .Returns(new TaskCompletionSource().Task);
-
- var eventBus = new TestableEventBus();
- var dispatcher = new DefaultRequestDispatcher(connectionHost.Object, compilerHost, CancellationToken.None, eventBus, keepAlive);
- var startTime = DateTime.Now;
-
- // Act
- dispatcher.Run();
-
- // Assert
- Assert.True(eventBus.HitKeepAliveTimeout);
- }
-
- ///
- /// Ensure server respects keep alive and shuts down after processing a single connection.
- ///
- [Fact]
- public void Dispatcher_ProcessSingleConnection_HitsKeepAliveTimeout()
- {
- // Arrange
- var connectionTask = CreateConnectionWithEmptyServerRequest();
- var keepAlive = TimeSpan.FromSeconds(1);
- var compilerHost = CreateCompilerHost(c =>
- {
- c.ExecuteFunc = (req, ct) =>
- {
- return EmptyServerResponse;
- };
- });
- var connectionHost = CreateConnectionHost(connectionTask, new TaskCompletionSource().Task);
-
- var eventBus = new TestableEventBus();
- var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None, eventBus, keepAlive);
-
- // Act
- dispatcher.Run();
-
- // Assert
- Assert.Equal(1, eventBus.CompletedCount);
- Assert.True(eventBus.LastProcessedTime.HasValue);
- Assert.True(eventBus.HitKeepAliveTimeout);
- }
-
- ///
- /// Ensure server respects keep alive and shuts down after processing multiple connections.
- ///
- [Fact]
- public void Dispatcher_ProcessMultipleConnections_HitsKeepAliveTimeout()
- {
- // Arrange
- var count = 5;
- var list = new List>();
- for (var i = 0; i < count; i++)
- {
- var connectionTask = CreateConnectionWithEmptyServerRequest();
- list.Add(connectionTask);
- }
-
- list.Add(new TaskCompletionSource().Task);
- var connectionHost = CreateConnectionHost(list.ToArray());
- var compilerHost = CreateCompilerHost(c =>
- {
- c.ExecuteFunc = (req, ct) =>
- {
- return EmptyServerResponse;
- };
- });
-
- var keepAlive = TimeSpan.FromSeconds(1);
- var eventBus = new TestableEventBus();
- var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None, eventBus, keepAlive);
-
- // Act
- dispatcher.Run();
-
- // Assert
- Assert.Equal(count, eventBus.CompletedCount);
- Assert.True(eventBus.LastProcessedTime.HasValue);
- Assert.True(eventBus.HitKeepAliveTimeout);
- }
-
- ///
- /// Ensure server respects keep alive and shuts down after processing simultaneous connections.
- ///
- [Fact]
- public async Task Dispatcher_ProcessSimultaneousConnections_HitsKeepAliveTimeout()
- {
- // Arrange
- var totalCount = 2;
- var readySource = new TaskCompletionSource();
- var list = new List>();
- var connectionHost = new Mock();
- connectionHost
- .Setup(x => x.WaitForConnectionAsync(It.IsAny()))
- .Returns((CancellationToken ct) =>
- {
- if (list.Count < totalCount)
- {
- var source = new TaskCompletionSource();
- var connectionTask = CreateConnectionWithEmptyServerRequest(c =>
- {
- // Keep the connection active until we decide to end it.
- c.WaitForDisconnectAsyncFunc = _ => source.Task;
- });
- list.Add(source);
- return connectionTask;
- }
-
- readySource.SetResult(true);
- return new TaskCompletionSource().Task;
- });
-
- var compilerHost = CreateCompilerHost(c =>
- {
- c.ExecuteFunc = (req, ct) =>
- {
- return EmptyServerResponse;
- };
- });
-
- var eventBus = new TestableEventBus();
- var completedCompilations = 0;
- var allCompilationsComplete = new TaskCompletionSource();
- eventBus.CompilationComplete += (obj, args) =>
- {
- if (++completedCompilations == totalCount)
- {
- // All compilations have completed.
- allCompilationsComplete.SetResult(true);
- }
- };
- var keepAlive = TimeSpan.FromSeconds(1);
- var dispatcherTask = Task.Run(() =>
- {
- var dispatcher = new DefaultRequestDispatcher(connectionHost.Object, compilerHost, CancellationToken.None, eventBus, keepAlive);
- dispatcher.Run();
- });
-
- // Wait for all connections to be created.
- await readySource.Task;
-
- // Wait for all compilations to complete.
- await allCompilationsComplete.Task;
-
- // Now allow all the connections to be disconnected.
- foreach (var source in list)
- {
- source.SetResult(true);
- }
-
- // Act
- // Now dispatcher should be in an idle state with no active connections.
- await dispatcherTask;
-
- // Assert
- Assert.False(eventBus.HasDetectedBadConnection);
- Assert.Equal(totalCount, eventBus.CompletedCount);
- Assert.True(eventBus.LastProcessedTime.HasValue, "LastProcessedTime should have had a value.");
- Assert.True(eventBus.HitKeepAliveTimeout, "HitKeepAliveTimeout should have been hit.");
- }
-
- [Fact]
- public void Dispatcher_ClientConnectionThrows_BeginsShutdown()
- {
- // Arrange
- var listenCancellationToken = default(CancellationToken);
- var firstConnectionTask = CreateConnectionWithEmptyServerRequest(c =>
- {
- c.WaitForDisconnectAsyncFunc = (ct) =>
- {
- listenCancellationToken = ct;
- return Task.Delay(Timeout.Infinite, ct).ContinueWith(_ => null);
- };
- });
- var secondConnectionTask = CreateConnectionWithEmptyServerRequest(c =>
- {
- c.WaitForDisconnectAsyncFunc = (ct) => throw new Exception();
- });
-
- var compilerHost = CreateCompilerHost();
- var connectionHost = CreateConnectionHost(
- firstConnectionTask,
- secondConnectionTask,
- new TaskCompletionSource().Task);
- var keepAlive = TimeSpan.FromSeconds(10);
- var eventBus = new TestableEventBus();
- var dispatcher = new DefaultRequestDispatcher(connectionHost, compilerHost, CancellationToken.None, eventBus, keepAlive);
-
- // Act
- dispatcher.Run();
-
- // Assert
- Assert.True(eventBus.HasDetectedBadConnection);
- Assert.True(listenCancellationToken.IsCancellationRequested);
- }
-
- private static TestableConnection CreateConnection(Stream stream, string identifier = null)
- {
- return new TestableConnection(stream, identifier ?? "identifier");
- }
-
- private static async Task CreateConnectionWithEmptyServerRequest(Action configureConnection = null)
- {
- var memoryStream = new MemoryStream();
- await EmptyServerRequest.WriteAsync(memoryStream, CancellationToken.None);
- memoryStream.Position = 0;
- var connection = CreateConnection(memoryStream);
- configureConnection?.Invoke(connection);
-
- return connection;
- }
-
- private static ConnectionHost CreateConnectionHost(params Task[] connections)
- {
- var host = new Mock();
- if (connections.Length > 0)
- {
- var index = 0;
- host
- .Setup(x => x.WaitForConnectionAsync(It.IsAny()))
- .Returns((CancellationToken ct) => connections[index++]);
- }
-
- return host.Object;
- }
-
- private static TestableCompilerHost CreateCompilerHost(Action configureCompilerHost = null)
- {
- var compilerHost = new TestableCompilerHost();
- configureCompilerHost?.Invoke(compilerHost);
-
- return compilerHost;
- }
-
- private class TestableCompilerHost : CompilerHost
- {
- internal Func ExecuteFunc;
-
- public override ServerResponse Execute(ServerRequest request, CancellationToken cancellationToken)
- {
- if (ExecuteFunc != null)
- {
- return ExecuteFunc(request, cancellationToken);
- }
-
- return EmptyServerResponse;
- }
- }
-
- private class TestableConnection : Connection
- {
- internal Func WaitForDisconnectAsyncFunc;
-
- public TestableConnection(Stream stream, string identifier)
- {
- Stream = stream;
- Identifier = identifier;
- WaitForDisconnectAsyncFunc = ct => Task.Delay(Timeout.Infinite, ct);
- }
-
- public override Task WaitForDisconnectAsync(CancellationToken cancellationToken)
- {
- return WaitForDisconnectAsyncFunc(cancellationToken);
- }
- }
-
- private class TestableStream : Stream
- {
- internal readonly MemoryStream ReadStream = new MemoryStream();
- internal readonly MemoryStream WriteStream = new MemoryStream();
-
- public override bool CanRead => true;
- public override bool CanSeek => false;
- public override bool CanWrite => true;
- public override long Length { get { throw new NotImplementedException(); } }
- public override long Position
- {
- get { throw new NotImplementedException(); }
- set { throw new NotImplementedException(); }
- }
-
- public override void Flush()
- {
- }
-
- public override int Read(byte[] buffer, int offset, int count)
- {
- return ReadStream.Read(buffer, offset, count);
- }
-
- public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- return ReadStream.ReadAsync(buffer, offset, count, cancellationToken);
- }
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotImplementedException();
- }
-
- public override void SetLength(long value)
- {
- throw new NotImplementedException();
- }
-
- public override void Write(byte[] buffer, int offset, int count)
- {
- WriteStream.Write(buffer, offset, count);
- }
-
- public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
- {
- return WriteStream.WriteAsync(buffer, offset, count, cancellationToken);
- }
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/Infrastructure/ServerData.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/Infrastructure/ServerData.cs
deleted file mode 100644
index 37a9d0180aaa..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/Infrastructure/ServerData.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal sealed class ServerData : IDisposable
- {
- internal CancellationTokenSource CancellationTokenSource { get; }
- internal Task ServerTask { get; }
- internal Task ListenTask { get; }
- internal string PipeName { get; }
-
- internal ServerData(CancellationTokenSource cancellationTokenSource, string pipeName, Task serverTask, Task listenTask)
- {
- CancellationTokenSource = cancellationTokenSource;
- PipeName = pipeName;
- ServerTask = serverTask;
- ListenTask = listenTask;
- }
-
- internal async Task CancelAndCompleteAsync()
- {
- CancellationTokenSource.Cancel();
- return await ServerTask;
- }
-
- internal async Task Verify(int connections, int completed)
- {
- var stats = await CancelAndCompleteAsync().ConfigureAwait(false);
- Assert.Equal(connections, stats.Connections);
- Assert.Equal(completed, stats.CompletedConnections);
- }
-
- public void Dispose()
- {
- if (!CancellationTokenSource.IsCancellationRequested)
- {
- CancellationTokenSource.Cancel();
- }
-
- ServerTask.Wait();
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/Infrastructure/ServerStats.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/Infrastructure/ServerStats.cs
deleted file mode 100644
index ce4064528ff3..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/Infrastructure/ServerStats.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal struct ServerStats
- {
- internal readonly int Connections;
- internal readonly int CompletedConnections;
-
- internal ServerStats(int connections, int completedConnections)
- {
- Connections = connections;
- CompletedConnections = completedConnections;
- }
- }
-}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/Infrastructure/ServerUtilities.cs b/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/Infrastructure/ServerUtilities.cs
deleted file mode 100644
index 65e407f64437..000000000000
--- a/src/Razor/Microsoft.AspNetCore.Razor.Tools/test/Infrastructure/ServerUtilities.cs
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis;
-using Moq;
-
-namespace Microsoft.AspNetCore.Razor.Tools
-{
- internal static class ServerUtilities
- {
- internal static string DefaultClientDirectory { get; } = Path.GetDirectoryName(typeof(ServerUtilities).Assembly.Location);
-
- internal static ServerPaths CreateBuildPaths(string workingDir, string tempDir)
- {
- return new ServerPaths(
- clientDir: DefaultClientDirectory,
- workingDir: workingDir,
- tempDir: tempDir);
- }
-
- internal static ServerData CreateServer(
- string pipeName = null,
- CompilerHost compilerHost = null,
- ConnectionHost connectionHost = null,
- Action