anchor.diff:  | Disk
   
   let hashRegex = Text.RegularExpressions.Regex("(?<script>.+)_(?<hash>[a-zA-Z0-9]+\.dll$)", System.Text.RegularExpressions.RegexOptions.Compiled)
  -/// Run the given FAKE script with fsi.exe at the given working directory. Provides full access to Fsi options and args. Redirect output and error messages.
  -let internal runFAKEScriptWithFsiArgsAndRedirectMessages printDetails (FsiArgs(fsiOptions, scriptPath, scriptArgs)) env onErrMsg onOutMsg useCache cleanCache =
  -
  -    if printDetails then traceFAKE "Running Buildscript: %s" scriptPath
  -
  -    // Add arguments to the Environment
  -    for (k,v) in env do
  -      Environment.SetEnvironmentVariable(k, v, EnvironmentVariableTarget.Process)
  -
  -    // Create an env var that only contains the build script args part from the --fsiargs (or "").
  -    Environment.SetEnvironmentVariable("fsiargs-buildscriptargs", String.Join(" ", scriptArgs))
  -
  -    let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
  -
  -    let options =
  -        [ "fsi.exe"; "--noninteractive" ] @ fsiOptions
  -        |> List.toArray
  -
  -    let sbOut = Text.StringBuilder()
  -    let sbErr = Text.StringBuilder()
  -    let handleMessages() =
  -        let handleMessagesFrom (sb:Text.StringBuilder) onMsg =
  -            let s = sb.ToString()
  -            if not <| String.IsNullOrEmpty s
  -                then onMsg s
  -        handleMessagesFrom sbOut onOutMsg
  -        handleMessagesFrom sbErr onErrMsg
  -    let handleException (ex : Exception) = 
  -        onErrMsg (ex.ToString())
  -
  -    use outStream = new StringWriter(sbOut)
  -    use errStream = new StringWriter(sbErr)
  -    use stdin = new StreamReader(Stream.Null)
  -
  -    let scriptPath =
  -        if Path.IsPathRooted scriptPath then
  -            scriptPath
  -        else
  -            Path.Combine(Directory.GetCurrentDirectory(), scriptPath)
  -        
  +
  +type private CacheInfo =
  +  {
  +    ScriptFileName : string
  +    AssemblyPath : string
  +    AssemblyWarningsPath : string
  +    CacheConfigPath : string
  +    CacheConfig : Lazy<Cache.CacheConfig>
  +    IsValid : bool
  +  }
  +
  +let private getCacheInfoFromScript printDetails fsiOptions scriptPath =
       let allScriptContents = getAllScripts scriptPath
       let scriptHash = lazy (getScriptHash allScriptContents fsiOptions)
       //TODO this is only calculating the hash for the input file, not anything #load-ed
       
  -    let scriptFileName = lazy(Path.GetFileName(scriptPath))
  -    let hashPath = lazy("./.fake/" + scriptFileName.Value + "_" + scriptHash.Value)
  -    let assemblyPath = lazy(hashPath.Value + ".dll")
  -    let cacheConfigPath = lazy(hashPath.Value + "_config.xml")
  -    let cacheConfig = lazy(Cache.read cacheConfigPath.Value)
  -    let cacheValid = lazy (
  +    let scriptFileName = Path.GetFileName(scriptPath)
  +    let hashPath = "./.fake/" + scriptFileName + "_" + scriptHash.Value
  +    let assemblyPath = hashPath + ".dll"
  +    let assemblyWarningsPath = hashPath + "_warnings.txt"
  +    let cacheConfigPath = hashPath + "_config.xml"
  +    let cacheConfig = lazy Cache.read cacheConfigPath
  +    let cacheValid =
           let cacheFilesExist = 
  -            System.IO.File.Exists(assemblyPath.Value) &&
  -            System.IO.File.Exists(cacheConfigPath.Value) 
  +            File.Exists(assemblyPath) &&
  +            File.Exists(cacheConfigPath) &&
  +            File.Exists(assemblyWarningsPath)
           if cacheFilesExist then
               let loadedAssemblies =
                   cacheConfig.Value.Assemblies
  
positive.code:                     if printDetails then trace "Cache doesn't exist"
              else
                  if printDetails then trace "Cache doesn't exist"
          try
              let session = FsiEvaluationSession.Create(fsiConfig, options, stdin, outStream, errStream)
              try
                  session.EvalScript scriptPath
  
                  try
                      if useCache && not cacheValid.Value then
                          let assemBuilder = session.DynamicAssembly :?> System.Reflection.Emit.AssemblyBuilder
                          assemBuilder.Save("FSI-ASSEMBLY.dll")
                          if not <| Directory.Exists cacheDir.FullName then
                              let di = Directory.CreateDirectory cacheDir.FullName 
                              di.Attributes <- FileAttributes.Directory ||| FileAttributes.Hidden
  
                          let destinationFile = FileInfo(assemblyPath.Value)
                          let targetDirectory = destinationFile.Directory
  
                          if (not <| targetDirectory.Exists) then targetDirectory.Create()
                          if (destinationFile.Exists) then destinationFile.Delete()
  
                          File.Move("FSI-ASSEMBLY.dll", assemblyPath.Value)
                      
                          if File.Exists("FSI-ASSEMBLY.pdb") then
                              File.Delete("FSI-ASSEMBLY.pdb")
                          if File.Exists("FSI-ASSEMBLY.dll.mdb") then
                              File.Delete("FSI-ASSEMBLY.dll.mdb")
  
                          let dynamicAssemblies = 
                              System.AppDomain.CurrentDomain.GetAssemblies()
                              |> Seq.filter(fun assem -> assem.IsDynamic)
                              |> Seq.map(fun assem -> assem.GetName().Name)
                              |> Seq.filter(fun assem -> assem <> "FSI-ASSEMBLY")
                              // General Reflection.Emit helper (most likely harmless to ignore)
                              |> Seq.filter(fun assem -> assem <> "Anonymously Hosted DynamicMethods Assembly")
                              // RazorEngine generated
                              |> Seq.filter(fun assem -> assem <> "RazorEngine.Compilation.ImpromptuInterfaceDynamicAssembly")
                              |> Seq.cache
                          if dynamicAssemblies |> Seq.length > 0 then
                              let msg =
                                  sprintf "Dynamic assemblies were generated during evaluation of script (%s).\nCan not save cache." 
                                      (System.String.Join(", ", dynamicAssemblies))
                              trace msg
  
                          else
                              let assemblies = 
                                  System.AppDomain.CurrentDomain.GetAssemblies()
                                  |> Seq.filter(fun assem -> not assem.IsDynamic)
                                  // They are not dynamic, but can't be re-used either.
                                  |> Seq.filter(fun assem -> not <| assem.GetName().Name.StartsWith("CompiledRazorTemplates.Dynamic.RazorEngine_"))
                          
                              let cacheConfig : XDocument = Cache.create assemblies
                              cacheConfig.Save(cacheConfigPath.Value) 
                              if printDetails then trace (System.Environment.NewLine + "Saved cache")
                  with 
                  | ex ->
                      handleException ex
                      reraise()
                  // TODO: Reactivate when FCS don't show output any more 
                  // handleMessages()
                  true
              with
              | _ex ->
                  handleMessages()
                  false
          with
          | exn ->
              traceError "FsiEvaluationSession could not be created."
              traceError <| sbErr.ToString()
              raise exn
  
  /// Run the given buildscript with fsi.exe and allows for extra arguments to the script. Returns output.
  let executeBuildScriptWithArgsAndReturnMessages script (scriptArgs: string[]) useCache cleanCache =
      let messages = ref []
      let appendMessage isError msg =
          messages := { IsError = isError
                        Message = msg
                        Timestamp = DateTimeOffset.UtcNow } :: !messages
  
negative.code:                     cacheDir.GetFiles()
                      |> Seq.filter(fun file -> 
                          let oldScriptName, _ = getScriptAndHash(file.Name)
                          oldScriptName = cacheInfo.ScriptFileName)
  
                  if (oldFiles |> Seq.length) > 0 then
                      if cleanCache then
  