Launcher now uses new-slots; fix Windows environment passing bug

db4
Slava Pestov 2008-03-07 01:55:29 -06:00
parent 2f2073a2c9
commit 755003df08
8 changed files with 245 additions and 72 deletions

View File

@ -1 +1,2 @@
Doug Coleman
Slava Pestov

View File

@ -64,7 +64,7 @@ $nl
"This is used in situations where you want a spawn child process with some overridden environment variables." } ;
ARTICLE: "io.launcher.timeouts" "Process run-time timeouts"
{ $description "The " { $snippet "timeout" } " slot of a " { $link process } " can be set to a " { $link duration } " specifying a maximum running time for the process. If " { $link wait-for-process } " is called and the process does not exit before the duration expires, it will be killed." } ;
"The " { $snippet "timeout" } " slot of a " { $link process } " can be set to a " { $link duration } " specifying a maximum running time for the process. If " { $link wait-for-process } " is called and the process does not exit before the duration expires, it will be killed." ;
HELP: get-environment
{ $values { "process" process } { "env" "an association" } }
@ -147,14 +147,17 @@ $nl
"A " { $link process } " instance can be created directly and passed to launching words for more control. It must be a fresh instance which has never been spawned before. To spawn a process several times from the same descriptor, " { $link clone } " the descriptor first." ;
ARTICLE: "io.launcher.lifecycle" "The process lifecycle"
"A freshly instantiated " { $link process } " represents a set of launch parameters. Words for launching processes take a fresh process which has never been started before as input, and output a copy as output."
{ $link process-started? }
"A freshly instantiated " { $link process } " represents a set of launch parameters."
{ $subsection process }
{ $subsection <process> }
"Words for launching processes take a fresh process which has never been started before as input, and output a copy as output."
{ $subsection process-started? }
"The " { $link process } " instance output by launching words contains all original slot values in addition to the " { $snippet "handle" } " slot, which indicates the process is currently running."
{ $link process-running? }
{ $subsection process-running? }
"It is possible to wait for a process to exit:"
{ $link wait-for-process }
{ $subsection wait-for-process }
"A running process can also be killed:"
{ $link kill-process } ;
{ $subsection kill-process } ;
ARTICLE: "io.launcher.launch" "Launching processes"
"Launching processes:"
@ -164,8 +167,47 @@ ARTICLE: "io.launcher.launch" "Launching processes"
{ $subsection <process-stream> }
{ $subsection with-process-stream } ;
ARTICLE: "io.launcher.examples" "Launcher examples"
"Starting a command and waiting for it to finish:"
{ $code
"\"ls /etc\" run-process"
}
"Starting a program in the background:"
{ $code
"{ \"emacs\" \"foo.txt\" } run-detached"
}
"Running a command, throwing an exception if it exits unsuccessfully:"
{ $code
"\"make clean all\" try-process"
}
"Running a command, throwing an exception if it exits unsuccessfully or if it takes too long to run:"
{ $code
"<process>"
" \"make test\" >>command"
" 5 minutes >>timeout"
"try-process"
}
"Running a command, throwing an exception if it exits unsuccessfully, and redirecting output and error messages to a log file:"
{ $code
"<process>"
" \"make clean all\" >>command"
" \"log.txt\" >>stdout"
" +stdout+ >>stderr"
"try-process"
}
"Running a command, appending error messages to a log file, and reading the output for further processing:"
{ $code
"\"log.txt\" <file-appender> ["
" <process>"
" swap >>stderr"
" \"report\" >>command"
" ascii <process-stream> lines sort reverse [ print ] each"
"] with-disposal"
} ;
ARTICLE: "io.launcher" "Operating system processes"
"The " { $vocab-link "io.launcher" } " vocabulary implements cross-platform process launching."
{ $subsection "io.launcher.examples" }
{ $subsection "io.launcher.descriptors" }
{ $subsection "io.launcher.launch" }
"Advanced topics:"

View File

@ -69,27 +69,26 @@ TUPLE: CreateProcess-args
: fill-dwCreateFlags ( process args -- process args )
0
over pass-environment? [ CREATE_UNICODE_ENVIRONMENT bitor ] when
over detached>> winnt? and [ DETACHED_PROCESS bitor ] when
pick pass-environment? [ CREATE_UNICODE_ENVIRONMENT bitor ] when
pick detached>> winnt? and [ DETACHED_PROCESS bitor ] when
>>dwCreateFlags ;
: fill-lpEnvironment ( process args -- process args )
over pass-environment? [
[
over get-environment
[ "=" swap 3append string>u16-alien % ] assoc-each
[ swap % "=" % % "\0" % ] assoc-each
"\0" %
] { } make >c-ushort-array
] "" make >c-ushort-array
>>lpEnvironment
] when ;
: fill-startup-info ( process args -- process args )
dup lpStartupInfo>>
STARTF_USESTDHANDLES swap set-STARTUPINFO-dwFlags ;
STARTF_USESTDHANDLES over lpStartupInfo>> set-STARTUPINFO-dwFlags ;
HOOK: fill-redirection io-backend ( process args -- process args )
HOOK: fill-redirection io-backend ( process args -- )
M: windows-ce-io fill-redirection ;
M: windows-ce-io fill-redirection 2drop ;
: make-CreateProcess-args ( process -- args )
default-CreateProcess-args
@ -102,14 +101,12 @@ M: windows-ce-io fill-redirection ;
M: windows-io current-process-handle ( -- handle )
GetCurrentProcessId ;
M: windows-io run-process* ( desc -- handle )
M: windows-io run-process* ( process -- handle )
[
[
make-CreateProcess-args
fill-redirection
dup call-CreateProcess
CreateProcess-args-lpProcessInformation
] with-descriptor
dup make-CreateProcess-args
tuck fill-redirection
dup call-CreateProcess
lpProcessInformation>>
] with-destructors ;
M: windows-io kill-process* ( handle -- )

View File

@ -0,0 +1,131 @@
IN: io.windows.launcher.nt.tests
USING: io.launcher tools.test calendar accessors
namespaces kernel system arrays io io.files io.encodings.ascii
sequences parser assocs hashtables ;
[ ] [
<process>
"notepad" >>command
1/2 seconds >>timeout
"notepad" set
] unit-test
[ f ] [ "notepad" get process-running? ] unit-test
[ f ] [ "notepad" get process-started? ] unit-test
[ ] [ "notepad" [ run-detached ] change ] unit-test
[ "notepad" get wait-for-process ] must-fail
[ t ] [ "notepad" get killed>> ] unit-test
[ f ] [ "notepad" get process-running? ] unit-test
[ ] [
<process>
vm "-quiet" "-run=hello-world" 3array >>command
"out.txt" temp-file >>stdout
try-process
] unit-test
[ "Hello world" ] [
"out.txt" temp-file ascii file-lines first
] unit-test
[ ] [
<process>
vm "-run=listener" 2array >>command
+closed+ >>stdin
try-process
] unit-test
[ ] [
"extra/io/windows/nt/launcher/test" resource-path [
<process>
vm "-script" "stderr.factor" 3array >>command
"out.txt" temp-file >>stdout
"err.txt" temp-file >>stderr
try-process
] with-directory
] unit-test
[ "output" ] [
"out.txt" temp-file ascii file-lines first
] unit-test
[ "error" ] [
"err.txt" temp-file ascii file-lines first
] unit-test
[ ] [
"extra/io/windows/nt/launcher/test" resource-path [
<process>
vm "-script" "stderr.factor" 3array >>command
"out.txt" temp-file >>stdout
+stdout+ >>stderr
try-process
] with-directory
] unit-test
[ "outputerror" ] [
"out.txt" temp-file ascii file-lines first
] unit-test
[ "output" ] [
"extra/io/windows/nt/launcher/test" resource-path [
<process>
vm "-script" "stderr.factor" 3array >>command
"err2.txt" temp-file >>stderr
ascii <process-stream> lines first
] with-directory
] unit-test
[ "error" ] [
"err2.txt" temp-file ascii file-lines first
] unit-test
[ t ] [
"extra/io/windows/nt/launcher/test" resource-path [
<process>
vm "-script" "env.factor" 3array >>command
ascii <process-stream> contents
] with-directory eval
os-envs =
] unit-test
[ t ] [
"extra/io/windows/nt/launcher/test" resource-path [
<process>
vm "-script" "env.factor" 3array >>command
+replace-environment+ >>environment-mode
os-envs >>environment
ascii <process-stream> contents
] with-directory eval
os-envs =
] unit-test
[ "B" ] [
"extra/io/windows/nt/launcher/test" resource-path [
<process>
vm "-script" "env.factor" 3array >>command
{ { "A" "B" } } >>environment
ascii <process-stream> contents
] with-directory eval
"A" swap at
] unit-test
[ f ] [
"extra/io/windows/nt/launcher/test" resource-path [
<process>
vm "-script" "env.factor" 3array >>command
{ { "HOME" "XXX" } } >>environment
+prepend-environment+ >>environment-mode
ascii <process-stream> contents
] with-directory eval
"HOME" swap at "XXX" =
] unit-test

View File

@ -5,7 +5,7 @@ io.windows libc io.nonblocking io.streams.duplex windows.types
math windows.kernel32 windows namespaces io.launcher kernel
sequences windows.errors assocs splitting system strings
io.windows.launcher io.windows.nt.pipes io.backend
combinators shuffle ;
combinators shuffle accessors locals ;
IN: io.windows.nt.launcher
: duplicate-handle ( handle -- handle' )
@ -31,13 +31,12 @@ IN: io.windows.nt.launcher
: redirect-closed ( default obj access-mode create-mode -- handle )
drop 2nip null-pipe ;
: redirect-file ( default path access-mode create-mode -- handle )
>r >r >r drop r>
normalize-pathname
r> ! access-mode
:: redirect-file ( default path access-mode create-mode -- handle )
path normalize-pathname
access-mode
share-mode
security-attributes-inherit
r> ! create-mode
create-mode
FILE_ATTRIBUTE_NORMAL ! flags and attributes
f ! template file
CreateFile dup invalid-handle? dup close-later ;
@ -60,24 +59,25 @@ IN: io.windows.nt.launcher
} cond ;
: default-stdout ( args -- handle )
CreateProcess-args-stdout-pipe dup [ pipe-out ] when ;
stdout-pipe>> dup [ pipe-out ] when ;
: redirect-stdout ( args -- handle )
: redirect-stdout ( process args -- handle )
default-stdout
+stdout+ get
swap stdout>>
GENERIC_WRITE
CREATE_ALWAYS
redirect
STD_OUTPUT_HANDLE GetStdHandle or ;
: redirect-stderr ( args -- handle )
+stderr+ get +stdout+ eq? [
CreateProcess-args-lpStartupInfo
: redirect-stderr ( process args -- handle )
over stderr>> +stdout+ eq? [
lpStartupInfo>>
STARTUPINFO-hStdOutput
nip
] [
drop
f
+stderr+ get
swap stderr>>
GENERIC_WRITE
CREATE_ALWAYS
redirect
@ -85,11 +85,11 @@ IN: io.windows.nt.launcher
] if ;
: default-stdin ( args -- handle )
CreateProcess-args-stdin-pipe dup [ pipe-in ] when ;
stdin-pipe>> dup [ pipe-in ] when ;
: redirect-stdin ( args -- handle )
: redirect-stdin ( process args -- handle )
default-stdin
+stdin+ get
swap stdin>>
GENERIC_READ
OPEN_EXISTING
redirect
@ -97,48 +97,42 @@ IN: io.windows.nt.launcher
: add-pipe-dtors ( pipe -- )
dup
pipe-in close-later
pipe-out close-later ;
in>> close-later
out>> close-later ;
: fill-stdout-pipe
: fill-stdout-pipe ( args -- args )
<unique-incoming-pipe>
dup add-pipe-dtors
dup pipe-in f set-inherit
over set-CreateProcess-args-stdout-pipe ;
>>stdout-pipe ;
: fill-stdin-pipe
: fill-stdin-pipe ( args -- args )
<unique-outgoing-pipe>
dup add-pipe-dtors
dup pipe-out f set-inherit
over set-CreateProcess-args-stdin-pipe ;
>>stdin-pipe ;
M: windows-nt-io fill-redirection
dup CreateProcess-args-lpStartupInfo
over redirect-stdout over set-STARTUPINFO-hStdOutput
over redirect-stderr over set-STARTUPINFO-hStdError
over redirect-stdin over set-STARTUPINFO-hStdInput
drop ;
M: windows-nt-io fill-redirection ( process args -- )
[ 2dup redirect-stdout ] keep lpStartupInfo>> set-STARTUPINFO-hStdOutput
[ 2dup redirect-stderr ] keep lpStartupInfo>> set-STARTUPINFO-hStdError
[ 2dup redirect-stdin ] keep lpStartupInfo>> set-STARTUPINFO-hStdInput
2drop ;
M: windows-nt-io (process-stream)
[
[
make-CreateProcess-args
dup make-CreateProcess-args
fill-stdout-pipe
fill-stdin-pipe
fill-stdout-pipe
fill-stdin-pipe
fill-redirection
tuck fill-redirection
dup call-CreateProcess
dup call-CreateProcess
dup CreateProcess-args-stdin-pipe pipe-in CloseHandle drop
dup CreateProcess-args-stdout-pipe pipe-out CloseHandle drop
dup stdin-pipe>> pipe-in CloseHandle drop
dup stdout-pipe>> pipe-out CloseHandle drop
dup CreateProcess-args-stdout-pipe pipe-in
over CreateProcess-args-stdin-pipe pipe-out
[ f <win32-file> ] 2apply <reader&writer>
rot CreateProcess-args-lpProcessInformation <process>
] with-destructors
] with-descriptor ;
dup lpProcessInformation>>
over stdout-pipe>> in>> f <win32-file>
rot stdin-pipe>> out>> f <win32-file>
] with-destructors ;

View File

@ -0,0 +1,3 @@
USE: system
USE: prettyprint
os-envs .

View File

@ -0,0 +1,5 @@
USE: io
USE: namespaces
"output" write flush
"error" stderr get stream-write stderr get stream-flush

View File

@ -3,7 +3,7 @@
USING: alien alien.c-types arrays destructors io io.windows libc
windows.types math windows.kernel32 windows namespaces kernel
sequences windows.errors assocs math.parser system random
combinators ;
combinators new-slots accessors ;
IN: io.windows.nt.pipes
! This code is based on
@ -42,8 +42,8 @@ TUPLE: pipe in out ;
: close-pipe ( pipe -- )
dup
pipe-in CloseHandle drop
pipe-out CloseHandle drop ;
in>> CloseHandle drop
out>> CloseHandle drop ;
: <incoming-pipe> ( name -- pipe )
PIPE_ACCESS_INBOUND GENERIC_WRITE <pipe> ;
@ -70,13 +70,13 @@ TUPLE: pipe in out ;
! /dev/null simulation
: null-input ( -- pipe )
<unique-outgoing-pipe>
dup pipe-out CloseHandle drop
pipe-in ;
dup out>> CloseHandle drop
in>> ;
: null-output ( -- pipe )
<unique-incoming-pipe>
dup pipe-in CloseHandle drop
pipe-out ;
dup in>> CloseHandle drop
out>> ;
: null-pipe ( mode -- pipe )
{