diff options
Diffstat (limited to 'lib/pure/osproc.nim')
-rw-r--r-- | lib/pure/osproc.nim | 92 |
1 files changed, 76 insertions, 16 deletions
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 3e3391d52..5113695d8 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -18,7 +18,8 @@ include "system/inclrtl" import - strutils, os, strtabs, streams, cpuinfo + strutils, os, strtabs, streams, cpuinfo, streamwrapper, + std/private/since export quoteShell, quoteShellWindows, quoteShellPosix @@ -237,6 +238,10 @@ proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## Returns ``p``'s output stream for reading from. ## + ## You cannot perform peek/write/setOption operations to this stream. + ## Use `peekableOutputStream proc <#peekableOutputStream,Process>`_ + ## if you need to peek stream. + ## ## **WARNING**: The returned `Stream` should not be closed manually as it ## is closed when closing the Process ``p``. ## @@ -247,6 +252,10 @@ proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## Returns ``p``'s error stream for reading from. ## + ## You cannot perform peek/write/setOption operations to this stream. + ## Use `peekableErrorStream proc <#peekableErrorStream,Process>`_ + ## if you need to peek stream. + ## ## **WARNING**: The returned `Stream` should not be closed manually as it ## is closed when closing the Process ``p``. ## @@ -254,6 +263,30 @@ proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## * `inputStream proc <#inputStream,Process>`_ ## * `outputStream proc <#outputStream,Process>`_ +proc peekableOutputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [], since: (1, 3).} + ## Returns ``p``'s output stream for reading from. + ## + ## You can peek returned stream. + ## + ## **WARNING**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. + ## + ## See also: + ## * `outputStream proc <#outputStream,Process>`_ + ## * `peekableErrorStream proc <#peekableErrorStream,Process>`_ + +proc peekableErrorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [], since: (1, 3).} + ## Returns ``p``'s error stream for reading from. + ## + ## You can run peek operation to returned stream. + ## + ## **WARNING**: The returned `Stream` should not be closed manually as it + ## is closed when closing the Process ``p``. + ## + ## See also: + ## * `errorStream proc <#errorStream,Process>`_ + ## * `peekableOutputStream proc <#peekableOutputStream,Process>`_ + proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## Returns ``p``'s input file handle for writing to. @@ -737,6 +770,18 @@ when defined(Windows) and not defined(useNimRtl): p.errStream = newFileHandleStream(p.errHandle) result = p.errStream + proc peekableOutputStream(p: Process): Stream = + streamAccess(p) + if p.outStream == nil: + p.outStream = newFileHandleStream(p.outHandle).newPipeOutStream + result = p.outStream + + proc peekableErrorStream(p: Process): Stream = + streamAccess(p) + if p.errStream == nil: + p.errStream = newFileHandleStream(p.errHandle).newPipeOutStream + result = p.errStream + proc execCmd(command: string): int = var si: STARTUPINFO @@ -1360,28 +1405,40 @@ elif not defined(useNimRtl): p.exitStatus = status result = exitStatusLikeShell(status) - proc createStream(stream: var owned(Stream), handle: var FileHandle, - fileMode: FileMode) = + proc createStream(handle: var FileHandle, + fileMode: FileMode): owned FileStream = var f: File if not open(f, handle, fileMode): raiseOSError(osLastError()) - stream = newFileStream(f) + return newFileStream(f) proc inputStream(p: Process): Stream = streamAccess(p) if p.inStream == nil: - createStream(p.inStream, p.inHandle, fmWrite) + p.inStream = createStream(p.inHandle, fmWrite) return p.inStream proc outputStream(p: Process): Stream = streamAccess(p) if p.outStream == nil: - createStream(p.outStream, p.outHandle, fmRead) + p.outStream = createStream(p.outHandle, fmRead) return p.outStream proc errorStream(p: Process): Stream = streamAccess(p) if p.errStream == nil: - createStream(p.errStream, p.errHandle, fmRead) + p.errStream = createStream(p.errHandle, fmRead) + return p.errStream + + proc peekableOutputStream(p: Process): Stream = + streamAccess(p) + if p.outStream == nil: + p.outStream = createStream(p.outHandle, fmRead).newPipeOutStream + return p.outStream + + proc peekableErrorStream(p: Process): Stream = + streamAccess(p) + if p.errStream == nil: + p.errStream = createStream(p.errHandle, fmRead).newPipeOutStream return p.errStream proc csystem(cmd: cstring): cint {.nodecl, importc: "system", @@ -1446,6 +1503,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { ## 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. ## @@ -1456,15 +1514,17 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { ## * `execProcess proc ## <#execProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_ ## - 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) + ## Example: + ## + ## .. code-block:: Nim + ## 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 |