/// <summary> /// Execute the dotnet store command on the provided package manifest /// </summary> /// <param name="defaults"></param> /// <param name="projectLocation"></param> /// <param name="outputLocation"></param> /// <param name="targetFramework"></param> /// <param name="packageManifest"></param> /// <param name="enableOptimization"></param> /// <returns></returns> public StoreResult Store(string projectLocation, string outputLocation, string targetFramework, string packageManifest, bool enableOptimization) { if (outputLocation == null) { throw new ArgumentNullException(nameof(outputLocation)); } if (Directory.Exists(outputLocation)) { try { Directory.Delete(outputLocation, true); Console.WriteLine("Deleted previous publish folder"); } catch (Exception e) { Console.WriteLine($"Warning unable to delete previous publish folder: {e.Message}"); } } var dotnetCLI = FindExecutableInPath("dotnet.exe"); if (dotnetCLI == null) { dotnetCLI = FindExecutableInPath("dotnet"); } if (string.IsNullOrEmpty(dotnetCLI)) { throw new Exception("Failed to locate dotnet CLI executable. Make sure the dotnet CLI is installed in the environment PATH."); } var fullProjectLocation = this._workingDirectory; if (!string.IsNullOrEmpty(projectLocation)) { fullProjectLocation = ProjectUtilities.DetermineProjectLocation(this._workingDirectory, projectLocation); } var fullPackageManifest = Path.Combine(fullProjectLocation, packageManifest); Console.WriteLine($"... invoking 'dotnet store' for manifest {fullPackageManifest} into output directory {outputLocation}"); StringBuilder arguments = new StringBuilder("store"); if (!string.IsNullOrEmpty(outputLocation)) { arguments.Append($" --output \"{outputLocation}\""); } if (!string.IsNullOrEmpty(targetFramework)) { arguments.Append($" --framework \"{targetFramework}\""); } arguments.Append($" --manifest \"{fullPackageManifest}\""); arguments.Append($" --runtime {Common.Constants.RUNTIME_HIERARCHY_STARTING_POINT}"); if (!enableOptimization) { arguments.Append(" --skip-optimization"); } var psi = new ProcessStartInfo { FileName = dotnetCLI, Arguments = arguments.ToString(), WorkingDirectory = this._workingDirectory, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; var handler = (DataReceivedEventHandler)((o, e) => { if (string.IsNullOrEmpty(e.Data)) { return; } // Skip outputting this warning message as it adds a lot of noise to the output and is not actionable. // Full warning message being skipped: message NETSDK1062: // Unable to use package assets cache due to I/O error. This can occur when the same project is built // more than once in parallel. Performance may be degraded, but the build result will not be impacted. if (e.Data.Contains("message NETSDK1062")) { return; } Console.WriteLine("... store: " + e.Data); }); int exitCode; using (var proc = new Process()) { proc.StartInfo = psi; proc.Start(); proc.ErrorDataReceived += handler; proc.OutputDataReceived += handler; proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); proc.EnableRaisingEvents = true; proc.WaitForExit(); exitCode = proc.ExitCode; } return(new StoreResult() { exitCode = exitCode, filePath = outputLocation }); }
/// <summary> /// Executes the dotnet publish command for the provided project /// </summary> /// <param name="defaults"></param> /// <param name="projectLocation"></param> /// <param name="outputLocation"></param> /// <param name="targetFramework"></param> /// <param name="configuration"></param> /// <param name="msbuildParameters"></param> /// <param name="deploymentTargetPackageStoreManifestContent"></param> public int Publish(string projectLocation, string outputLocation, string targetFramework, string configuration, string msbuildParameters, IList <string> publishManifests) { if (outputLocation == null) { throw new ArgumentNullException(nameof(outputLocation)); } if (Directory.Exists(outputLocation)) { try { Directory.Delete(outputLocation, true); Console.WriteLine("Deleted previous publish folder"); } catch (Exception e) { Console.WriteLine($"Warning unable to delete previous publish folder: {e.Message}"); } } Console.WriteLine($"... invoking 'dotnet publish', working folder '{outputLocation}'"); var dotnetCLI = FindExecutableInPath("dotnet.exe"); if (dotnetCLI == null) { dotnetCLI = FindExecutableInPath("dotnet"); } if (string.IsNullOrEmpty(dotnetCLI)) { throw new Exception("Failed to locate dotnet CLI executable. Make sure the dotnet CLI is installed in the environment PATH."); } var fullProjectLocation = this._workingDirectory; if (!string.IsNullOrEmpty(projectLocation)) { fullProjectLocation = ProjectUtilities.DetermineProjectLocation(this._workingDirectory, projectLocation); } StringBuilder arguments = new StringBuilder("publish"); if (!string.IsNullOrEmpty(projectLocation)) { arguments.Append($" \"{fullProjectLocation}\""); } if (!string.IsNullOrEmpty(outputLocation)) { arguments.Append($" --output \"{outputLocation}\""); } if (!string.IsNullOrEmpty(configuration)) { arguments.Append($" --configuration \"{configuration}\""); } if (!string.IsNullOrEmpty(targetFramework)) { arguments.Append($" --framework \"{targetFramework}\""); } if (!string.IsNullOrEmpty(msbuildParameters)) { arguments.Append($" {msbuildParameters}"); } if (!string.Equals("netcoreapp1.0", targetFramework, StringComparison.OrdinalIgnoreCase)) { arguments.Append(" /p:GenerateRuntimeConfigurationFiles=true"); // If you set the runtime to RUNTIME_HIERARCHY_STARTING_POINT it will trim out the Windows and Mac OS specific dependencies but Razor view precompilation // will not run. So only do this packaging optimization if there are no Razor views. if (Directory.GetFiles(fullProjectLocation, "*.cshtml", SearchOption.AllDirectories).Length == 0) { arguments.Append($" -r {Common.Constants.RUNTIME_HIERARCHY_STARTING_POINT}"); if (msbuildParameters == null || msbuildParameters.IndexOf("--self-contained", StringComparison.InvariantCultureIgnoreCase) == -1) { arguments.Append(" --self-contained false "); } if (string.IsNullOrEmpty(msbuildParameters) || !msbuildParameters.Contains("PreserveCompilationContext")) { Console.WriteLine("... Disabling compilation context to reduce package size. If compilation context is needed pass in the \"/p:PreserveCompilationContext=false\" switch."); arguments.Append(" /p:PreserveCompilationContext=false"); } } // If we have a manifest of packages already deploy in target deployment environment then write it to disk and add the // command line switch if (publishManifests != null && publishManifests.Count > 0) { foreach (var manifest in publishManifests) { arguments.Append($" --manifest \"{manifest}\""); } } } var psi = new ProcessStartInfo { FileName = dotnetCLI, Arguments = arguments.ToString(), WorkingDirectory = this._workingDirectory, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; var handler = (DataReceivedEventHandler)((o, e) => { if (string.IsNullOrEmpty(e.Data)) { return; } Console.WriteLine("... publish: " + e.Data); }); int exitCode; using (var proc = new Process()) { proc.StartInfo = psi; proc.Start(); proc.ErrorDataReceived += handler; proc.OutputDataReceived += handler; proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); proc.EnableRaisingEvents = true; proc.WaitForExit(); exitCode = proc.ExitCode; } if (exitCode == 0) { ProcessAdditionalFiles(outputLocation); var chmodPath = FindExecutableInPath("chmod"); if (!string.IsNullOrEmpty(chmodPath) && File.Exists(chmodPath)) { // as we are not invoking through a shell, which would handle // wildcard expansion for us, we need to invoke per-file var files = Directory.GetFiles(outputLocation, "*", SearchOption.TopDirectoryOnly); foreach (var file in files) { var filename = Path.GetFileName(file); var psiChmod = new ProcessStartInfo { FileName = chmodPath, Arguments = "+rx \"" + filename + "\"", WorkingDirectory = outputLocation, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using (var proc = new Process()) { proc.StartInfo = psiChmod; proc.Start(); proc.ErrorDataReceived += handler; proc.OutputDataReceived += handler; proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); proc.EnableRaisingEvents = true; proc.WaitForExit(); if (proc.ExitCode == 0) { Console.WriteLine($"Changed permissions on published file (chmod +rx {filename})."); } } } } } return(exitCode); }