Begin fixup package validation

上级 1dbca251
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27102.0
# Visual Studio Version 16
VisualStudioVersion = 16.0.28606.126
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.UnitTests", "src\Compilers\Core\CodeAnalysisTest\Microsoft.CodeAnalysis.UnitTests.csproj", "{A4C99B85-765C-4C65-9C2A-BB609AAB09E6}"
EndProject
......@@ -160,6 +160,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompilerBenchmarks", "src\T
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildBoss", "src\Tools\BuildBoss\BuildBoss.csproj", "{8A02AFAF-F622-4E3E-9E1A-8CFDACC7C7E1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Net.Compilers.Toolset.Package", "src\NuGet\Microsoft.Net.Compilers.Toolset\Microsoft.Net.Compilers.Toolset.Package.csproj", "{6D407402-CC4A-4125-9B00-C70562A636A5}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 4
......@@ -435,6 +437,10 @@ Global
{8A02AFAF-F622-4E3E-9E1A-8CFDACC7C7E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A02AFAF-F622-4E3E-9E1A-8CFDACC7C7E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A02AFAF-F622-4E3E-9E1A-8CFDACC7C7E1}.Release|Any CPU.Build.0 = Release|Any CPU
{6D407402-CC4A-4125-9B00-C70562A636A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D407402-CC4A-4125-9B00-C70562A636A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D407402-CC4A-4125-9B00-C70562A636A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D407402-CC4A-4125-9B00-C70562A636A5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......@@ -508,6 +514,7 @@ Global
{2483917E-7024-4D10-99C6-2BEF338FF53B} = {274B96B7-F815-47E3-9CA4-4024A57A478F}
{B446E771-AB52-41C9-ACFC-FDF8EACAF291} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{8A02AFAF-F622-4E3E-9E1A-8CFDACC7C7E1} = {FD0FAF5F-1DED-485C-99FA-84B97F3A8EEC}
{6D407402-CC4A-4125-9B00-C70562A636A5} = {274B96B7-F815-47E3-9CA4-4024A57A478F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6F599E08-A9EA-4FAA-897F-5D824B0210E6}
......
......@@ -407,6 +407,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Exte
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.TypeScript", "src\Tools\ExternalAccess\TypeScript\Microsoft.CodeAnalysis.ExternalAccess.TypeScript.csproj", "{1638FB04-0298-4341-B5E0-8A13B4823C81}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Net.Compilers.Toolset.Package", "src\NuGet\Microsoft.Net.Compilers.Toolset\Microsoft.Net.Compilers.Toolset.Package.csproj", "{A74C7D2E-92FA-490A-B80A-28BEF56B56FC}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Compilers\VisualBasic\BasicAnalyzerDriver\BasicAnalyzerDriver.projitems*{2523d0e6-df32-4a3e-8ae0-a19bffae2ef6}*SharedItemsImports = 4
......@@ -1072,6 +1074,10 @@ Global
{1638FB04-0298-4341-B5E0-8A13B4823C81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1638FB04-0298-4341-B5E0-8A13B4823C81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1638FB04-0298-4341-B5E0-8A13B4823C81}.Release|Any CPU.Build.0 = Release|Any CPU
{A74C7D2E-92FA-490A-B80A-28BEF56B56FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A74C7D2E-92FA-490A-B80A-28BEF56B56FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A74C7D2E-92FA-490A-B80A-28BEF56B56FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A74C7D2E-92FA-490A-B80A-28BEF56B56FC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......@@ -1263,6 +1269,7 @@ Global
{BD8CE303-5F04-45EC-8DCF-73C9164CD614} = {8977A560-45C2-4EC2-A849-97335B382C74}
{2FB6C157-DF91-4B1C-9827-A4D1C08C73EC} = {8977A560-45C2-4EC2-A849-97335B382C74}
{1638FB04-0298-4341-B5E0-8A13B4823C81} = {8977A560-45C2-4EC2-A849-97335B382C74}
{A74C7D2E-92FA-490A-B80A-28BEF56B56FC} = {C52D8057-43AF-40E6-A01B-6CDBB7301985}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {604E6B91-7BC0-4126-AE07-D4D2FEFC3D29}
......
......@@ -29,9 +29,9 @@
<ProjectReference Include="..\..\Compilers\Server\VBCSCompiler\VBCSCompiler.csproj" PrivateAssets="all"/>
</ItemGroup>
<Target Name="_GetFilesToPackage" DependsOnTargets="InitializeDestkopCompilerArtifacts">
<Target Name="_GetFilesToPackage" DependsOnTargets="InitializeDesktopCompilerArtifacts">
<ItemGroup>
<_File Include="@(DestkopCompilerArtifact)" TargetDir="" />
<_File Include="@(DesktopCompilerArtifact)" TargetDir="" />
<_File Include="$(MSBuildProjectDirectory)\Init.cmd" TargetDir="" />
<!-- Workaround for https://github.com/dotnet/roslyn/issues/17864 -->
......
......@@ -26,6 +26,26 @@ namespace BuildBoss
/// </summary>
internal sealed class PackageContentsChecker : ICheckerUtil
{
private readonly struct PackageAsset
{
public bool IsDesktop { get; }
public string FileRelativeName { get; }
public string Checksum { get; }
public bool IsCoreClr => !IsDesktop;
public string FileName => Path.GetFileName(FileRelativeName);
public PackageAsset(string fileRelativeName, string checksum, bool isDesktop)
{
FileRelativeName = fileRelativeName;
Checksum = checksum;
IsDesktop = isDesktop;
}
public PackageAsset WithFileRelativeName(string fileRelativeName) => new PackageAsset(fileRelativeName, Checksum, IsDesktop);
public override string ToString() => FileRelativeName;
}
internal static StringComparer PathComparer { get; } = StringComparer.OrdinalIgnoreCase;
internal static StringComparison PathComparison { get; } = StringComparison.OrdinalIgnoreCase;
......@@ -44,103 +64,137 @@ public bool Check(TextWriter textWriter)
{
try
{
var allGood = CheckDesktop(textWriter);
allGood &= CheckCoreClr(textWriter);
var packageAssets = new List<PackageAsset>();
if (!GetPackageAssets(textWriter, packageAssets))
{
return false;
}
var allGood = true;
allGood &= CheckDesktop(textWriter, filter(isDesktop: true));
allGood &= CheckCoreClr(textWriter, filter(isDesktop: false));
allGood &= CheckCombined(textWriter, packageAssets.Select(x => x.FileRelativeName));
return allGood;
IEnumerable<string> filter(bool isDesktop) => packageAssets.Where(x => x.IsDesktop == isDesktop).Select(x => x.FileRelativeName);
}
catch (Exception ex)
{
textWriter.WriteLine($"Error verifying: {ex.Message}");
return false;
}
}
/// <summary>
/// Verify the contents of our desktop targeting compiler packages are correct.
/// </summary>
private bool CheckDesktop(TextWriter textWriter)
private bool CheckDesktop(TextWriter textWriter, IEnumerable<string> assetRelativeNames)
{
var (allGood, dllRelativeNames) = GetDllRelativeNames(
textWriter,
$@"csc\{Configuration}\net472",
$@"vbc\{Configuration}\net472",
$@"csi\{Configuration}\net472",
$@"VBCSCompiler\{Configuration}\net472",
$@"Microsoft.Build.Tasks.CodeAnalysis\{Configuration}\net472");
if (!allGood)
{
return false;
}
// These are the core MSBuild dlls that will always be present / redirected when running
// inside of desktop MSBuild. Even though they are in our output directories they should
// not be a part of our deployment
// need to be
dllRelativeNames = FilterRelativeFileNames(
dllRelativeNames,
"Microsoft.Build.dll",
"Microsoft.Build.Framework.dll",
"Microsoft.Build.Tasks.Core.dll",
"Microsoft.Build.Utilities.Core.dll").ToList();
var allGood = true;
allGood &= VerifyNuPackage(
textWriter,
FindNuGetPackage(Path.Combine(ArtifactsDirectory, "packages", Configuration, "Shipping"), "Microsoft.Net.Compilers"),
@"tools",
dllRelativeNames);
assetRelativeNames);
allGood &= VerifyNuPackage(
textWriter,
FindNuGetPackage(Path.Combine(ArtifactsDirectory, "VSSetup", Configuration, "DevDivPackages"), "VS.Tools.Roslyn"),
string.Empty,
dllRelativeNames);
assetRelativeNames);
allGood &= VerifyVsix(
textWriter,
FindVsix("Roslyn.Compilers.Extension"),
dllRelativeNames.Concat(new[] { "Roslyn.Compilers.Extension.dll" }));
assetRelativeNames.Concat(new[] { "Roslyn.Compilers.Extension.dll" }));
return allGood;
}
/// <summary>
/// Verify the contents of our desktop targeting compiler packages are correct.
/// </summary>
private bool CheckCoreClr(TextWriter textWriter)
private bool CheckCoreClr(TextWriter textWriter, IEnumerable<string> assetRelativeNames)
{
var (allGood, dllRelativeNames) = GetDllRelativeNames(
textWriter,
$@"csc\{Configuration}\netcoreapp2.1\publish",
$@"vbc\{Configuration}\netcoreapp2.1\publish",
$@"VBCSCompiler\{Configuration}\netcoreapp2.1\publish");
if (!allGood)
{
return false;
}
// The native DLLs ship inside the runtime specific directories but build deploys it at the
// root as well. That copy is unnecessary.
dllRelativeNames = FilterRelativeFileNames(
dllRelativeNames,
assetRelativeNames = FilterRelativeFileNames(
assetRelativeNames,
"Microsoft.DiaSymReader.Native.amd64.dll",
"Microsoft.DiaSymReader.Native.x86.dll").ToList();
return VerifyNuPackage(
textWriter,
FindNuGetPackage(Path.Combine(ArtifactsDirectory, "packages", Configuration, "Shipping"), "Microsoft.NETCore.Compilers"),
@"tools\bincore",
dllRelativeNames);
@"tools",
assetRelativeNames);
}
/// <summary>
/// Verify the contents of our combinde toolset compiler packages are correct.
/// </summary>
private bool CheckCombined(TextWriter textWriter, IEnumerable<string> assetRelativeNames)
{
return VerifyNuPackage(
textWriter,
FindNuGetPackage(Path.Combine(ArtifactsDirectory, "packages", Configuration, "Shipping"), "Microsoft.Net.Compilers.Toolset"),
@"tools",
assetRelativeNames);
}
private bool GetPackageAssets(TextWriter textWriter, List<PackageAsset> packageAssets)
{
var allGood = true;
var desktopAssets = new List<PackageAsset>();
var coreClrAssets = new List<PackageAsset>();
allGood &= GetPackageAssetsCore(
textWriter,
isDesktop: true,
desktopAssets,
$@"csc\{Configuration}\net472",
$@"vbc\{Configuration}\net472",
$@"csi\{Configuration}\net472",
$@"VBCSCompiler\{Configuration}\net472",
$@"Microsoft.Build.Tasks.CodeAnalysis\{Configuration}\net472");
allGood &= GetPackageAssetsCore(
textWriter,
isDesktop: false,
coreClrAssets,
$@"csc\{Configuration}\netcoreapp2.1\publish",
$@"vbc\{Configuration}\netcoreapp2.1\publish",
$@"VBCSCompiler\{Configuration}\netcoreapp2.1\publish");
coreClrAssets = coreClrAssets.Select(x => x.WithFileRelativeName(Path.Combine("bincore", x.FileRelativeName))).ToList();
allGood &= GetPackageAssetsCore(
textWriter,
isDesktop: false,
coreClrAssets,
$@"Microsoft.Build.Tasks.CodeAnalysis\{Configuration}\netcoreapp2.1\publish");
packageAssets.AddRange(desktopAssets);
packageAssets.AddRange(coreClrAssets);
packageAssets.Sort((x, y) => x.FileRelativeName.CompareTo(y.FileRelativeName));
return allGood;
}
/// <summary>
/// Get all of the dependencies in the specified directory set.
/// </summary>
private (bool succeeded, List<string> dllRelativeNames) GetDllRelativeNames(TextWriter textWriter, params string[] directoryPaths)
private bool GetPackageAssetsCore(TextWriter textWriter, bool isDesktop, List<PackageAsset> packageAssets, params string[] directoryPaths)
{
var dllToChecksumMap = new Dictionary<string, string>(PathComparer);
var relativeNameMap = new Dictionary<string, PackageAsset>(PathComparer);
var allGood = true;
// This will record all of the DLL files in a directory. The name of the DLL and the checksum of the contents will
IEnumerable<string> enumerateAssets(string directory, SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
var files = Directory.EnumerateFiles(directory, "*.dll", searchOption);
files = files.Concat(Directory.EnumerateFiles(directory, "*.targets", searchOption));
return files;
}
// This will record all of the assets files in a directory. The name of the assets and the checksum of the contents will
// be added to the map
void recordDependencies(MD5 md5, string directory)
{
......@@ -148,7 +202,7 @@ void recordDependencies(MD5 md5, string directory)
// are unique and simple to include hence we don't go through the process of verifying them.
IEnumerable<string> enumerateFiles()
{
foreach (var filePath in Directory.EnumerateFiles(directory, "*.dll"))
foreach (var filePath in enumerateAssets(directory))
{
yield return filePath;
}
......@@ -156,7 +210,7 @@ IEnumerable<string> enumerateFiles()
var runtimeDirectory = Path.Combine(directory, "runtimes");
if (Directory.Exists(runtimeDirectory))
{
foreach (var filePath in Directory.EnumerateFiles(Path.Combine(runtimeDirectory), "*.dll", SearchOption.AllDirectories))
foreach (var filePath in enumerateAssets(runtimeDirectory, SearchOption.AllDirectories))
{
yield return filePath;
}
......@@ -167,37 +221,39 @@ IEnumerable<string> enumerateFiles()
string getRelativeName(string filePath) => filePath.Substring(normalizedDirectoryName.Length);
var foundOne = false;
foreach (var dllFilePath in enumerateFiles())
foreach (var assetFilePath in enumerateFiles())
{
foundOne = true;
var dllRelativeName = getRelativeName(dllFilePath);
using (var stream = File.Open(dllFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var stream = File.Open(assetFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var assetRelativeName = getRelativeName(assetFilePath);
var hash = md5.ComputeHash(stream);
var hashString = BitConverter.ToString(hash);
if (dllToChecksumMap.TryGetValue(dllRelativeName, out string existingHashString))
if (relativeNameMap.TryGetValue(assetRelativeName, out PackageAsset existingAsset))
{
// Make sure that all copies of the DLL have the same contents. The DLLs are being merged into
// a single directory in the resulting NuGet. If the contents are different then our merge is
// invalid.
if (existingHashString != hashString)
if (existingAsset.Checksum != hashString)
{
textWriter.WriteLine($"Dll {dllRelativeName} exists at two different versions");
textWriter.WriteLine($"Asset {assetRelativeName} exists at two different versions");
textWriter.WriteLine($"\tHash 1: {hashString}");
textWriter.WriteLine($"\tHash 2: {existingHashString}");
textWriter.WriteLine($"\tHash 2: {existingAsset.Checksum}");
allGood = false;
}
}
else
{
dllToChecksumMap.Add(dllRelativeName, hashString);
var packageAsset = new PackageAsset(assetRelativeName, hashString, isDesktop);
packageAssets.Add(packageAsset);
relativeNameMap[assetRelativeName] = packageAsset;
}
}
}
if (!foundOne)
{
textWriter.WriteLine($"Directory {directory} did not have any dlls");
textWriter.WriteLine($"Directory {directory} did not have any assets");
allGood = false;
}
}
......@@ -210,8 +266,7 @@ IEnumerable<string> enumerateFiles()
}
}
var dllFileNames = dllToChecksumMap.Keys.OrderBy(x => x).ToList();
return (allGood, dllFileNames);
return allGood;
}
private IEnumerable<string> FilterRelativeFileNames(IEnumerable<string> relativeFileNames, params string[] excludeNames)
......@@ -254,7 +309,7 @@ private IEnumerable<string> FilterRelativeFileNames(IEnumerable<string> relative
{
Debug.Assert(string.IsNullOrEmpty(folderRelativePath) || folderRelativePath[0] != '\\');
// Get all of the DLL parts that are in the specified folder. Will exclude items that
// Get all of the assets parts that are in the specified folder. Will exclude items that
// are in any child folder
IEnumerable<string> getPartsInFolder()
{
......@@ -273,14 +328,16 @@ IEnumerable<string> getPartsInFolder()
relativeName = relativeName.Substring(1);
}
if (!relativeName.StartsWith(folderRelativePath, PathComparison) ||
!relativeName.EndsWith(".dll", PathComparison) ||
relativeName.EndsWith(".resources.dll", PathComparison))
if (!relativeName.StartsWith(folderRelativePath, PathComparison))
{
continue;
}
yield return relativeName;
if ((relativeName.EndsWith(".dll", PathComparison) || relativeName.EndsWith(".targets", PathComparison)) &&
!relativeName.EndsWith(".resources.dll", PathComparison))
{
yield return relativeName;
}
}
}
}
......@@ -311,14 +368,14 @@ IEnumerable<string> getPartsInFolder()
}
else
{
textWriter.WriteLine($"\tFound unexpected dll {relativeName}");
textWriter.WriteLine($"\tFound unexpected asset {relativeName}");
allGood = false;
}
}
foreach (var pair in map.Where(x => !x.Value))
{
textWriter.WriteLine($"\tDll {pair.Key} not found");
textWriter.WriteLine($"\tAsset {pair.Key} not found");
allGood = false;
}
......@@ -327,8 +384,16 @@ IEnumerable<string> getPartsInFolder()
private string FindNuGetPackage(string directory, string partialName)
{
var file = Directory.EnumerateFiles(directory, partialName + "*.nupkg").SingleOrDefault();
return file ?? throw new Exception($"Unable to find '{partialName}*.nupkg' in '{directory}'");
var regex = $@"{partialName}.\d.*\.nupkg";
var file = Directory
.EnumerateFiles(directory, "*.nupkg")
.Where(filePath =>
{
var fileName = Path.GetFileName(filePath);
return Regex.IsMatch(fileName, regex);
})
.SingleOrDefault();
return file ?? throw new Exception($"Unable to find unique '{partialName}' in '{directory}'");
}
private string FindVsix(string fileName)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册