diff --git a/src/Terrabuild.Extensions/Cargo.fs b/src/Terrabuild.Extensions/Cargo.fs
index 297c4c3f..d04068bf 100644
--- a/src/Terrabuild.Extensions/Cargo.fs
+++ b/src/Terrabuild.Extensions/Cargo.fs
@@ -45,8 +45,9 @@ type Cargo() =
/// Arguments for command.
static member __dispatch__ (context: ActionContext) (arguments: string option) =
let arguments = arguments |> Option.defaultValue ""
-
- let ops = [ shellOp context.Command arguments ]
+ let arguments = $"{context.Command} {arguments}"
+
+ let ops = [ shellOp "cargo" arguments ]
execRequest Cacheability.Always ops
diff --git a/src/Terrabuild.Extensions/Docker.fs b/src/Terrabuild.Extensions/Docker.fs
index b65f235e..c8e15469 100644
--- a/src/Terrabuild.Extensions/Docker.fs
+++ b/src/Terrabuild.Extensions/Docker.fs
@@ -7,6 +7,19 @@ open Terrabuild.Extensibility
///
type Docker() =
+ ///
+ /// Run a docker `command`.
+ ///
+ /// Example.
+ /// Arguments for command.
+ static member __dispatch__ (context: ActionContext) (arguments: string option) =
+ let arguments = arguments |> Option.defaultValue ""
+ let arguments = $"{context.Command} {arguments}"
+
+ let ops = [ shellOp "docker" arguments ]
+ execRequest Cacheability.Always ops
+
+
///
/// Build a Dockerfile.
///
diff --git a/src/Terrabuild.Extensions/Dotnet.fs b/src/Terrabuild.Extensions/Dotnet.fs
index c4262385..c3f0d087 100644
--- a/src/Terrabuild.Extensions/Dotnet.fs
+++ b/src/Terrabuild.Extensions/Dotnet.fs
@@ -75,6 +75,19 @@ type Dotnet() =
projectInfo
+ ///
+ /// Run a dotnet `command`.
+ ///
+ /// Example.
+ /// Arguments for command.
+ static member __dispatch__ (context: ActionContext) (arguments: string option) =
+ let arguments = arguments |> Option.defaultValue ""
+ let arguments = $"{context.Command} {arguments}"
+
+ let ops = [ shellOp "dotnet" arguments ]
+ execRequest Cacheability.Always ops
+
+
///
/// Build project and ensure packages are available first.
///
@@ -110,17 +123,6 @@ type Dotnet() =
buildRequest context buildOps
- ///
- /// Run a dotnet `command`.
- ///
- /// Example.
- /// Arguments for command.
- static member __dispatch__ (context: ActionContext) (arguments: string option) =
- let arguments = arguments |> Option.defaultValue ""
-
- let ops = [ shellOp context.Command arguments ]
- execRequest Cacheability.Always ops
-
///
/// Pack a project.
diff --git a/src/Terrabuild.Extensions/Gradle.fs b/src/Terrabuild.Extensions/Gradle.fs
index 5e24af21..dcf4759d 100644
--- a/src/Terrabuild.Extensions/Gradle.fs
+++ b/src/Terrabuild.Extensions/Gradle.fs
@@ -21,6 +21,19 @@ type Gradle() =
with Outputs = Set [ "build/classes/" ] }
projectInfo
+ ///
+ /// Run a gradle `command`.
+ ///
+ /// Example.
+ /// Arguments for command.
+ static member __dispatch__ (context: ActionContext) (arguments: string option) =
+ let arguments = arguments |> Option.defaultValue ""
+ let arguments = $"{context.Command} {arguments}"
+
+ let ops = [ shellOp "gradle" arguments ]
+ execRequest Cacheability.Always ops
+
+
///
/// Invoke build task `assemble` for `configuration`.
///
diff --git a/src/Terrabuild.Extensions/Npm.fs b/src/Terrabuild.Extensions/Npm.fs
index 9f066fc1..98492622 100644
--- a/src/Terrabuild.Extensions/Npm.fs
+++ b/src/Terrabuild.Extensions/Npm.fs
@@ -22,6 +22,21 @@ type Npm() =
projectInfo
+ ///
+ /// Run npm command.
+ ///
+ /// Arguments to pass to target.
+ static member __dispatch__ (context: ActionContext) (arguments: string option) =
+ let cmd = context.Command
+ let arguments = arguments |> Option.defaultValue ""
+
+ let ops = [
+ shellOp "npm" "ci"
+ shellOp "npm" $"run {cmd} -- {arguments}"
+ ]
+ execRequest Cacheability.Always ops
+
+
///
/// Install packages using lock file.
///
diff --git a/src/Terrabuild.Extensions/Terraform.fs b/src/Terrabuild.Extensions/Terraform.fs
index cc910fc8..6e05a2a7 100644
--- a/src/Terrabuild.Extensions/Terraform.fs
+++ b/src/Terrabuild.Extensions/Terraform.fs
@@ -24,6 +24,20 @@ type Terraform() =
Outputs = Set [ "*.planfile" ] }
projectInfo
+
+ ///
+ /// Run a terraform `command`.
+ ///
+ /// Example.
+ /// Arguments for command.
+ static member __dispatch__ (context: ActionContext) (arguments: string option) =
+ let arguments = arguments |> Option.defaultValue ""
+ let arguments = $"{context.Command} {arguments}"
+
+ let ops = [ shellOp "terraform" arguments ]
+ execRequest Cacheability.Always ops
+
+
///
/// Init Terraform.
///
diff --git a/src/Terrabuild.Extensions/Yarn.fs b/src/Terrabuild.Extensions/Yarn.fs
index 10ab6f5d..06c1abed 100644
--- a/src/Terrabuild.Extensions/Yarn.fs
+++ b/src/Terrabuild.Extensions/Yarn.fs
@@ -23,6 +23,21 @@ type Yarn() =
projectInfo
+ ///
+ /// Run yarn `command`.
+ ///
+ /// Arguments to pass to target.
+ static member __dispatch__ (context: ActionContext) (arguments: string option) =
+ let arguments = arguments |> Option.defaultValue ""
+ let cmd = context.Command
+
+ let ops = [
+ shellOp "yarn" "install --frozen-lockfile"
+ shellOp "yarn" $"{cmd} -- {arguments}"
+ ]
+ execRequest Cacheability.Always ops
+
+
///
/// Install packages using lock file.
///
diff --git a/src/Terrabuild/CLI.fs b/src/Terrabuild/CLI.fs
index f40cfc9b..f857f6d8 100644
--- a/src/Terrabuild/CLI.fs
+++ b/src/Terrabuild/CLI.fs
@@ -72,6 +72,24 @@ with
| Container_Tool _ -> "Container Tool to use (docker or podman)."
| WhatIf -> "Prepare the action but do not apply."
+[]
+type ServeArgs =
+ | [] Workspace of path:string
+ | [] Configuration of name:string
+ | [] Variable of variable:string * value:string
+ | [] Label of labels:string list
+ | [] Logs
+with
+ interface IArgParserTemplate with
+ member this.Usage =
+ match this with
+ | Workspace _ -> "Root of workspace. If not specified, current directory is used."
+ | Configuration _ -> "Configuration to use."
+ | Variable _ -> "Set variable."
+ | Label _-> "Select projects based on labels."
+ | Logs -> "Output logs for impacted projects."
+
+
[]
type ClearArgs =
| [] Cache
@@ -110,6 +128,7 @@ type TerrabuildArgs =
| [] Scaffold of ParseResults
| [] Logs of ParseResults
| [] Run of ParseResults
+ | [] Serve of ParseResults
| [] Clear of ParseResults
| [] Login of ParseResults
| [] Logout of ParseResults
@@ -122,6 +141,7 @@ with
| Scaffold _ -> "Scaffold workspace."
| Logs _ -> "dump logs."
| Run _ -> "Run specified targets."
+ | Serve _ -> "Serve specified targets."
| Clear _ -> "Clear specified caches."
| Login _ -> "Connect to backend."
| Logout _ -> "Disconnect from backend."
diff --git a/src/Terrabuild/Core/Build.fs b/src/Terrabuild/Core/Build.fs
index b30a2a0d..19d86fc4 100644
--- a/src/Terrabuild/Core/Build.fs
+++ b/src/Terrabuild/Core/Build.fs
@@ -115,7 +115,11 @@ let execCommands (node: GraphDef.Node) (cacheEntry: Cache.IEntry) (options: Conf
Log.Debug("{Hash}: Running '{Command}' with '{Arguments}'", node.TargetHash, cmd, args)
let logFile = cacheEntry.NextLogFile()
- let exitCode = Exec.execCaptureTimestampedOutput workDir cmd args logFile
+ let exitCode =
+ if options.Targets |> Set.contains "serve" then
+ Exec.execConsole workDir cmd args
+ else
+ Exec.execCaptureTimestampedOutput workDir cmd args logFile
cmdLastEndedAt <- DateTime.UtcNow
let endedAt = cmdLastEndedAt
let duration = endedAt - startedAt
diff --git a/src/Terrabuild/Helpers/Exec.fs b/src/Terrabuild/Helpers/Exec.fs
index 23303ee5..87ac0d36 100644
--- a/src/Terrabuild/Helpers/Exec.fs
+++ b/src/Terrabuild/Helpers/Exec.fs
@@ -9,17 +9,17 @@ type CaptureResult =
| Success of string*int
| Error of string*int
-let private createProcess workingDir command args =
+let private createProcess workingDir command args redirect =
let psi = ProcessStartInfo (FileName = command,
Arguments = args,
UseShellExecute = false,
WorkingDirectory = workingDir,
- RedirectStandardOutput = true,
- RedirectStandardError = true)
+ RedirectStandardOutput = redirect,
+ RedirectStandardError = redirect)
new Process(StartInfo = psi)
let execCaptureOutput (workingDir: string) (command: string) (args: string) =
- use proc = createProcess workingDir command args
+ use proc = createProcess workingDir command args true
proc.Start() |> ignore
proc.WaitForExit()
@@ -27,6 +27,15 @@ let execCaptureOutput (workingDir: string) (command: string) (args: string) =
| 0 -> Success (proc.StandardOutput.ReadToEnd(), proc.ExitCode)
| _ -> Error (proc.StandardError.ReadToEnd(), proc.ExitCode)
+let execConsole (workingDir: string) (command: string) (args: string) =
+ try
+ use proc = createProcess workingDir command args false
+ proc.Start() |> ignore
+ proc.WaitForExit()
+ proc.ExitCode
+ with
+ | exn -> TerrabuildException.Raise($"Process '{command} {args} in directory '{workingDir}' failed", exn)
+
let execCaptureTimestampedOutput (workingDir: string) (command: string) (args: string) (logFile: string) =
try
use logWriter = new StreamWriter(logFile)
@@ -35,14 +44,13 @@ let execCaptureTimestampedOutput (workingDir: string) (command: string) (args: s
let inline lockWrite (from: string) (msg: string) =
lock writeLock (fun () -> logWriter.WriteLine($"{DateTime.UtcNow} {from} {msg}"))
- use proc = createProcess workingDir command args
+ use proc = createProcess workingDir command args true
proc.OutputDataReceived.Add(fun e -> lockWrite "OUT" e.Data)
proc.ErrorDataReceived.Add(fun e -> lockWrite "ERR" e.Data)
proc.Start() |> ignore
proc.BeginOutputReadLine()
proc.BeginErrorReadLine()
proc.WaitForExit()
-
proc.ExitCode
with
| exn -> TerrabuildException.Raise($"Process '{command} {args} in directory '{workingDir}' failed", exn)
diff --git a/src/Terrabuild/Program.fs b/src/Terrabuild/Program.fs
index f142f751..1e3ef4ad 100644
--- a/src/Terrabuild/Program.fs
+++ b/src/Terrabuild/Program.fs
@@ -174,7 +174,6 @@ let processCommandLine (parser: ArgumentParser) (result: ParseRe
0
let run (runArgs: ParseResults) =
- let targets = runArgs.GetResult(RunArgs.Target) |> Seq.map String.toLower
let wsDir =
match runArgs.TryGetResult(RunArgs.Workspace) with
| Some ws -> ws
@@ -182,6 +181,7 @@ let processCommandLine (parser: ArgumentParser) (result: ParseRe
match Environment.CurrentDirectory |> findWorkspace with
| Some ws -> ws
| _ -> TerrabuildException.Raise("Can't find workspace root directory. Check you are in a workspace.")
+ let targets = runArgs.GetResult(RunArgs.Target) |> Seq.map String.toLower
let configuration = runArgs.TryGetResult(RunArgs.Configuration) |> Option.defaultValue "default" |> String.toLower
let note = runArgs.TryGetResult(RunArgs.Note)
let labels = runArgs.TryGetResult(RunArgs.Label) |> Option.map (fun labels -> labels |> Seq.map String.toLower |> Set)
@@ -218,6 +218,36 @@ let processCommandLine (parser: ArgumentParser) (result: ParseRe
RunTargetOptions.ContainerTool = containerTool }
runTarget logs options
+ let serve (serveArgs: ParseResults) =
+ let wsDir =
+ match serveArgs.TryGetResult(ServeArgs.Workspace) with
+ | Some ws -> ws
+ | _ ->
+ match Environment.CurrentDirectory |> findWorkspace with
+ | Some ws -> ws
+ | _ -> TerrabuildException.Raise("Can't find workspace root directory. Check you are in a workspace.")
+ let configuration = serveArgs.TryGetResult(ServeArgs.Configuration) |> Option.defaultValue "default" |> String.toLower
+ let labels = serveArgs.TryGetResult(ServeArgs.Label) |> Option.map (fun labels -> labels |> Seq.map String.toLower |> Set)
+ let variables = serveArgs.GetResults(ServeArgs.Variable) |> Map
+ let options = { RunTargetOptions.Workspace = wsDir |> FS.fullPath
+ RunTargetOptions.WhatIf = false
+ RunTargetOptions.Debug = debug
+ RunTargetOptions.Force = false
+ RunTargetOptions.MaxConcurrency = Int32.MaxValue
+ RunTargetOptions.Retry = true
+ RunTargetOptions.StartedAt = DateTime.UtcNow
+ RunTargetOptions.IsLog = false
+ RunTargetOptions.Targets = Set [ "serve" ]
+ RunTargetOptions.LocalOnly = true
+ RunTargetOptions.CheckState = false
+ RunTargetOptions.Configuration = configuration
+ RunTargetOptions.Note = None
+ RunTargetOptions.Tag = None
+ RunTargetOptions.Labels = labels
+ RunTargetOptions.Variables = variables
+ RunTargetOptions.ContainerTool = None }
+ runTarget true options
+
let logs (logsArgs: ParseResults) =
let targets = logsArgs.GetResult(LogsArgs.Target) |> Seq.map String.toLower
let wsDir =
@@ -279,6 +309,7 @@ let processCommandLine (parser: ArgumentParser) (result: ParseRe
| p when p.Contains(TerrabuildArgs.Scaffold) -> p.GetResult(TerrabuildArgs.Scaffold) |> scaffold
| p when p.Contains(TerrabuildArgs.Logs) -> p.GetResult(TerrabuildArgs.Logs) |> logs
| p when p.Contains(TerrabuildArgs.Run) -> p.GetResult(TerrabuildArgs.Run) |> run
+ | p when p.Contains(TerrabuildArgs.Serve) -> p.GetResult(TerrabuildArgs.Serve) |> serve
| p when p.Contains(TerrabuildArgs.Clear) -> p.GetResult(TerrabuildArgs.Clear) |> clear
| p when p.Contains(TerrabuildArgs.Login) -> p.GetResult(TerrabuildArgs.Login) |> login
| p when p.Contains(TerrabuildArgs.Logout) -> p.GetResult(TerrabuildArgs.Logout) |> logout