mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
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`
This commit is contained in:
@@ -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:
|
||||
|
||||
|
||||
@@ -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")
|
||||
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)
|
||||
|
||||
var p = startProcess(command, options = options + {poEvalCommand})
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user