summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
authorTimothee Cour <timothee.cour2@gmail.com>2020-05-13 04:45:36 -0700
committerGitHub <noreply@github.com>2020-05-13 13:45:36 +0200
commit041ee92bba0ba3f361218eb20ceeeee6eec85f91 (patch)
tree1a55acb85d5a9d15f836aaa1a0930193bdebf17c /lib/pure
parent1648f1dd9955c848f8fbaf46a89798ece21460cc (diff)
downloadNim-041ee92bba0ba3f361218eb20ceeeee6eec85f91.tar.gz
`osproc.execCmdEx` now takes an optional `input` for stdin, `env`, workingDir (#14211)
* `osproc.execCmdEx` now takes an optional `input` for stdin

* execCmdEx now also takes an optional ``workingDir` and `env`
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/osproc.nim43
1 files changed, 31 insertions, 12 deletions
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index f90b310ea..3e3391d52 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -1438,12 +1438,16 @@ elif not defined(useNimRtl):
 
 
 proc execCmdEx*(command: string, options: set[ProcessOption] = {
-                poStdErrToStdOut, poUsePath}): tuple[
+                poStdErrToStdOut, poUsePath}, env: StringTableRef = nil,
+                workingDir = "", input = ""): tuple[
                 output: TaintedString,
                 exitCode: int] {.tags:
                 [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} =
-  ## A convenience proc that runs the `command`, grabs all its output and
-  ## exit code and returns both.
+  ## A convenience proc that runs the `command`, and returns its `output` and
+  ## `exitCode`. `env` and `workingDir` params behave as for `startProcess`.
+  ## If `input.len > 0`, it is passed as stdin.
+  ## Note: this could block if `input.len` is greater than your OS's maximum
+  ## pipe buffer size.
   ##
   ## See also:
   ## * `execCmd proc <#execCmd,string>`_
@@ -1452,17 +1456,32 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = {
   ## * `execProcess proc
   ##   <#execProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_
   ##
-  ## Example:
-  ##
-  ## .. code-block:: Nim
-  ##  let (outp, errC) = execCmdEx("nim c -r mytestfile.nim")
-
-  var p = startProcess(command, options = options + {poEvalCommand})
+  runnableExamples:
+    var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4")
+    import strutils, strtabs
+    stripLineEnd(result[0]) ## portable way to remove trailing newline, if any
+    doAssert result == ("12", 0)
+    doAssert execCmdEx("ls --nonexistant").exitCode != 0
+    when defined(posix):
+      assert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0)
+      assert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0)
+
+  when (NimMajor, NimMinor, NimPatch) < (1, 3, 5):
+    doAssert input.len == 0
+    doAssert workingDir.len == 0
+    doAssert env == nil
+
+  var p = startProcess(command, options = options + {poEvalCommand},
+    workingDir = workingDir, env = env)
   var outp = outputStream(p)
 
-  # There is no way to provide input for the child process
-  # anymore. Closing it will create EOF on stdin instead of eternal
-  # blocking.
+  if input.len > 0:
+    # There is no way to provide input for the child process
+    # anymore. Closing it will create EOF on stdin instead of eternal
+    # blocking.
+    # Writing in chunks would require a selectors (eg kqueue/epoll) to avoid
+    # blocking on io.
+    inputStream(p).write(input)
   close inputStream(p)
 
   result = (TaintedString"", -1)