0 people like it.
Like the snippet!
Run MsBuild 2015
runs msbuild using 2015 msbuild and fails if there is an error. All errors reported came across on the output stream instead of the error stream.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
|
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<string>()
let errors = System.Collections.Generic.List<string>()
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
|
namespace System
namespace System.Diagnostics
namespace System.IO
val delimit : s:string -> items:seq<string> -> string
Full name: Script.delimit
val s : string
val items : seq<string>
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = String
Full name: Microsoft.FSharp.Core.string
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
Multiple items
type String =
new : value:char -> string + 7 overloads
member Chars : int -> char
member Clone : unit -> obj
member CompareTo : value:obj -> int + 1 overload
member Contains : value:string -> bool
member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
member EndsWith : value:string -> bool + 2 overloads
member Equals : obj:obj -> bool + 2 overloads
member GetEnumerator : unit -> CharEnumerator
member GetHashCode : unit -> int
...
Full name: System.String
--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
String.Join(separator: string, values: Collections.Generic.IEnumerable<string>) : string
String.Join<'T>(separator: string, values: Collections.Generic.IEnumerable<'T>) : string
String.Join(separator: string, [<ParamArray>] values: obj []) : string
String.Join(separator: string, [<ParamArray>] value: string []) : string
String.Join(separator: string, value: string [], startIndex: int, count: int) : string
val runProc : filename:string -> args:string -> startDir:string option -> seq<string> * seq<string>
Full name: Script.runProc
val filename : string
val args : string
val startDir : string option
val timer : Stopwatch
Multiple items
type Stopwatch =
new : unit -> Stopwatch
member Elapsed : TimeSpan
member ElapsedMilliseconds : int64
member ElapsedTicks : int64
member IsRunning : bool
member Reset : unit -> unit
member Restart : unit -> unit
member Start : unit -> unit
member Stop : unit -> unit
static val Frequency : int64
...
Full name: System.Diagnostics.Stopwatch
--------------------
Stopwatch() : unit
Stopwatch.StartNew() : Stopwatch
val procStartInfo : ProcessStartInfo
Multiple items
type ProcessStartInfo =
new : unit -> ProcessStartInfo + 2 overloads
member Arguments : string with get, set
member CreateNoWindow : bool with get, set
member Domain : string with get, set
member EnvironmentVariables : StringDictionary
member ErrorDialog : bool with get, set
member ErrorDialogParentHandle : nativeint with get, set
member FileName : string with get, set
member LoadUserProfile : bool with get, set
member Password : SecureString with get, set
...
Full name: System.Diagnostics.ProcessStartInfo
--------------------
ProcessStartInfo() : unit
ProcessStartInfo(fileName: string) : unit
ProcessStartInfo(fileName: string, arguments: string) : unit
union case Option.Some: Value: 'T -> Option<'T>
val d : string
property ProcessStartInfo.WorkingDirectory: string
val outputs : Collections.Generic.List<string>
namespace System.Collections
namespace System.Collections.Generic
Multiple items
type List<'T> =
new : unit -> List<'T> + 2 overloads
member Add : item:'T -> unit
member AddRange : collection:IEnumerable<'T> -> unit
member AsReadOnly : unit -> ReadOnlyCollection<'T>
member BinarySearch : item:'T -> int + 2 overloads
member Capacity : int with get, set
member Clear : unit -> unit
member Contains : item:'T -> bool
member ConvertAll<'TOutput> : converter:Converter<'T, 'TOutput> -> List<'TOutput>
member CopyTo : array:'T[] -> unit + 2 overloads
...
nested type Enumerator
Full name: System.Collections.Generic.List<_>
--------------------
Collections.Generic.List() : unit
Collections.Generic.List(capacity: int) : unit
Collections.Generic.List(collection: Collections.Generic.IEnumerable<'T>) : unit
val errors : Collections.Generic.List<string>
val outputHandler : ((string -> 'a) -> obj -> DataReceivedEventArgs -> 'a)
val f : (string -> 'a)
type obj = Object
Full name: Microsoft.FSharp.Core.obj
val args : DataReceivedEventArgs
type DataReceivedEventArgs =
inherit EventArgs
member Data : string
Full name: System.Diagnostics.DataReceivedEventArgs
property DataReceivedEventArgs.Data: string
val p : Process
Multiple items
type Process =
inherit Component
new : unit -> Process
member BasePriority : int
member BeginErrorReadLine : unit -> unit
member BeginOutputReadLine : unit -> unit
member CancelErrorRead : unit -> unit
member CancelOutputRead : unit -> unit
member Close : unit -> unit
member CloseMainWindow : unit -> bool
member EnableRaisingEvents : bool with get, set
member ExitCode : int
...
Full name: System.Diagnostics.Process
--------------------
Process() : unit
event Process.OutputDataReceived: IEvent<DataReceivedEventHandler,DataReceivedEventArgs>
abstract member IDelegateEvent.AddHandler : handler:'Delegate -> unit
type DataReceivedEventHandler =
delegate of obj * DataReceivedEventArgs -> unit
Full name: System.Diagnostics.DataReceivedEventHandler
Collections.Generic.List.Add(item: string) : unit
event Process.ErrorDataReceived: IEvent<DataReceivedEventHandler,DataReceivedEventArgs>
val started : bool
Process.Start() : bool
val ex : exn
property Exception.Data: Collections.IDictionary
Collections.IDictionary.Add(key: obj, value: obj) : unit
val reraise : unit -> 'T
Full name: Microsoft.FSharp.Core.Operators.reraise
val not : value:bool -> bool
Full name: Microsoft.FSharp.Core.Operators.not
val failwithf : format:Printf.StringFormat<'T,'Result> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.failwithf
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
property Process.ProcessName: string
property Process.Id: int
Process.BeginOutputReadLine() : unit
Process.BeginErrorReadLine() : unit
Process.WaitForExit() : unit
Process.WaitForExit(milliseconds: int) : bool
Stopwatch.Stop() : unit
property Stopwatch.ElapsedMilliseconds: int64
val cleanOut : (seq<string> -> seq<string>)
val l : seq<string>
module Seq
from Microsoft.FSharp.Collections
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.filter
val o : string
String.IsNullOrEmpty(value: string) : bool
val msbuild : targetProject:string -> buildArgs:string list -> seq<string> * seq<string>
Full name: Script.msbuild
val targetProject : string
val buildArgs : string list
val targetFolder : string
type Path =
static val DirectorySeparatorChar : char
static val AltDirectorySeparatorChar : char
static val VolumeSeparatorChar : char
static val InvalidPathChars : char[]
static val PathSeparator : char
static member ChangeExtension : path:string * extension:string -> string
static member Combine : [<ParamArray>] paths:string[] -> string + 3 overloads
static member GetDirectoryName : path:string -> string
static member GetExtension : path:string -> string
static member GetFileName : path:string -> string
...
Full name: System.IO.Path
Path.GetDirectoryName(path: string) : string
val msbuildPath : string
val errorCount : ('a -> 'a -> Text.RegularExpressions.Match option) (requires 'a :> seq<string>)
val outputs : #seq<string>
val errors : #seq<string>
val regex : Text.RegularExpressions.Regex
namespace System.Text
namespace System.Text.RegularExpressions
Multiple items
type Regex =
new : pattern:string -> Regex + 1 overload
member GetGroupNames : unit -> string[]
member GetGroupNumbers : unit -> int[]
member GroupNameFromNumber : i:int -> string
member GroupNumberFromName : name:string -> int
member IsMatch : input:string -> bool + 1 overload
member Match : input:string -> Match + 2 overloads
member Matches : input:string -> MatchCollection + 1 overload
member Options : RegexOptions
member Replace : input:string * replacement:string -> string + 5 overloads
...
Full name: System.Text.RegularExpressions.Regex
--------------------
Text.RegularExpressions.Regex(pattern: string) : unit
Text.RegularExpressions.Regex(pattern: string, options: Text.RegularExpressions.RegexOptions) : unit
val concat : sources:seq<#seq<'T>> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.concat
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>
Full name: Microsoft.FSharp.Collections.Seq.map
Text.RegularExpressions.Regex.Match(input: string) : Text.RegularExpressions.Match
Text.RegularExpressions.Regex.Match(input: string, startat: int) : Text.RegularExpressions.Match
Text.RegularExpressions.Regex.Match(input: string, beginning: int, length: int) : Text.RegularExpressions.Match
val tryFind : predicate:('T -> bool) -> source:seq<'T> -> 'T option
Full name: Microsoft.FSharp.Collections.Seq.tryFind
val m : Text.RegularExpressions.Match
property Text.RegularExpressions.Group.Success: bool
val output : seq<string>
val errors : seq<string>
val errorMatch : Text.RegularExpressions.Match
type RegexOptions =
| None = 0
| IgnoreCase = 1
| Multiline = 2
| ExplicitCapture = 4
| Compiled = 8
| Singleline = 16
| IgnorePatternWhitespace = 32
| RightToLeft = 64
| ECMAScript = 256
| CultureInvariant = 512
Full name: System.Text.RegularExpressions.RegexOptions
field Text.RegularExpressions.RegexOptions.IgnoreCase = 1
Text.RegularExpressions.Regex.IsMatch(input: string) : bool
Text.RegularExpressions.Regex.IsMatch(input: string, startat: int) : bool
Multiple items
module List
from Microsoft.FSharp.Collections
--------------------
type List<'T> =
| ( [] )
| ( :: ) of Head: 'T * Tail: 'T list
interface IEnumerable
interface IEnumerable<'T>
member Head : 'T
member IsEmpty : bool
member Item : index:int -> 'T with get
member Length : int
member Tail : 'T list
static member Cons : head:'T * tail:'T list -> 'T list
static member Empty : 'T list
Full name: Microsoft.FSharp.Collections.List<_>
val ofSeq : source:seq<'T> -> 'T list
Full name: Microsoft.FSharp.Collections.List.ofSeq
val errorText : string
val text : string
property Text.RegularExpressions.Match.Groups: Text.RegularExpressions.GroupCollection
String.IsNullOrWhiteSpace(value: string) : bool
union case Option.None: Option<'T>
val exists : predicate:('T -> bool) -> source:seq<'T> -> bool
Full name: Microsoft.FSharp.Collections.Seq.exists
val c : string
More information