opentelemetry-dotnet-instru.../build/Build.Steps.Windows.cs

323 lines
13 KiB
C#

using DependencyListGenerator;
using Nuke.Common;
using Nuke.Common.IO;
using Nuke.Common.ProjectModel;
using Nuke.Common.Tooling;
using Nuke.Common.Tools.Docker;
using Nuke.Common.Tools.DotNet;
using Nuke.Common.Tools.MSBuild;
using Serilog;
using static Nuke.Common.EnvironmentInfo;
using static Nuke.Common.Tools.Docker.DockerTasks;
using static Nuke.Common.Tools.DotNet.DotNetTasks;
using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
partial class Build
{
Target CompileNativeSrcWindows => _ => _
.Unlisted()
.After(CompileManagedSrc)
.After(GenerateNetFxAssemblyRedirectionSource)
.OnlyWhenStatic(() => IsWin)
.Executes(() =>
{
// If we're building for x64, build for x86 too
var platforms =
Equals(Platform, MSBuildTargetPlatform.x64)
? new[] { MSBuildTargetPlatform.x64, MSBuildTargetPlatform.x86 }
: new[] { MSBuildTargetPlatform.x86 };
foreach (var project in Solution.GetNativeSrcProjects())
{
PerformLegacyRestoreIfNeeded(project);
var (major, minor, patch) = VersionHelper.GetVersionParts();
// Can't use dotnet msbuild, as needs to use the VS version of MSBuild
MSBuild(s => s
.SetTargetPath(project)
.SetConfiguration(BuildConfiguration)
.SetRestore(!NoRestore)
.SetMaxCpuCount(null)
.SetProperty("OTEL_AUTO_VERSION_MAJOR", major)
.SetProperty("OTEL_AUTO_VERSION_MINOR", minor)
.SetProperty("OTEL_AUTO_VERSION_PATCH", patch)
.CombineWith(platforms, (m, platform) => m
.SetTargetPlatform(platform)));
}
});
Target CompileNativeDependenciesForManagedTestsWindows => _ => _
.Unlisted()
.After(CompileManagedSrc)
.After(GenerateNetFxAssemblyRedirectionSource)
.OnlyWhenStatic(() => IsWin)
.Executes(() =>
{
var continuousProfilerNativeDepProject = Solution.GetContinuousProfilerNativeDep();
PerformLegacyRestoreIfNeeded(continuousProfilerNativeDepProject);
// Can't use dotnet msbuild, as needs to use the VS version of MSBuild
MSBuild(s => s
.SetProjectFile(continuousProfilerNativeDepProject)
.SetConfiguration(BuildConfiguration)
.SetRestore(!NoRestore)
.SetTargetPlatform(Platform)
.SetRestore(false));
});
Target CompileNativeTestsWindows => _ => _
.Unlisted()
.After(CompileNativeSrc)
.OnlyWhenStatic(() => IsWin)
.Executes(() =>
{
// If we're building for x64, build for x86 too
var platforms =
Equals(Platform, MSBuildTargetPlatform.x64)
? new[] { MSBuildTargetPlatform.x64, MSBuildTargetPlatform.x86 }
: new[] { MSBuildTargetPlatform.x86 };
var nativeTestProject = Solution.GetNativeTestProject();
PerformLegacyRestoreIfNeeded(nativeTestProject);
// Can't use dotnet msbuild, as needs to use the VS version of MSBuild
MSBuild(s => s
.SetTargetPath(nativeTestProject)
.SetConfiguration(BuildConfiguration)
.SetRestore(!NoRestore)
.SetMaxCpuCount(null)
.CombineWith(platforms, (m, platform) => m
.SetTargetPlatform(platform)));
});
Target PublishNativeProfilerWindows => _ => _
.Unlisted()
.OnlyWhenStatic(() => IsWin)
.After(CompileNativeSrc, PublishManagedProfiler)
.Executes(() =>
{
foreach (var architecture in ArchitecturesForPlatform)
{
var source = NativeProfilerProject.Directory / "bin" / BuildConfiguration / architecture.ToString() /
$"{NativeProfilerProject.Name}.dll";
var dest = TracerHomeDirectory / $"win-{architecture}";
Log.Information($"Copying '{source}' to '{dest}'");
source.CopyToDirectory(dest, ExistsPolicy.FileOverwrite);
}
});
Target RunNativeTestsWindows => _ => _
.Unlisted()
.After(CompileNativeSrcWindows)
.After(CompileNativeTestsWindows)
.After(PublishManagedProfiler)
.OnlyWhenStatic(() => IsWin)
.Executes(() =>
{
var project = Solution.GetProjectByName(Projects.Tests.AutoInstrumentationNativeTests);
var workingDirectory = project.Directory / "bin" / BuildConfiguration.ToString() / Platform.ToString();
var exePath = workingDirectory / $"{project.Name}.exe";
var envVars = new Dictionary<string, string>(){
{ "OTEL_DOTNET_AUTO_LOG_DIRECTORY", ProfilerTestLogs }
};
var testExe = ToolResolver.GetTool(exePath);
testExe($"--gtest_output=xml", workingDirectory: workingDirectory, environmentVariables: envVars);
});
Target PublishIisTestApplications => _ => _
.Unlisted()
.After(CompileManagedTests)
.After(BuildInstallationScripts)
.OnlyWhenStatic(() => IsWin && (Containers == ContainersWindows || Containers == ContainersWindowsOnly))
.Executes(() =>
{
var aspNetProject = Solution.GetProjectByName(Projects.Tests.Applications.AspNet);
BuildDockerImage(aspNetProject, "integrated-nogac", "classic-nogac", "integrated", "classic");
var wcfProject = Solution.GetProjectByName(Projects.Tests.Applications.WcfIis);
BuildDockerImage(wcfProject);
var owinProject = Solution.GetProjectByName(Projects.Tests.Applications.OwinIis);
BuildDockerImage(owinProject);
});
void BuildDockerImage(Project project, params string[] targets)
{
const string moduleName = "OpenTelemetry.DotNet.Auto.psm1";
var sourceModulePath = InstallationScriptsDirectory / moduleName;
var localBinDirectory = project.Directory / "bin";
var localTracerZip = localBinDirectory / "tracer.zip";
try
{
sourceModulePath.CopyToDirectory(localBinDirectory);
TracerHomeDirectory.ZipTo(localTracerZip);
PerformLegacyRestoreIfNeeded(project);
MSBuild(x => x
.SetConfiguration(BuildConfiguration)
.SetTargetPlatform(Platform)
.SetProperty("DeployOnBuild", true)
.SetMaxCpuCount(null)
.SetProperty("PublishProfile",
project.Directory / "Properties" / "PublishProfiles" / $"FolderProfile.{BuildConfiguration}.pubxml")
.SetTargetPath(project));
if (targets.Length > 0)
{
foreach (var target in targets)
{
DockerBuild(x => x
.SetPath(".")
.SetBuildArg($"configuration={BuildConfiguration}")
.EnableRm()
.SetProcessWorkingDirectory(project.Directory)
.SetTag($"{Path.GetFileNameWithoutExtension(project).Replace(".", "-")}-{target}".ToLowerInvariant())
.SetTarget(target)
);
}
}
else
{
DockerBuild(x => x
.SetPath(".")
.SetBuildArg($"configuration={BuildConfiguration}")
.EnableRm()
.SetProcessWorkingDirectory(project.Directory)
.SetTag(Path.GetFileNameWithoutExtension(project).Replace(".", "-").ToLowerInvariant())
);
}
}
finally
{
localTracerZip.DeleteFile();
var localModulePath = localBinDirectory / moduleName;
localModulePath.DeleteFile();
}
}
Target GenerateNetFxTransientDependencies => _ => _
.Unlisted()
.After(Restore)
.OnlyWhenStatic(() => IsWin)
.Executes(() =>
{
// The target project needs to have its NuGet packages restored prior to running the tool.
var targetProject = Solution.GetProjectByName(Projects.AutoInstrumentation);
DotNetRestore(s => s.SetProjectFile(targetProject));
var project = targetProject.GetMSBuildProject();
var packages = Solution.Directory / "src" / "Directory.Packages.props";
const string label = $"Transient dependencies auto-generated by {nameof(GenerateNetFxTransientDependencies)}";
var packagesGroup = project.Xml.ItemGroups.FirstOrDefault(x => x.Label == label);
if (packagesGroup == null)
{
packagesGroup = project.Xml.AddItemGroup();
packagesGroup.Label = label;
packagesGroup.Condition = " '$(TargetFramework)' == 'net462' AND $(_IsPacking) != true ";
}
var packagesProject = ProjectModelTasks.ParseProject(packages);
var versionGroup = packagesProject.Xml.ItemGroups.FirstOrDefault(x => x.Label == label);
if (versionGroup == null)
{
versionGroup = packagesProject.Xml.AddItemGroup();
versionGroup.Label = label;
}
var deps = Generator.EnumerateDependencies(project.FullPath);
foreach (var item in deps)
{
if (!packagesGroup.Items.Any(x => x.Include == item.Name))
{
packagesGroup.AddItem("PackageReference", item.Name);
}
if (!versionGroup.Items.Any(x => x.Include == item.Name))
{
var reference = versionGroup.AddItem("PackageVersion", item.Name);
reference.AddMetadata("Version", item.Version, expressAsAttribute: true);
}
}
project.Save();
packagesProject.Save();
});
Target GenerateNetFxAssemblyRedirectionSource => _ => _
.Unlisted()
.After(PublishManagedProfiler)
.OnlyWhenStatic(() => IsWin)
.Executes(() =>
{
var netFxAssembliesFolder = TracerHomeDirectory / MapToFolderOutput(TargetFramework.NET462);
var generatedSourceFile = SourceDirectory / Projects.AutoInstrumentationNative / "netfx_assembly_redirection.h";
AssemblyRedirectionSourceGenerator.Generate(netFxAssembliesFolder, generatedSourceFile);
});
Target InstallNetFxAssembliesGAC => _ => _
.Unlisted()
.After(BuildTracer)
.After(RunManagedUnitTests)
.OnlyWhenStatic(() => IsWin && (TestTargetFramework == TargetFramework.NET462 || TestTargetFramework == TargetFramework.NOT_SPECIFIED))
.Executes(() => RunNetFxGacOperation("-i"));
/// <remarks>
/// Warning: This target could cause potential harm to your system by removing a required library from GAC.
/// </remarks>
Target UninstallNetFxAssembliesGAC => _ => _
.Description("Removes .NET Framework output libraries from the GAC.")
.After(BuildTracer)
.OnlyWhenStatic(() => IsWin)
.Executes(() => RunNetFxGacOperation("-u"));
private void RunNetFxGacOperation(string operation)
{
// To update the GAC, we need to run the tool as Administrator.
// Throw if not running as a Windows Administrator.
if (!IsWindowsAdministrator())
{
throw new InvalidOperationException("This target must be run on Windows as Administrator.");
}
var netFxAssembliesFolder = TracerHomeDirectory / MapToFolderOutput(TargetFramework.NET462);
var installTool = Solution.GetProjectByName(Projects.Tools.GacInstallTool);
DotNetRun(s => s
.SetProjectFile(installTool)
.SetConfiguration(BuildConfiguration)
.SetApplicationArguments(operation, netFxAssembliesFolder));
static bool IsWindowsAdministrator()
{
if (!IsWin)
{
return false;
}
#pragma warning disable CA1416 // Validate platform compatibility
using var identity = System.Security.Principal.WindowsIdentity.GetCurrent();
var principal = new System.Security.Principal.WindowsPrincipal(identity);
return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
#pragma warning restore CA1416 // Validate platform compatibility
}
}
private void PerformLegacyRestoreIfNeeded(Project project)
{
if (!NoRestore && project.Directory.ContainsFile("packages.config"))
{
RestoreLegacyNuGetPackagesConfig(new[] { project });
}
}
}