Gra*_*ant 24 c# msbuild process exit-code
我正在用C#编写一个checkout,build和deployment应用程序,并且需要知道检测我的调用msbuild.exe是否成功的最佳方法.我试图使用该过程中的错误代码,但我不确定这是否始终准确.
有没有办法(通过下面的代码),我可以判断是否msbuild.exe成功完成?
try
{
Process msbProcess = new Process();
msbProcess.StartInfo.FileName = this.MSBuildPath;
msbProcess.StartInfo.Arguments = msbArguments;
msbProcess.Start();
msbProcess.WaitForExit();
if (msbProcess.ExitCode != 0)
{
//
}
else
{
//
}
msbProcess.Close();
}
catch (Exception ex)
{
//
}
Run Code Online (Sandbox Code Playgroud)
Jim*_*hel 31
据我所知,MSBuild在遇到错误时返回退出代码> 0.如果它没有遇到任何错误,它将返回退出代码0.我从未见过它以代码<0退出.
我在批处理文件中使用它:
msbuild <args>
if errorlevel 1 goto errorDone
Run Code Online (Sandbox Code Playgroud)
在用这种方式四年的时间里,我从来没有理由怀疑这种方法的正确性.
MSDN论坛上的几个问题问同样的问题.例如:http://social.msdn.microsoft.com/forums/en-US/msbuild/thread/a4ae6b2b-9b1f-4e59-86b4-370f44d73a85.标准响应实际上是"如果errorlevel为0,那么就没有错误."
对不起,如果我参加聚会有点太晚了……但是在问题发布近 7 年后,我想看到一个完整的答案。我使用下面的代码做了一些测试,以下是结论:
分析
msbuild.exe返回1时,会发生的至少一个生成错误,并返回0时构建成功完成。目前,该程序没有考虑警告,这意味着带有警告的成功构建msbuild.exe仍然会返回0。
其他错误,例如:尝试构建不存在的项目,或提供不正确的参数(如/myInvalidArgument),也会导致msbuild.exereturn 1。
源代码
以下 C# 代码是通过msbuild.exe从命令行触发来构建您最喜欢的项目的完整实现。在编译项目之前不要忘记设置任何必要的环境设置。
您的BuildControl类:
using System;
namespace Example
{
public sealed class BuildControl
{
// ...
public bool BuildStuff()
{
MsBuilder builder = new MsBuilder(@"C:\...\project.csproj", "Release", "x86")
{
Target = "Rebuild", // for rebuilding instead of just building
};
bool success = builder.Build(out string buildOutput);
Console.WriteLine(buildOutput);
return success;
}
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
MsBuilder类:通过从命令行调用 MsBuild.exe 来构建内容:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Example
{
public sealed class MsBuilder
{
public string ProjectPath { get; }
public string LogPath { get; set; }
public string Configuration { get; }
public string Platform { get; }
public int MaxCpuCount { get; set; } = 1;
public string Target { get; set; } = "Build";
public string MsBuildPath { get; set; } =
@"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MsBuild.exe";
public string BuildOutput { get; private set; }
public MsBuilder(string projectPath, string configuration, string platform)
{
ProjectPath = !string.IsNullOrWhiteSpace(projectPath) ? projectPath : throw new ArgumentNullException(nameof(projectPath));
if (!File.Exists(ProjectPath)) throw new FileNotFoundException(projectPath);
Configuration = !string.IsNullOrWhiteSpace(configuration) ? configuration : throw new ArgumentNullException(nameof(configuration));
Platform = !string.IsNullOrWhiteSpace(platform) ? platform : throw new ArgumentNullException(nameof(platform));
LogPath = Path.Combine(Path.GetDirectoryName(ProjectPath), $"{Path.GetFileName(ProjectPath)}.{Configuration}-{Platform}.msbuild.log");
}
public bool Build(out string buildOutput)
{
List<string> arguments = new List<string>()
{
$"/nologo",
$"\"{ProjectPath}\"",
$"/p:Configuration={Configuration}",
$"/p:Platform={Platform}",
$"/t:{Target}",
$"/maxcpucount:{(MaxCpuCount > 0 ? MaxCpuCount : 1)}",
$"/fileLoggerParameters:LogFile=\"{LogPath}\";Append;Verbosity=diagnostic;Encoding=UTF-8",
};
using (CommandLineProcess cmd = new CommandLineProcess(MsBuildPath, string.Join(" ", arguments)))
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"Build started: Project: '{ProjectPath}', Configuration: {Configuration}, Platform: {Platform}");
// Call MsBuild:
int exitCode = cmd.Run(out string processOutput, out string processError);
// Check result:
sb.AppendLine(processOutput);
if (exitCode == 0)
{
sb.AppendLine("Build completed successfully!");
buildOutput = sb.ToString();
return true;
}
else
{
if (!string.IsNullOrWhiteSpace(processError))
sb.AppendLine($"MSBUILD PROCESS ERROR: {processError}");
sb.AppendLine("Build failed!");
buildOutput = sb.ToString();
return false;
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
CommandLineProcess类 - 启动命令行进程并等待它完成。捕获所有标准输出/错误,并且不会为该进程启动单独的窗口:
using System;
using System.Diagnostics;
using System.IO;
namespace Example
{
public sealed class CommandLineProcess : IDisposable
{
public string Path { get; }
public string Arguments { get; }
public bool IsRunning { get; private set; }
public int? ExitCode { get; private set; }
private Process Process;
private readonly object Locker = new object();
public CommandLineProcess(string path, string arguments)
{
Path = path ?? throw new ArgumentNullException(nameof(path));
if (!File.Exists(path)) throw new ArgumentException($"Executable not found: {path}");
Arguments = arguments;
}
public int Run(out string output, out string err)
{
lock (Locker)
{
if (IsRunning) throw new Exception("The process is already running");
Process = new Process()
{
EnableRaisingEvents = true,
StartInfo = new ProcessStartInfo()
{
FileName = Path,
Arguments = Arguments,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
},
};
if (!Process.Start()) throw new Exception("Process could not be started");
output = Process.StandardOutput.ReadToEnd();
err = Process.StandardError.ReadToEnd();
Process.WaitForExit();
try { Process.Refresh(); } catch { }
return (ExitCode = Process.ExitCode).Value;
}
}
public void Kill()
{
lock (Locker)
{
try { Process?.Kill(); }
catch { }
IsRunning = false;
Process = null;
}
}
public void Dispose()
{
try { Process?.Dispose(); }
catch { }
}
}
}
Run Code Online (Sandbox Code Playgroud)
PS:我使用的是 Visual Studio 2017/.NET 4.7.2
| 归档时间: |
|
| 查看次数: |
17294 次 |
| 最近记录: |