diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2020-05-13 04:45:36 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-13 13:45:36 +0200 |
commit | 041ee92bba0ba3f361218eb20ceeeee6eec85f91 (patch) | |
tree | 1a55acb85d5a9d15f836aaa1a0930193bdebf17c | |
parent | 1648f1dd9955c848f8fbaf46a89798ece21460cc (diff) | |
download | Nim-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`
-rw-r--r-- | changelog.md | 4 | ||||
-rw-r--r-- | lib/pure/osproc.nim | 43 | ||||
-rw-r--r-- | lib/system.nim | 3 | ||||
-rw-r--r-- | tests/stdlib/tosproc.nim | 15 |
4 files changed, 51 insertions, 14 deletions
diff --git a/changelog.md b/changelog.md index d54ed4c8c..d6be5a9b7 100644 --- a/changelog.md +++ b/changelog.md @@ -92,6 +92,10 @@ - The callback that is passed to `system.onThreadDestruction` must now be `.raises: []`. +- `osproc.execCmdEx` now takes an optional `input` for stdin. +- `osproc.execCmdEx` now takes an optional `input` for stdin, `workingDir` and `env` + parameters. + ## Language changes - In the newruntime it is now allowed to assign discriminator field without restrictions as long as case object doesn't have custom destructor. Discriminator value doesn't have to be a constant either. If you have custom destructor for case object and you do want to freely assign discriminator fields, it is recommended to refactor object into 2 objects like this: 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) diff --git a/lib/system.nim b/lib/system.nim index 8ce79aa2f..6b24bdcb8 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2068,8 +2068,9 @@ const ## is the minor number of Nim's version. ## Odd for devel, even for releases. - NimPatch* {.intdefine.}: int = 3 + NimPatch* {.intdefine.}: int = 5 ## is the patch number of Nim's version. + ## Odd for devel, even for releases. import system/dollars export dollars diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim index 73cec0cb7..36afd6a23 100644 --- a/tests/stdlib/tosproc.nim +++ b/tests/stdlib/tosproc.nim @@ -1,7 +1,7 @@ # test the osproc module import stdtest/specialpaths -import "../.." / compiler/unittest_light +import "$nim" / compiler/unittest_light when defined(case_testfile): # compiled test file for child process from posix import exitnow @@ -119,3 +119,16 @@ else: var result = startProcessTest("nim r --hints:off -", options = {}, input = "echo 3*4") doAssert result == ("12\n", 0) + + import std/strtabs + block execProcessTest: + var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4") + stripLineEnd(result[0]) + doAssert result == ("12", 0) + doAssert execCmdEx("ls --nonexistant").exitCode != 0 + when false: + # bug: on windows, this raises; on posix, passes + doAssert execCmdEx("nonexistant").exitCode != 0 + when defined(posix): + doAssert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0) + doAssert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0) |