Skip to content

Commit

Permalink
osproc.execCmdEx now takes an optional input for stdin
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed May 11, 2020
1 parent 9502e39 commit 37ae76c
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 11 deletions.
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@
- Fix a bug where calling `close` on io streams in osproc.startProcess was a noop and led to
hangs if a process had both reads from stdin and writes (eg to stdout).

- `osproc.execCmdEx` now takes an optional `input` for stdin.

## Language changes
- In 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:
```nim
Expand Down
29 changes: 19 additions & 10 deletions lib/pure/osproc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1438,12 +1438,14 @@ elif not defined(useNimRtl):


proc execCmdEx*(command: string, options: set[ProcessOption] = {
poStdErrToStdOut, poUsePath}): tuple[
poStdErrToStdOut, poUsePath}, 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.
## exit code and returns both. 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>`_
Expand All @@ -1452,17 +1454,24 @@ 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")

runnableExamples:
var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4")
import strutils
stripLineEnd(result[0])
doAssert result == ("12", 0)

when (NimMajor, NimMinor) < (1, 3):
doAssert input.len == 0
var p = startProcess(command, options = options + {poEvalCommand})
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)
Expand Down
7 changes: 6 additions & 1 deletion tests/stdlib/tosproc.nim
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -119,3 +119,8 @@ else:

var result = startProcessTest("nim r --hints:off -", options = {}, input = "echo 3*4")
doAssert result == ("12\n", 0)

block execProcessTest:
var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4")
stripLineEnd(result[0])
doAssert result == ("12", 0)

0 comments on commit 37ae76c

Please sign in to comment.