open System open System.Diagnostics open System.IO let delimit s (items:string seq) = String.Join(s,items) let runProc filename args startDir = let timer = Stopwatch.StartNew() let procStartInfo = ProcessStartInfo( RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, FileName = filename, Arguments = args ) match startDir with | Some d -> procStartInfo.WorkingDirectory <- d | _ -> () let outputs = System.Collections.Generic.List() let errors = System.Collections.Generic.List() let outputHandler f (_sender:obj) (args:DataReceivedEventArgs) = f args.Data let p = new Process(StartInfo = procStartInfo) p.OutputDataReceived.AddHandler(DataReceivedEventHandler (outputHandler outputs.Add)) p.ErrorDataReceived.AddHandler(DataReceivedEventHandler (outputHandler errors.Add)) let started = try p.Start() with | ex -> ex.Data.Add("filename", filename) reraise() if not started then failwithf "Failed to start process %s" filename printfn "Started %s with pid %i" p.ProcessName p.Id p.BeginOutputReadLine() p.BeginErrorReadLine() p.WaitForExit() timer.Stop() printfn "Finished %s after %A milliseconds" filename timer.ElapsedMilliseconds let cleanOut l = l |> Seq.filter (fun o -> String.IsNullOrEmpty o |> not) cleanOut outputs,cleanOut errors let msbuild targetProject buildArgs = let targetFolder = Path.GetDirectoryName targetProject let msbuildPath = @"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe" let errorCount outputs errors = let regex = System.Text.RegularExpressions.Regex(@"^\s*([1-9][0-9]*)\s+Error\(s\)$|Build FAILED.") [ outputs;errors] |> Seq.concat |> Seq.map regex.Match |> Seq.tryFind(fun m -> m.Success) let args = targetProject::buildArgs |> delimit " " let output,errors = runProc msbuildPath args (Some targetFolder) match errorCount output errors with | Some errorMatch -> //printfn "%A" output //printfn "%A" errors let regex = System.Text.RegularExpressions.Regex("Build error", Text.RegularExpressions.RegexOptions.IgnoreCase) printfn "%A" (output |> Seq.filter regex.IsMatch |> List.ofSeq) let errorText = let text = errorMatch.Groups.[1].Value if String.IsNullOrWhiteSpace(text) then errorMatch.Groups.[0].Value else text failwithf "ErrorsFound : %s" errorText | None -> () if output |> Seq.exists (fun c -> c = "Build FAILED.") then failwithf "Build failed" output,errors