private static void LogToolsetToConsole(IConsole console, MsBuildToolset toolset) { if (console == null) { return; } if (console.Verbosity == Verbosity.Detailed) { console.WriteLine( LocalizedResourceManager.GetString( nameof(NuGetResources.MSBuildAutoDetection_Verbose)), toolset.Version, toolset.Path); } else { console.WriteLine( LocalizedResourceManager.GetString( nameof(NuGetResources.MSBuildAutoDetection)), toolset.Version, toolset.Path); } }
/// <summary> /// Returns the msbuild directory. If <paramref name="userVersion"/> is "latest", then the directory containing /// the highest installed msbuild version is returned. If <paramref name="userVersion"/> is null, /// the Env variable has priority over the highest installed version. Otherwise, the directory containing msbuild /// whose version matches <paramref name="userVersion"/> is returned. If no match is found, /// an exception will be thrown. Note that we use Microsoft.Build types as /// </summary> /// <param name="userVersion">version string as passed by user (so may be empty)</param> /// <param name="console">The console used to output messages.</param> /// <returns>The msbuild directory.</returns> public static MsBuildToolset GetMsBuildToolset(string userVersion, IConsole console) { var currentDirectoryCache = Directory.GetCurrentDirectory(); var installedToolsets = new List <MsBuildToolset>(); MsBuildToolset toolset = null; try { // If Mono, test well known paths and bail if found toolset = GetMsBuildFromMonoPaths(userVersion); if (toolset != null) { return(toolset); } // If the userVersion is not specified, favor the value in the $Path Env variable if (string.IsNullOrEmpty(userVersion)) { var msbuildExe = GetMSBuild(EnvironmentVariableWrapper.Instance); if (msbuildExe != null) { var msBuildDirectory = Path.GetDirectoryName(msbuildExe); var msbuildVersion = FileVersionInfo.GetVersionInfo(msbuildExe)?.FileVersion; return(toolset = new MsBuildToolset(msbuildVersion, msBuildDirectory)); } } using (var projectCollection = LoadProjectCollection()) { var installed = ((dynamic)projectCollection)?.Toolsets; if (installed != null) { foreach (var item in installed) { installedToolsets.Add(new MsBuildToolset(version: item.ToolsVersion, path: item.ToolsPath)); } installedToolsets = installedToolsets.ToList(); } } // In a non-Mono environment, we have the potential for SxS installs of MSBuild 15.1+. Let's add these here. if (!RuntimeEnvironmentHelper.IsMono) { var installedSxsToolsets = GetInstalledSxsToolsets(); if (installedToolsets == null) { installedToolsets = installedSxsToolsets; } else if (installedSxsToolsets != null) { installedToolsets.AddRange(installedSxsToolsets); } } if (!installedToolsets.Any()) { throw new CommandException( LocalizedResourceManager.GetString( nameof(NuGetResources.Error_CannotFindMsbuild))); } toolset = GetMsBuildDirectoryInternal( userVersion, console, installedToolsets.OrderByDescending(t => t), (IEnvironmentVariableReader reader) => GetMSBuild(reader)); Directory.SetCurrentDirectory(currentDirectoryCache); return(toolset); } finally { LogToolsetToConsole(console, toolset); } }
/// <summary> /// Returns the closure of project references for projects specified in <paramref name="projectPaths"/>. /// </summary> public static async Task <DependencyGraphSpec> GetProjectReferencesAsync( MsBuildToolset msbuildToolset, string[] projectPaths, int timeOut, IConsole console, bool recursive, string solutionDirectory, string solutionName, string restoreConfigFile, string[] sources, string packagesDirectory, RestoreLockProperties restoreLockProperties) { var msbuildPath = GetMsbuild(msbuildToolset.Path); if (!File.Exists(msbuildPath)) { throw new CommandException( string.Format( CultureInfo.CurrentCulture, LocalizedResourceManager.GetString(nameof(NuGetResources.MsBuildDoesNotExistAtPath)), msbuildPath)); } var nugetExePath = Assembly.GetEntryAssembly().Location; // Check for the non-ILMerged path var buildTasksPath = Path.Combine(Path.GetDirectoryName(nugetExePath), "NuGet.Build.Tasks.dll"); if (File.Exists(buildTasksPath)) { nugetExePath = buildTasksPath; } using (var inputTargetPath = new TempFile(".nugetinputs.targets")) using (var entryPointTargetPath = new TempFile(".nugetrestore.targets")) using (var resultsPath = new TempFile(".output.dg")) { // Read NuGet.targets from nuget.exe and write it to disk for msbuild.exe ExtractResource(NuGetTargets, entryPointTargetPath); // Build a .targets file of all restore inputs, this is needed to avoid going over the limit on command line arguments. var properties = new Dictionary <string, string>() { { "RestoreUseCustomAfterTargets", "true" }, { "RestoreGraphOutputPath", resultsPath }, { "RestoreRecursive", recursive.ToString().ToLowerInvariant() }, { "RestoreProjectFilterMode", "exclusionlist" } }; var inputTargetXML = GetRestoreInputFile(entryPointTargetPath, properties, projectPaths); inputTargetXML.Save(inputTargetPath); // Create msbuild parameters and include global properties that cannot be set in the input targets path var arguments = GetMSBuildArguments(entryPointTargetPath, inputTargetPath, nugetExePath, solutionDirectory, solutionName, restoreConfigFile, sources, packagesDirectory, msbuildToolset, restoreLockProperties, EnvironmentVariableWrapper.Instance); var processStartInfo = new ProcessStartInfo { UseShellExecute = false, FileName = msbuildPath, Arguments = arguments, RedirectStandardError = true, RedirectStandardOutput = true }; console.LogDebug($"{processStartInfo.FileName} {processStartInfo.Arguments}"); using (var process = Process.Start(processStartInfo)) { var errors = new StringBuilder(); var output = new StringBuilder(); var excluded = new string[] { "msb4011", entryPointTargetPath }; // Read console output var errorTask = ConsumeStreamReaderAsync(process.StandardError, errors, filter: null); var outputTask = ConsumeStreamReaderAsync(process.StandardOutput, output, filter: (line) => IsIgnoredOutput(line, excluded)); // Run msbuild var finished = process.WaitForExit(timeOut); // Handle timeouts if (!finished) { try { process.Kill(); } catch (Exception ex) { throw new CommandException( LocalizedResourceManager.GetString(nameof(NuGetResources.Error_CannotKillMsBuild)) + " : " + ex.Message, ex); } } // Read all console output from msbuild. await Task.WhenAll(outputTask, errorTask); // By default log msbuild output so that it is only // displayed under -Verbosity detailed var logLevel = LogLevel.Verbose; if (process.ExitCode != 0 || !finished) { // If a problem occurred log all msbuild output as an error // so that the user can see it. // By default this runs with /v:q which means that only // errors and warnings will be in the output. logLevel = LogLevel.Error; } // MSBuild writes errors to the output stream, parsing the console output to find // the errors would be error prone so here we log all output combined with any // errors on the error stream (haven't seen the error stream used to date) // to give the user the complete info. await console.LogAsync(logLevel, output.ToString() + errors.ToString()); if (!finished) { // MSBuild timed out throw new CommandException( LocalizedResourceManager.GetString(nameof(NuGetResources.Error_MsBuildTimedOut))); } await outputTask; if (process.ExitCode != 0) { // Do not continue if msbuild failed. throw new ExitCodeException(1); } } DependencyGraphSpec spec = null; if (File.Exists(resultsPath) && new FileInfo(resultsPath).Length != 0) { spec = DependencyGraphSpec.Load(resultsPath); File.Delete(resultsPath); } else { spec = new DependencyGraphSpec(); } return(spec); } }
public static string GetMSBuildArguments( string entryPointTargetPath, string inputTargetPath, string nugetExePath, string solutionDirectory, string solutionName, string restoreConfigFile, string[] sources, string packagesDirectory, MsBuildToolset toolset, RestoreLockProperties restoreLockProperties, IEnvironmentVariableReader reader) { // args for MSBuild.exe var args = new List <string>() { EscapeQuoted(inputTargetPath), "/t:GenerateRestoreGraphFile", "/nologo", "/nr:false" }; // Set the msbuild verbosity level if specified var msbuildVerbosity = reader.GetEnvironmentVariable("NUGET_RESTORE_MSBUILD_VERBOSITY"); if (string.IsNullOrEmpty(msbuildVerbosity)) { args.Add("/v:q"); } else { args.Add($"/v:{msbuildVerbosity} "); } // Override the target under ImportsAfter with the current NuGet.targets version. AddProperty(args, "NuGetRestoreTargets", entryPointTargetPath); AddProperty(args, "RestoreUseCustomAfterTargets", bool.TrueString); // Set path to nuget.exe or the build task AddProperty(args, "RestoreTaskAssemblyFile", nugetExePath); // Settings AddRestoreSources(args, sources); AddPropertyIfHasValue(args, "RestoreSolutionDirectory", solutionDirectory); AddPropertyIfHasValue(args, "RestoreConfigFile", restoreConfigFile); AddPropertyIfHasValue(args, "RestorePackagesPath", packagesDirectory); AddPropertyIfHasValue(args, "SolutionDir", solutionDirectory); AddPropertyIfHasValue(args, "SolutionName", solutionName); // If the MSBuild version used does not support SkipNonextentTargets and BuildInParallel // use the performance optimization // When BuildInParallel is used with ContinueOnError it does not continue in some scenarios if (toolset.ParsedVersion.CompareTo(new Version(15, 5)) < 0) { AddProperty(args, "RestoreBuildInParallel", bool.FalseString); AddProperty(args, "RestoreUseSkipNonexistentTargets", bool.FalseString); } // Add additional args to msbuild if needed var msbuildAdditionalArgs = reader.GetEnvironmentVariable("NUGET_RESTORE_MSBUILD_ARGS"); if (!string.IsNullOrEmpty(msbuildAdditionalArgs)) { args.Add(msbuildAdditionalArgs); } AddPropertyIfHasValue(args, "RestorePackagesWithLockFile", restoreLockProperties.RestorePackagesWithLockFile); AddPropertyIfHasValue(args, "NuGetLockFilePath", restoreLockProperties.NuGetLockFilePath); if (restoreLockProperties.RestoreLockedMode) { AddProperty(args, "RestoreLockedMode", bool.TrueString); } return(string.Join(" ", args)); }