fsharp/tests/scripts/scriptlib.fsx

210 строки
8.0 KiB
Plaintext

// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information.
//
// Scripting utilities
//=========================================================================================
namespace global
open System
open System.IO
open System.Text
open System.Diagnostics
[<AutoOpen>]
module Scripting =
let isNullOrEmpty s = String.IsNullOrEmpty s
let executeProcess fileName arguments =
let processWriteMessage (chan:TextWriter) (message:string) =
if message <> null then
chan.WriteLine(message)
printfn "%s %s" fileName arguments
let info = ProcessStartInfo(Arguments=arguments, UseShellExecute=false,
RedirectStandardOutput=true, RedirectStandardError=true,
CreateNoWindow=true, FileName=fileName)
let p = new Process(StartInfo=info)
p.OutputDataReceived.Add(fun x -> processWriteMessage stdout x.Data)
p.ErrorDataReceived.Add(fun x -> processWriteMessage stderr x.Data)
if p.Start() then
p.BeginOutputReadLine()
p.BeginErrorReadLine()
p.WaitForExit()
p.ExitCode
else
0
#if INTERACTIVE
let argv = FSharp.Compiler.Interactive.Settings.fsi.CommandLineArgs |> Seq.skip 1 |> Seq.toArray
let getCmdLineArgOptional (switchName: string) =
argv |> Array.filter(fun t -> t.StartsWith(switchName)) |> Array.map(fun t -> t.Remove(0, switchName.Length).Trim()) |> Array.tryHead
let getCmdLineArg switchName defaultValue =
match getCmdLineArgOptional switchName with
| Some file -> file
| _ -> defaultValue
let getCmdLineArgReqd switchName =
match getCmdLineArg switchName null with
| null -> failwith (sprintf "The argument %s is required" switchName)
| x -> x
let getCmdLineExtraArgs isSwitch = argv |> Array.skipWhile isSwitch
#endif
let makeDirectory output =
if not (Directory.Exists(output)) then
Directory.CreateDirectory(output) |> ignore
let (++) a b = Path.Combine(a,b)
let getBasename (a:string) = Path.GetFileNameWithoutExtension a
let getFullPath (a:string) = Path.GetFullPath a
let getFilename (a:string) = Path.GetFileName a
let getDirectoryName (a:string) = Path.GetDirectoryName a
let copyFile (source:string) dir =
let dest =
if not (Directory.Exists dir) then Directory.CreateDirectory dir |>ignore
let result = Path.Combine(dir, getFilename source)
result
//printfn "Copy %s --> %s" source dest
File.Copy(source, dest, true)
let deleteDirectory output =
if Directory.Exists output then
Directory.Delete(output, true)
let log format = printfn format
type FilePath = string
type CmdResult =
| Success
| ErrorLevel of string * int
type CmdArguments =
{ RedirectOutput : (string -> unit) option
RedirectError : (string -> unit) option
RedirectInput : (StreamWriter -> unit) option }
module Process =
let processExePath baseDir (exe:string) =
if Path.IsPathRooted(exe) then exe
else
match getDirectoryName exe with
| "" -> exe
| _ -> Path.Combine(baseDir,exe) |> Path.GetFullPath
let exec cmdArgs (workDir: FilePath) envs (path: FilePath) (arguments: string) =
let exePath = path |> processExePath workDir
let processInfo = new ProcessStartInfo(exePath, arguments)
processInfo.EnvironmentVariables.["DOTNET_ROLL_FORWARD"] <- "LatestMajor"
processInfo.EnvironmentVariables.["DOTNET_ROLL_FORWARD_TO_PRERELEASE"] <- "1"
processInfo.CreateNoWindow <- true
processInfo.UseShellExecute <- false
processInfo.WorkingDirectory <- workDir
ignore envs // work out what to do about this
let p = new Process()
p.EnableRaisingEvents <- true
p.StartInfo <- processInfo
let out = StringBuilder()
let err = StringBuilder()
cmdArgs.RedirectOutput|> Option.iter (fun f ->
processInfo.RedirectStandardOutput <- true
p.OutputDataReceived.Add (fun ea ->
if ea.Data <> null then
out.Append(ea.Data + Environment.NewLine) |> ignore
f ea.Data)
)
cmdArgs.RedirectError |> Option.iter (fun f ->
processInfo.RedirectStandardError <- true
p.ErrorDataReceived.Add (fun ea ->
if ea.Data <> null then
err.Append(ea.Data + Environment.NewLine) |> ignore
f ea.Data)
)
cmdArgs.RedirectInput
|> Option.iter (fun _ -> p.StartInfo.RedirectStandardInput <- true)
p.Start() |> ignore
cmdArgs.RedirectOutput |> Option.iter (fun _ -> p.BeginOutputReadLine())
cmdArgs.RedirectError |> Option.iter (fun _ -> p.BeginErrorReadLine())
cmdArgs.RedirectInput |> Option.iter (fun input ->
async {
let inputWriter = p.StandardInput
do! inputWriter.FlushAsync () |> Async.AwaitIAsyncResult |> Async.Ignore
input inputWriter
do! inputWriter.FlushAsync () |> Async.AwaitIAsyncResult |> Async.Ignore
inputWriter.Dispose ()
}
|> Async.Start)
p.WaitForExit()
match p.ExitCode with
| 0 -> Success
| errCode ->
let msg = sprintf "Error running command '%s' with args '%s' in directory '%s'.\n---- stdout below --- \n%s\n---- stderr below --- \n%s " exePath arguments workDir (out.ToString()) (err.ToString())
ErrorLevel (msg, errCode)
type OutPipe (writer: TextWriter) =
member x.Post (msg:string) = lock writer (fun () -> writer.WriteLine(msg))
interface System.IDisposable with
member _.Dispose() = writer.Flush()
let redirectTo (writer: TextWriter) = new OutPipe (writer)
let redirectToLog () = redirectTo System.Console.Out
#if !NETCOREAPP
let defaultPlatform =
match Environment.OSVersion.Platform, Environment.Is64BitOperatingSystem with
| PlatformID.MacOSX, true -> "osx.10.11-x64"
| PlatformID.Unix,true -> "ubuntu.14.04-x64"
| _, true -> "win7-x64"
| _, false -> "win7-x86"
#endif
let executeProcessNoRedirect fileName arguments =
let info = ProcessStartInfo(Arguments=arguments, UseShellExecute=false,
RedirectStandardOutput=true, RedirectStandardError=true,RedirectStandardInput=true,
CreateNoWindow=true, FileName=fileName)
let p = new Process(StartInfo=info)
if p.Start() then
async { try
let buffer = Array.zeroCreate 4096
while not p.StandardOutput.EndOfStream do
let n = p.StandardOutput.Read(buffer, 0, buffer.Length)
if n > 0 then System.Console.Out.Write(buffer, 0, n)
with _ -> () } |> Async.Start
async { try
let buffer = Array.zeroCreate 4096
while not p.StandardError.EndOfStream do
let n = p.StandardError.Read(buffer, 0, buffer.Length)
if n > 0 then System.Console.Error.Write(buffer, 0, n)
with _ -> () } |> Async.Start
async { try
while true do
let c = System.Console.In.ReadLine()
p.StandardInput.WriteLine(c)
with _ -> () } |> Async.Start
p.WaitForExit()
p.ExitCode
else
0