<commit_before>﻿[<AutoOpen>]
/// Contains tasks which allow to use MSBuild (or xBuild on Linux/Unix) to build .NET project files or solution files.
module Fake.MSBuildHelper

open System
open System.IO
open System.Configuration
open System.Xml.Linq

/// A type to represent MSBuild project files.
type MSBuildProject = XDocument

/// An exception type to signal build errors.
exception BuildException of string*list<string>
  with
    override x.ToString() = x.Data0.ToString() + "\r\n" + (separated "\r\n" x.Data1)

/// Tries to detect the right version of MSBuild.
///   - On Linux/Unix Systems we use xBuild.
///   - On Windows we try to find a "MSBuild" build parameter or read the MSBuild tool location from the AppSettings file.
let msBuildExe =   
    if isUnix then "xbuild"
    else
        let MSBuildPath = 
            (ProgramFilesX86 @@ @"\MSBuild\14.0\Bin") + ";" +
            (ProgramFilesX86 @@ @"\MSBuild\12.0\Bin") + ";" +
            (ProgramFilesX86 @@ @"\MSBuild\12.0\Bin\amd64") + ";" + 
            @"c:\Windows\Microsoft.NET\Framework\v4.0.30319\;" + 
            @"c:\Windows\Microsoft.NET\Framework\v4.0.30128\;" + 
            @"c:\Windows\Microsoft.NET\Framework\v3.5\"

        let ev = environVar "MSBuild"
        if not (isNullOrEmpty ev) then
            if isDirectory ev && Directory.Exists ev then ev @@ "MSBuild.exe" else ev
        else if "true".Equals(ConfigurationManager.AppSettings.["IgnoreMSBuild"], StringComparison.OrdinalIgnoreCase) then 
                String.Empty 
        else findPath "MSBuildPath" MSBuildPath "MSBuild.exe"

/// [omit]
let msbuildNamespace = "http://schemas.microsoft.com/developer/msbuild/2003"

/// [omit]
let xname name = XName.Get(name, msbuildNamespace)

/// [omit]
let loadProject (projectFileName : string) : MSBuildProject = 
    MSBuildProject.Load(projectFileName, LoadOptions.PreserveWhitespace)

// See: http://msdn.microsoft.com/en-us/library/ms228186.aspx
let internal unescapeMSBuildSpecialChars s =
    let replExpr = new Text.RegularExpressions.Regex("%..")
    replExpr.Replace(s, new Text.RegularExpressions.MatchEvaluator(
                            fun _match -> match _match.Value with
                                          | "%24" -> "$" | "%25" -> "%" | "%27" -> "'" | "%40" -> "@"
                                          | "%3B" -> ";" | "%3F" -> "?" | "%2A" -> "*" 
                                          | _ -> _match.Value))

/// [omit]
let internal getReferenceElements elementName projectFileName (doc : XDocument) = 
    let fi = fileInfo projectFileName
    doc.Descendants(xname "Project").Descendants(xname "ItemGroup").Descendants(xname elementName) 
    |> Seq.map (fun e -> 
        let a = e.Attribute(XName.Get "Include")
        let value = a.Value |> unescapeMSBuildSpecialChars |> convertWindowsToCurrentPath 
           
        let fileName =
            if value.StartsWith(".." + directorySeparator) || (not <| value.Contains directorySeparator) then
                fi.Directory.FullName @@ value
            else value
        a, fileName |> FullName)

/// [omit]
let processReferences elementName f projectFileName (doc : XDocument) = 
    let fi = fileInfo projectFileName
    doc
        |> getReferenceElements elementName projectFileName
    |> Seq.iter (fun (a, fileName) -> a.Value <- f fileName)
    doc

/// [omit]
let rec getProjectReferences (projectFileName : string) = 
    if projectFileName.EndsWith ".sln" then Set.empty
    else // exclude .sln-files since the are not XML
         
    let doc = loadProject projectFileName
    let references = getReferenceElements "ProjectReference" projectFileName doc |> Seq.map snd |> Seq.filter File.Exists
    references
      |> Seq.map getProjectReferences
      |> Seq.concat
      |> Seq.append references
      |> Set.ofSeq

/// MSBuild verbosity option
type MSBuildVerbosity = 
    | Quiet
    | Minimal
    | Normal
    | Detailed
    | Diagnostic

/// MSBuild log option
type MSBuildLogParameter = 
    | Append
    | PerformanceSummary
    | Summary
    | NoSummary
    | ErrorsOnly
    | WarningsOnly
    | NoItemAndPropertyList
    | ShowCommandLine
    | ShowTimestamp
    | ShowEventId
    | ForceNoAlign
    | DisableConsoleColor
    | DisableMPLogging
    | EnableMPLogging

/// A type for MSBuild configuration
type MSBuildFileLoggerConfig =
    { Number : int
      Filename : string option
      Verbosity : MSBuildVerbosity option
      Parameters : MSBuildLogParameter list option }

type MSBuildDistributedLoggerConfig = 
    {
        ClassName : string option
        AssemblyPath : string
        Parameters : (string * string) list option }

/// A type for MSBuild task parameters
type MSBuildParams = 
    { Targets : string list
      Properties : (string * string) list
      MaxCpuCount : int option option
      NoLogo : bool
      NodeReuse : bool
      RestorePackagesFlag : bool
      ToolsVersion : string option
      Verbosity : MSBuildVerbosity option
      NoConsoleLogger : bool
      FileLoggers : MSBuildFileLoggerConfig list option
      DistributedLoggers : (MSBuildDistributedLoggerConfig * MSBuildDistributedLoggerConfig option) list option }

/// Defines a default for MSBuild task parameters
let mutable MSBuildDefaults = 
    { Targets = []
      Properties = []
      MaxCpuCount = Some None
      NoLogo = false
      NodeReuse = true
      ToolsVersion = None
      Verbosity = None
      NoConsoleLogger = false
      RestorePackagesFlag = false
      FileLoggers = None 
      DistributedLoggers = None }

/// [omit]
let getAllParameters targets maxcpu noLogo nodeReuse tools verbosity noconsolelogger fileLoggers distributedFileLoggers properties =
    if isUnix then [ targets; tools; verbosity; noconsolelogger ] @ fileLoggers @ distributedFileLoggers @ properties<commit_msg>NodeReuse can cause TeamCity to not be able to start next build<commit_after>﻿[<AutoOpen>]
/// Contains tasks which allow to use MSBuild (or xBuild on Linux/Unix) to build .NET project files or solution files.
module Fake.MSBuildHelper

open System
open System.IO
open System.Configuration
open System.Xml.Linq
open BuildServerHelper

/// A type to represent MSBuild project files.
type MSBuildProject = XDocument

/// An exception type to signal build errors.
exception BuildException of string*list<string>
  with
    override x.ToString() = x.Data0.ToString() + "\r\n" + (separated "\r\n" x.Data1)

/// Tries to detect the right version of MSBuild.
///   - On Linux/Unix Systems we use xBuild.
///   - On Windows we try to find a "MSBuild" build parameter or read the MSBuild tool location from the AppSettings file.
let msBuildExe =   
    if isUnix then "xbuild"
    else
        let MSBuildPath = 
            (ProgramFilesX86 @@ @"\MSBuild\14.0\Bin") + ";" +
            (ProgramFilesX86 @@ @"\MSBuild\12.0\Bin") + ";" +
            (ProgramFilesX86 @@ @"\MSBuild\12.0\Bin\amd64") + ";" + 
            @"c:\Windows\Microsoft.NET\Framework\v4.0.30319\;" + 
            @"c:\Windows\Microsoft.NET\Framework\v4.0.30128\;" + 
            @"c:\Windows\Microsoft.NET\Framework\v3.5\"

        let ev = environVar "MSBuild"
        if not (isNullOrEmpty ev) then
            if isDirectory ev && Directory.Exists ev then ev @@ "MSBuild.exe" else ev
        else if "true".Equals(ConfigurationManager.AppSettings.["IgnoreMSBuild"], StringComparison.OrdinalIgnoreCase) then 
                String.Empty 
        else findPath "MSBuildPath" MSBuildPath "MSBuild.exe"

/// [omit]
let msbuildNamespace = "http://schemas.microsoft.com/developer/msbuild/2003"

/// [omit]
let xname name = XName.Get(name, msbuildNamespace)

/// [omit]
let loadProject (projectFileName : string) : MSBuildProject = 
    MSBuildProject.Load(projectFileName, LoadOptions.PreserveWhitespace)

// See: http://msdn.microsoft.com/en-us/library/ms228186.aspx
let internal unescapeMSBuildSpecialChars s =
    let replExpr = new Text.RegularExpressions.Regex("%..")
    replExpr.Replace(s, new Text.RegularExpressions.MatchEvaluator(
                            fun _match -> match _match.Value with
                                          | "%24" -> "$" | "%25" -> "%" | "%27" -> "'" | "%40" -> "@"
                                          | "%3B" -> ";" | "%3F" -> "?" | "%2A" -> "*" 
                                          | _ -> _match.Value))

/// [omit]
let internal getReferenceElements elementName projectFileName (doc : XDocument) = 
    let fi = fileInfo projectFileName
    doc.Descendants(xname "Project").Descendants(xname "ItemGroup").Descendants(xname elementName) 
    |> Seq.map (fun e -> 
        let a = e.Attribute(XName.Get "Include")
        let value = a.Value |> unescapeMSBuildSpecialChars |> convertWindowsToCurrentPath 
           
        let fileName =
            if value.StartsWith(".." + directorySeparator) || (not <| value.Contains directorySeparator) then
                fi.Directory.FullName @@ value
            else value
        a, fileName |> FullName)

/// [omit]
let processReferences elementName f projectFileName (doc : XDocument) = 
    let fi = fileInfo projectFileName
    doc
        |> getReferenceElements elementName projectFileName
    |> Seq.iter (fun (a, fileName) -> a.Value <- f fileName)
    doc

/// [omit]
let rec getProjectReferences (projectFileName : string) = 
    if projectFileName.EndsWith ".sln" then Set.empty
    else // exclude .sln-files since the are not XML
         
    let doc = loadProject projectFileName
    let references = getReferenceElements "ProjectReference" projectFileName doc |> Seq.map snd |> Seq.filter File.Exists
    references
      |> Seq.map getProjectReferences
      |> Seq.concat
      |> Seq.append references
      |> Set.ofSeq

/// MSBuild verbosity option
type MSBuildVerbosity = 
    | Quiet
    | Minimal
    | Normal
    | Detailed
    | Diagnostic

/// MSBuild log option
type MSBuildLogParameter = 
    | Append
    | PerformanceSummary
    | Summary
    | NoSummary
    | ErrorsOnly
    | WarningsOnly
    | NoItemAndPropertyList
    | ShowCommandLine
    | ShowTimestamp
    | ShowEventId
    | ForceNoAlign
    | DisableConsoleColor
    | DisableMPLogging
    | EnableMPLogging

/// A type for MSBuild configuration
type MSBuildFileLoggerConfig =
    { Number : int
      Filename : string option
      Verbosity : MSBuildVerbosity option
      Parameters : MSBuildLogParameter list option }

type MSBuildDistributedLoggerConfig = 
    {
        ClassName : string option
        AssemblyPath : string
        Parameters : (string * string) list option }

/// A type for MSBuild task parameters
type MSBuildParams = 
    { Targets : string list
      Properties : (string * string) list
      MaxCpuCount : int option option
      NoLogo : bool
      NodeReuse : bool
      RestorePackagesFlag : bool
      ToolsVersion : string option
      Verbosity : MSBuildVerbosity option
      NoConsoleLogger : bool
      FileLoggers : MSBuildFileLoggerConfig list option
      DistributedLoggers : (MSBuildDistributedLoggerConfig * MSBuildDistributedLoggerConfig option) list option }

/// Defines a default for MSBuild task parameters
let mutable MSBuildDefaults = 
    { Targets = []
      Properties = []
      MaxCpuCount = Some None
      NoLogo = false
      NodeReuse = not (buildServer = TeamCity)
      ToolsVersion = None
      Verbosity = None
      NoConsoleLogger = false
      RestorePackagesFlag = false
      FileLoggers = None 
      DistributedLoggers = None }

/// [omit]
let getAllParameters targets maxcpu noLogo nodeReuse tools verbosity noconsolelogger fileLoggers distributedFileLoggers properties =
    if isUnix then [ targets; tools; verbosity; noconsolelogger ] @ fileLoggers @ distributedFileLoggers @ properties
{'fraction_non_alphanumeric': 0.0980492375841213, 'fraction_numerical': 0.009540846750149075, 'mean_word_length': 2.6001226617601962, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3496296', 'n_tokens_mistral': 3429, 'n_tokens_neox': 3256, 'n_words': 914}