[backport] run nimpretty on os-related stuff

This commit is contained in:
narimiran 2019-09-27 12:17:00 +02:00
commit 34d0be2ec1
10 changed files with 191 additions and 182 deletions

View file

@ -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.
## 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].}
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