diff options
Diffstat (limited to 'lib/pure/osproc.nim')
-rw-r--r-- | lib/pure/osproc.nim | 174 |
1 files changed, 81 insertions, 93 deletions
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 353713a80..d24740a16 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -32,22 +32,22 @@ when defined(linux): type ProcessOption* = enum ## Options that can be passed to `startProcess proc - ## <#startProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_. - poEchoCmd, ## Echo the command before execution. - poUsePath, ## Asks system to search for executable using PATH environment - ## variable. - ## On Windows, this is the default. - poEvalCommand, ## Pass `command` directly to the shell, without quoting. - ## Use it only if `command` comes from trusted source. - poStdErrToStdOut, ## Merge stdout and stderr to the stdout stream. - poParentStreams, ## Use the parent's streams. - poInteractive, ## Optimize the buffer handling for responsiveness for - ## UI applications. Currently this only affects - ## Windows: Named pipes are used so that you can peek - ## at the process' output streams. - poDaemon ## Windows: The program creates no Window. - ## Unix: Start the program as a daemon. This is still - ## work in progress! + ## <#startProcess,string,string,openArray[string],StringTableRef,set[ProcessOption]>`_. + poEchoCmd, ## Echo the command before execution. + poUsePath, ## Asks system to search for executable using PATH environment + ## variable. + ## On Windows, this is the default. + poEvalCommand, ## Pass `command` directly to the shell, without quoting. + ## Use it only if `command` comes from trusted source. + poStdErrToStdOut, ## Merge stdout and stderr to the stdout stream. + poParentStreams, ## Use the parent's streams. + poInteractive, ## Optimize the buffer handling for responsiveness for + ## UI applications. Currently this only affects + ## Windows: Named pipes are used so that you can peek + ## at the process' output streams. + poDaemon ## Windows: The program creates no Window. + ## Unix: Start the program as a daemon. This is still + ## work in progress! ProcessObj = object of RootObj when defined(windows): @@ -66,21 +66,16 @@ type Process* = ref ProcessObj ## Represents an operating system process. const poDemon* {.deprecated.} = poDaemon ## Nim versions before 0.20 - ## used the wrong spelling ("demon"). - ## Now `ProcessOption` uses the correct spelling ("daemon"), - ## and this is needed just for backward compatibility. - - -proc execProcess*(command: string, - workingDir: string = "", - args: openArray[string] = [], - env: StringTableRef = nil, - options: set[ProcessOption] = {poStdErrToStdOut, - poUsePath, - poEvalCommand}): TaintedString {. - rtl, extern: "nosp$1", - tags: [ExecIOEffect, ReadIOEffect, - RootEffect].} + ## used the wrong spelling ("demon"). + ## Now `ProcessOption` uses the correct spelling ("daemon"), + ## and this is needed just for backward compatibility. + + +proc execProcess*(command: string, workingDir: string = "", + args: openArray[string] = [], env: StringTableRef = nil, + options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, poEvalCommand}): + TaintedString {.rtl, extern: "nosp$1", + tags: [ExecIOEffect, ReadIOEffect, RootEffect].} ## A convenience procedure that executes ``command`` with ``startProcess`` ## and returns its output as a string. ## @@ -102,8 +97,8 @@ proc execProcess*(command: string, ## # Note: outp may have an interleave of text from the nim compile ## # and any output from mytestfile when it runs -proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [ExecIOEffect, - ReadIOEffect, RootEffect].} +proc execCmd*(command: string): int {.rtl, extern: "nosp$1", + tags: [ExecIOEffect, ReadIOEffect, RootEffect].} ## Executes ``command`` and returns its error code. ## ## Standard input, output, error streams are inherited from the calling process. @@ -121,13 +116,11 @@ proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [ExecIOEffect ## .. code-block:: Nim ## let errC = execCmd("nim c -r mytestfile.nim") -proc startProcess*(command: string, - workingDir: string = "", - args: openArray[string] = [], - env: StringTableRef = nil, - options: set[ProcessOption] = {poStdErrToStdOut}): - owned(Process) {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadEnvEffect, - RootEffect].} +proc startProcess*(command: string, workingDir: string = "", + args: openArray[string] = [], env: StringTableRef = nil, + options: set[ProcessOption] = {poStdErrToStdOut}): + owned(Process) {.rtl, extern: "nosp$1", + tags: [ExecIOEffect, ReadEnvEffect, RootEffect].} ## Starts a process. `Command` is the executable file, `workingDir` is the ## process's working directory. If ``workingDir == ""`` the current directory ## is used (default). `args` are the command line arguments that are passed to the @@ -216,7 +209,7 @@ proc processID*(p: Process): int {.rtl, extern: "nosp$1".} = return p.id proc waitForExit*(p: Process, timeout: int = -1): int {.rtl, - extern: "nosp$1", tags: [].} + extern: "nosp$1", tags: [].} ## Waits for the process to finish and returns `p`'s error code. ## ## **WARNING**: Be careful when using `waitForExit` for processes created without @@ -274,7 +267,7 @@ proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", result = p.inHandle proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", - tags: [].} = + tags: [].} = ## Returns ``p``'s output file handle for reading from. ## ## **WARNING**: The returned `FileHandle` should not be closed manually as @@ -286,7 +279,7 @@ proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", result = p.outHandle proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", - tags: [].} = + tags: [].} = ## Returns ``p``'s error file handle for reading from. ## ## **WARNING**: The returned `FileHandle` should not be closed manually as @@ -303,12 +296,11 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} = result = cpuinfo.countProcessors() proc execProcesses*(cmds: openArray[string], - options = {poStdErrToStdOut, poParentStreams}, - n = countProcessors(), - beforeRunEvent: proc(idx: int) = nil, - afterRunEvent: proc(idx: int, p: Process) = nil): int - {.rtl, extern: "nosp$1", - tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect].} = + options = {poStdErrToStdOut, poParentStreams}, n = countProcessors(), + beforeRunEvent: proc(idx: int) = nil, + afterRunEvent: proc(idx: int, p: Process) = nil): + int {.rtl, extern: "nosp$1", + tags: [ExecIOEffect, TimeEffect, ReadEnvEffect, RootEffect].} = ## Executes the commands `cmds` in parallel. ## Creates `n` processes that execute in parallel. ## @@ -413,20 +405,20 @@ proc execProcesses*(cmds: openArray[string], for i in 0..high(cmds): if beforeRunEvent != nil: beforeRunEvent(i) - var p = startProcess(cmds[i], options=options + {poEvalCommand}) + var p = startProcess(cmds[i], options = options + {poEvalCommand}) result = max(abs(waitForExit(p)), result) if afterRunEvent != nil: afterRunEvent(i, p) close(p) when not defined(useNimRtl): - proc execProcess(command: string, - workingDir: string = "", - args: openArray[string] = [], - env: StringTableRef = nil, - options: set[ProcessOption] = {poStdErrToStdOut, - poUsePath, - poEvalCommand}): TaintedString = - var p = startProcess(command, workingDir=workingDir, args=args, env=env, options=options) + proc execProcess(command: string, workingDir: string = "", + args: openArray[string] = [], env: StringTableRef = nil, + options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, + poEvalCommand}): + TaintedString = + + var p = startProcess(command, workingDir = workingDir, args = args, + env = env, options = options) var outp = outputStream(p) result = TaintedString"" var line = newStringOfCap(120).TaintedString @@ -501,16 +493,14 @@ when defined(Windows) and not defined(useNimRtl): #var # O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int # O_RDONLY {.importc: "_O_RDONLY", header: "<fcntl.h>".}: int - proc myDup(h: Handle; inherit: WINBOOL=1): Handle = + proc myDup(h: Handle; inherit: WINBOOL = 1): Handle = let thisProc = getCurrentProcess() - if duplicateHandle(thisProc, h, - thisProc, addr result,0,inherit, + if duplicateHandle(thisProc, h, thisProc, addr result, 0, inherit, DUPLICATE_SAME_ACCESS) == 0: raiseOSError(osLastError()) proc createAllPipeHandles(si: var STARTUPINFO; - stdin, stdout, stderr: var Handle; - hash: int) = + stdin, stdout, stderr: var Handle; hash: int) = var sa: SECURITY_ATTRIBUTES sa.nLength = sizeof(SECURITY_ATTRIBUTES).cint sa.lpSecurityDescriptor = nil @@ -518,37 +508,37 @@ when defined(Windows) and not defined(useNimRtl): let pipeOutName = newWideCString(r"\\.\pipe\stdout" & $hash) let pipeInName = newWideCString(r"\\.\pipe\stdin" & $hash) let pipeOut = createNamedPipe(pipeOutName, - dwOpenMode=PIPE_ACCESS_INBOUND or FILE_FLAG_WRITE_THROUGH, - dwPipeMode=PIPE_NOWAIT, - nMaxInstances=1, - nOutBufferSize=1024, nInBufferSize=1024, - nDefaultTimeOut=0,addr sa) + dwOpenMode = PIPE_ACCESS_INBOUND or FILE_FLAG_WRITE_THROUGH, + dwPipeMode = PIPE_NOWAIT, + nMaxInstances = 1, + nOutBufferSize = 1024, nInBufferSize = 1024, + nDefaultTimeOut = 0, addr sa) if pipeOut == INVALID_HANDLE_VALUE: raiseOSError(osLastError()) let pipeIn = createNamedPipe(pipeInName, - dwOpenMode=PIPE_ACCESS_OUTBOUND or FILE_FLAG_WRITE_THROUGH, - dwPipeMode=PIPE_NOWAIT, - nMaxInstances=1, - nOutBufferSize=1024, nInBufferSize=1024, - nDefaultTimeOut=0,addr sa) + dwOpenMode = PIPE_ACCESS_OUTBOUND or FILE_FLAG_WRITE_THROUGH, + dwPipeMode = PIPE_NOWAIT, + nMaxInstances = 1, + nOutBufferSize = 1024, nInBufferSize = 1024, + nDefaultTimeOut = 0, addr sa) if pipeIn == INVALID_HANDLE_VALUE: raiseOSError(osLastError()) si.hStdOutput = createFileW(pipeOutName, FILE_WRITE_DATA or SYNCHRONIZE, 0, addr sa, OPEN_EXISTING, # very important flag! - FILE_ATTRIBUTE_NORMAL, - 0 # no template file for OPEN_EXISTING - ) + FILE_ATTRIBUTE_NORMAL, + 0 # no template file for OPEN_EXISTING + ) if si.hStdOutput == INVALID_HANDLE_VALUE: raiseOSError(osLastError()) si.hStdError = myDup(si.hStdOutput) si.hStdInput = createFileW(pipeInName, FILE_READ_DATA or SYNCHRONIZE, 0, addr sa, OPEN_EXISTING, # very important flag! - FILE_ATTRIBUTE_NORMAL, - 0 # no template file for OPEN_EXISTING - ) + FILE_ATTRIBUTE_NORMAL, + 0 # no template file for OPEN_EXISTING + ) if si.hStdOutput == INVALID_HANDLE_VALUE: raiseOSError(osLastError()) @@ -569,11 +559,10 @@ when defined(Windows) and not defined(useNimRtl): proc fileClose(h: Handle) {.inline.} = if h > 4: discard closeHandle(h) - proc startProcess(command: string, - workingDir: string = "", - args: openArray[string] = [], - env: StringTableRef = nil, - options: set[ProcessOption] = {poStdErrToStdOut}): owned Process = + proc startProcess(command: string, workingDir: string = "", + args: openArray[string] = [], env: StringTableRef = nil, + options: set[ProcessOption] = {poStdErrToStdOut}): + owned Process = var si: STARTUPINFO procInfo: PROCESS_INFORMATION @@ -789,7 +778,7 @@ when defined(Windows) and not defined(useNimRtl): proc hasData*(p: Process): bool = var x: int32 - if peekNamedPipe(p.outHandle, lpTotalBytesAvail=addr x): + if peekNamedPipe(p.outHandle, lpTotalBytesAvail = addr x): result = x > 0 elif not defined(useNimRtl): @@ -842,11 +831,10 @@ elif not defined(useNimRtl): tags: [ExecIOEffect, ReadEnvEffect, ReadDirEffect, RootEffect], cdecl, gcsafe.} {.pop.} - proc startProcess(command: string, - workingDir: string = "", - args: openArray[string] = [], - env: StringTableRef = nil, - options: set[ProcessOption] = {poStdErrToStdOut}): owned Process = + proc startProcess(command: string, workingDir: string = "", + args: openArray[string] = [], env: StringTableRef = nil, + options: set[ProcessOption] = {poStdErrToStdOut}): + owned Process = var pStdin, pStdout, pStderr: array[0..1, cint] new(result) @@ -1013,7 +1001,7 @@ elif not defined(useNimRtl): if sizeRead == sizeof(error): raiseOSError(osLastError(), "Could not find command: '$1'. OS error: $2" % - [$data.sysCommand, $strerror(error)]) + [$data.sysCommand, $strerror(error)]) return pid @@ -1066,7 +1054,7 @@ elif not defined(useNimRtl): discard execve(data.sysCommand, data.sysArgs, data.sysEnv) startProcessFail(data) - {.pop} + {.pop.} proc close(p: Process) = if poParentStreams notin p.options: @@ -1401,7 +1389,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { ## .. code-block:: Nim ## let (outp, errC) = execCmdEx("nim c -r mytestfile.nim") - var p = startProcess(command, options=options + {poEvalCommand}) + var p = startProcess(command, options = options + {poEvalCommand}) var outp = outputStream(p) # There is no way to provide input for the child process |