##// END OF EJS Templates
Merge pull request #13242 from Kojoley/remove-unused-_find_cmd...
Matthias Bussonnier -
r26994:76b369ef merge
parent child Browse files
Show More
@@ -1,78 +1,70
1 """cli-specific implementation of process utilities.
1 """cli-specific implementation of process utilities.
2
2
3 cli - Common Language Infrastructure for IronPython. Code
3 cli - Common Language Infrastructure for IronPython. Code
4 can run on any operating system. Check os.name for os-
4 can run on any operating system. Check os.name for os-
5 specific settings.
5 specific settings.
6
6
7 This file is only meant to be imported by process.py, not by end-users.
7 This file is only meant to be imported by process.py, not by end-users.
8
8
9 This file is largely untested. To become a full drop-in process
9 This file is largely untested. To become a full drop-in process
10 interface for IronPython will probably require you to help fill
10 interface for IronPython will probably require you to help fill
11 in the details.
11 in the details.
12 """
12 """
13
13
14 # Import cli libraries:
14 # Import cli libraries:
15 import clr
15 import clr
16 import System
16 import System
17
17
18 # Import Python libraries:
18 # Import Python libraries:
19 import os
19 import os
20
20
21 # Import IPython libraries:
21 # Import IPython libraries:
22 from IPython.utils import py3compat
22 from IPython.utils import py3compat
23 from ._process_common import arg_split
23 from ._process_common import arg_split
24
24
25 def _find_cmd(cmd):
26 """Find the full path to a command using which."""
27 paths = System.Environment.GetEnvironmentVariable("PATH").Split(os.pathsep)
28 for path in paths:
29 filename = os.path.join(path, cmd)
30 if System.IO.File.Exists(filename):
31 return py3compat.decode(filename)
32 raise OSError("command %r not found" % cmd)
33
25
34 def system(cmd):
26 def system(cmd):
35 """
27 """
36 system(cmd) should work in a cli environment on Mac OSX, Linux,
28 system(cmd) should work in a cli environment on Mac OSX, Linux,
37 and Windows
29 and Windows
38 """
30 """
39 psi = System.Diagnostics.ProcessStartInfo(cmd)
31 psi = System.Diagnostics.ProcessStartInfo(cmd)
40 psi.RedirectStandardOutput = True
32 psi.RedirectStandardOutput = True
41 psi.RedirectStandardError = True
33 psi.RedirectStandardError = True
42 psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
34 psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
43 psi.UseShellExecute = False
35 psi.UseShellExecute = False
44 # Start up process:
36 # Start up process:
45 reg = System.Diagnostics.Process.Start(psi)
37 reg = System.Diagnostics.Process.Start(psi)
46
38
47 def getoutput(cmd):
39 def getoutput(cmd):
48 """
40 """
49 getoutput(cmd) should work in a cli environment on Mac OSX, Linux,
41 getoutput(cmd) should work in a cli environment on Mac OSX, Linux,
50 and Windows
42 and Windows
51 """
43 """
52 psi = System.Diagnostics.ProcessStartInfo(cmd)
44 psi = System.Diagnostics.ProcessStartInfo(cmd)
53 psi.RedirectStandardOutput = True
45 psi.RedirectStandardOutput = True
54 psi.RedirectStandardError = True
46 psi.RedirectStandardError = True
55 psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
47 psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
56 psi.UseShellExecute = False
48 psi.UseShellExecute = False
57 # Start up process:
49 # Start up process:
58 reg = System.Diagnostics.Process.Start(psi)
50 reg = System.Diagnostics.Process.Start(psi)
59 myOutput = reg.StandardOutput
51 myOutput = reg.StandardOutput
60 output = myOutput.ReadToEnd()
52 output = myOutput.ReadToEnd()
61 myError = reg.StandardError
53 myError = reg.StandardError
62 error = myError.ReadToEnd()
54 error = myError.ReadToEnd()
63 return output
55 return output
64
56
65 def check_pid(pid):
57 def check_pid(pid):
66 """
58 """
67 Check if a process with the given PID (pid) exists
59 Check if a process with the given PID (pid) exists
68 """
60 """
69 try:
61 try:
70 System.Diagnostics.Process.GetProcessById(pid)
62 System.Diagnostics.Process.GetProcessById(pid)
71 # process with given pid is running
63 # process with given pid is running
72 return True
64 return True
73 except System.InvalidOperationException:
65 except System.InvalidOperationException:
74 # process wasn't started by this object (but is running)
66 # process wasn't started by this object (but is running)
75 return True
67 return True
76 except System.ArgumentException:
68 except System.ArgumentException:
77 # process with given pid isn't running
69 # process with given pid isn't running
78 return False
70 return False
@@ -1,225 +1,217
1 """Posix-specific implementation of process utilities.
1 """Posix-specific implementation of process utilities.
2
2
3 This file is only meant to be imported by process.py, not by end-users.
3 This file is only meant to be imported by process.py, not by end-users.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2010-2011 The IPython Development Team
7 # Copyright (C) 2010-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 # Stdlib
17 # Stdlib
18 import errno
18 import errno
19 import os
19 import os
20 import subprocess as sp
20 import subprocess as sp
21 import sys
21 import sys
22
22
23 import pexpect
23 import pexpect
24
24
25 # Our own
25 # Our own
26 from ._process_common import getoutput, arg_split
26 from ._process_common import getoutput, arg_split
27 from IPython.utils import py3compat
27 from IPython.utils import py3compat
28 from IPython.utils.encoding import DEFAULT_ENCODING
28 from IPython.utils.encoding import DEFAULT_ENCODING
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Function definitions
31 # Function definitions
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33
33
34 def _find_cmd(cmd):
35 """Find the full path to a command using which."""
36
37 path = sp.Popen(['/usr/bin/env', 'which', cmd],
38 stdout=sp.PIPE, stderr=sp.PIPE).communicate()[0]
39 return py3compat.decode(path)
40
41
42 class ProcessHandler(object):
34 class ProcessHandler(object):
43 """Execute subprocesses under the control of pexpect.
35 """Execute subprocesses under the control of pexpect.
44 """
36 """
45 # Timeout in seconds to wait on each reading of the subprocess' output.
37 # Timeout in seconds to wait on each reading of the subprocess' output.
46 # This should not be set too low to avoid cpu overusage from our side,
38 # This should not be set too low to avoid cpu overusage from our side,
47 # since we read in a loop whose period is controlled by this timeout.
39 # since we read in a loop whose period is controlled by this timeout.
48 read_timeout = 0.05
40 read_timeout = 0.05
49
41
50 # Timeout to give a process if we receive SIGINT, between sending the
42 # Timeout to give a process if we receive SIGINT, between sending the
51 # SIGINT to the process and forcefully terminating it.
43 # SIGINT to the process and forcefully terminating it.
52 terminate_timeout = 0.2
44 terminate_timeout = 0.2
53
45
54 # File object where stdout and stderr of the subprocess will be written
46 # File object where stdout and stderr of the subprocess will be written
55 logfile = None
47 logfile = None
56
48
57 # Shell to call for subprocesses to execute
49 # Shell to call for subprocesses to execute
58 _sh = None
50 _sh = None
59
51
60 @property
52 @property
61 def sh(self):
53 def sh(self):
62 if self._sh is None:
54 if self._sh is None:
63 shell_name = os.environ.get("SHELL", "sh")
55 shell_name = os.environ.get("SHELL", "sh")
64 self._sh = pexpect.which(shell_name)
56 self._sh = pexpect.which(shell_name)
65 if self._sh is None:
57 if self._sh is None:
66 raise OSError('"{}" shell not found'.format(shell_name))
58 raise OSError('"{}" shell not found'.format(shell_name))
67
59
68 return self._sh
60 return self._sh
69
61
70 def __init__(self, logfile=None, read_timeout=None, terminate_timeout=None):
62 def __init__(self, logfile=None, read_timeout=None, terminate_timeout=None):
71 """Arguments are used for pexpect calls."""
63 """Arguments are used for pexpect calls."""
72 self.read_timeout = (ProcessHandler.read_timeout if read_timeout is
64 self.read_timeout = (ProcessHandler.read_timeout if read_timeout is
73 None else read_timeout)
65 None else read_timeout)
74 self.terminate_timeout = (ProcessHandler.terminate_timeout if
66 self.terminate_timeout = (ProcessHandler.terminate_timeout if
75 terminate_timeout is None else
67 terminate_timeout is None else
76 terminate_timeout)
68 terminate_timeout)
77 self.logfile = sys.stdout if logfile is None else logfile
69 self.logfile = sys.stdout if logfile is None else logfile
78
70
79 def getoutput(self, cmd):
71 def getoutput(self, cmd):
80 """Run a command and return its stdout/stderr as a string.
72 """Run a command and return its stdout/stderr as a string.
81
73
82 Parameters
74 Parameters
83 ----------
75 ----------
84 cmd : str
76 cmd : str
85 A command to be executed in the system shell.
77 A command to be executed in the system shell.
86
78
87 Returns
79 Returns
88 -------
80 -------
89 output : str
81 output : str
90 A string containing the combination of stdout and stderr from the
82 A string containing the combination of stdout and stderr from the
91 subprocess, in whatever order the subprocess originally wrote to its
83 subprocess, in whatever order the subprocess originally wrote to its
92 file descriptors (so the order of the information in this string is the
84 file descriptors (so the order of the information in this string is the
93 correct order as would be seen if running the command in a terminal).
85 correct order as would be seen if running the command in a terminal).
94 """
86 """
95 try:
87 try:
96 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
88 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
97 except KeyboardInterrupt:
89 except KeyboardInterrupt:
98 print('^C', file=sys.stderr, end='')
90 print('^C', file=sys.stderr, end='')
99
91
100 def getoutput_pexpect(self, cmd):
92 def getoutput_pexpect(self, cmd):
101 """Run a command and return its stdout/stderr as a string.
93 """Run a command and return its stdout/stderr as a string.
102
94
103 Parameters
95 Parameters
104 ----------
96 ----------
105 cmd : str
97 cmd : str
106 A command to be executed in the system shell.
98 A command to be executed in the system shell.
107
99
108 Returns
100 Returns
109 -------
101 -------
110 output : str
102 output : str
111 A string containing the combination of stdout and stderr from the
103 A string containing the combination of stdout and stderr from the
112 subprocess, in whatever order the subprocess originally wrote to its
104 subprocess, in whatever order the subprocess originally wrote to its
113 file descriptors (so the order of the information in this string is the
105 file descriptors (so the order of the information in this string is the
114 correct order as would be seen if running the command in a terminal).
106 correct order as would be seen if running the command in a terminal).
115 """
107 """
116 try:
108 try:
117 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
109 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
118 except KeyboardInterrupt:
110 except KeyboardInterrupt:
119 print('^C', file=sys.stderr, end='')
111 print('^C', file=sys.stderr, end='')
120
112
121 def system(self, cmd):
113 def system(self, cmd):
122 """Execute a command in a subshell.
114 """Execute a command in a subshell.
123
115
124 Parameters
116 Parameters
125 ----------
117 ----------
126 cmd : str
118 cmd : str
127 A command to be executed in the system shell.
119 A command to be executed in the system shell.
128
120
129 Returns
121 Returns
130 -------
122 -------
131 int : child's exitstatus
123 int : child's exitstatus
132 """
124 """
133 # Get likely encoding for the output.
125 # Get likely encoding for the output.
134 enc = DEFAULT_ENCODING
126 enc = DEFAULT_ENCODING
135
127
136 # Patterns to match on the output, for pexpect. We read input and
128 # Patterns to match on the output, for pexpect. We read input and
137 # allow either a short timeout or EOF
129 # allow either a short timeout or EOF
138 patterns = [pexpect.TIMEOUT, pexpect.EOF]
130 patterns = [pexpect.TIMEOUT, pexpect.EOF]
139 # the index of the EOF pattern in the list.
131 # the index of the EOF pattern in the list.
140 # even though we know it's 1, this call means we don't have to worry if
132 # even though we know it's 1, this call means we don't have to worry if
141 # we change the above list, and forget to change this value:
133 # we change the above list, and forget to change this value:
142 EOF_index = patterns.index(pexpect.EOF)
134 EOF_index = patterns.index(pexpect.EOF)
143 # The size of the output stored so far in the process output buffer.
135 # The size of the output stored so far in the process output buffer.
144 # Since pexpect only appends to this buffer, each time we print we
136 # Since pexpect only appends to this buffer, each time we print we
145 # record how far we've printed, so that next time we only print *new*
137 # record how far we've printed, so that next time we only print *new*
146 # content from the buffer.
138 # content from the buffer.
147 out_size = 0
139 out_size = 0
148 try:
140 try:
149 # Since we're not really searching the buffer for text patterns, we
141 # Since we're not really searching the buffer for text patterns, we
150 # can set pexpect's search window to be tiny and it won't matter.
142 # can set pexpect's search window to be tiny and it won't matter.
151 # We only search for the 'patterns' timeout or EOF, which aren't in
143 # We only search for the 'patterns' timeout or EOF, which aren't in
152 # the text itself.
144 # the text itself.
153 #child = pexpect.spawn(pcmd, searchwindowsize=1)
145 #child = pexpect.spawn(pcmd, searchwindowsize=1)
154 if hasattr(pexpect, 'spawnb'):
146 if hasattr(pexpect, 'spawnb'):
155 child = pexpect.spawnb(self.sh, args=['-c', cmd]) # Pexpect-U
147 child = pexpect.spawnb(self.sh, args=['-c', cmd]) # Pexpect-U
156 else:
148 else:
157 child = pexpect.spawn(self.sh, args=['-c', cmd]) # Vanilla Pexpect
149 child = pexpect.spawn(self.sh, args=['-c', cmd]) # Vanilla Pexpect
158 flush = sys.stdout.flush
150 flush = sys.stdout.flush
159 while True:
151 while True:
160 # res is the index of the pattern that caused the match, so we
152 # res is the index of the pattern that caused the match, so we
161 # know whether we've finished (if we matched EOF) or not
153 # know whether we've finished (if we matched EOF) or not
162 res_idx = child.expect_list(patterns, self.read_timeout)
154 res_idx = child.expect_list(patterns, self.read_timeout)
163 print(child.before[out_size:].decode(enc, 'replace'), end='')
155 print(child.before[out_size:].decode(enc, 'replace'), end='')
164 flush()
156 flush()
165 if res_idx==EOF_index:
157 if res_idx==EOF_index:
166 break
158 break
167 # Update the pointer to what we've already printed
159 # Update the pointer to what we've already printed
168 out_size = len(child.before)
160 out_size = len(child.before)
169 except KeyboardInterrupt:
161 except KeyboardInterrupt:
170 # We need to send ^C to the process. The ascii code for '^C' is 3
162 # We need to send ^C to the process. The ascii code for '^C' is 3
171 # (the character is known as ETX for 'End of Text', see
163 # (the character is known as ETX for 'End of Text', see
172 # curses.ascii.ETX).
164 # curses.ascii.ETX).
173 child.sendline(chr(3))
165 child.sendline(chr(3))
174 # Read and print any more output the program might produce on its
166 # Read and print any more output the program might produce on its
175 # way out.
167 # way out.
176 try:
168 try:
177 out_size = len(child.before)
169 out_size = len(child.before)
178 child.expect_list(patterns, self.terminate_timeout)
170 child.expect_list(patterns, self.terminate_timeout)
179 print(child.before[out_size:].decode(enc, 'replace'), end='')
171 print(child.before[out_size:].decode(enc, 'replace'), end='')
180 sys.stdout.flush()
172 sys.stdout.flush()
181 except KeyboardInterrupt:
173 except KeyboardInterrupt:
182 # Impatient users tend to type it multiple times
174 # Impatient users tend to type it multiple times
183 pass
175 pass
184 finally:
176 finally:
185 # Ensure the subprocess really is terminated
177 # Ensure the subprocess really is terminated
186 child.terminate(force=True)
178 child.terminate(force=True)
187 # add isalive check, to ensure exitstatus is set:
179 # add isalive check, to ensure exitstatus is set:
188 child.isalive()
180 child.isalive()
189
181
190 # We follow the subprocess pattern, returning either the exit status
182 # We follow the subprocess pattern, returning either the exit status
191 # as a positive number, or the terminating signal as a negative
183 # as a positive number, or the terminating signal as a negative
192 # number.
184 # number.
193 # on Linux, sh returns 128+n for signals terminating child processes on Linux
185 # on Linux, sh returns 128+n for signals terminating child processes on Linux
194 # on BSD (OS X), the signal code is set instead
186 # on BSD (OS X), the signal code is set instead
195 if child.exitstatus is None:
187 if child.exitstatus is None:
196 # on WIFSIGNALED, pexpect sets signalstatus, leaving exitstatus=None
188 # on WIFSIGNALED, pexpect sets signalstatus, leaving exitstatus=None
197 if child.signalstatus is None:
189 if child.signalstatus is None:
198 # this condition may never occur,
190 # this condition may never occur,
199 # but let's be certain we always return an integer.
191 # but let's be certain we always return an integer.
200 return 0
192 return 0
201 return -child.signalstatus
193 return -child.signalstatus
202 if child.exitstatus > 128:
194 if child.exitstatus > 128:
203 return -(child.exitstatus - 128)
195 return -(child.exitstatus - 128)
204 return child.exitstatus
196 return child.exitstatus
205
197
206
198
207 # Make system() with a functional interface for outside use. Note that we use
199 # Make system() with a functional interface for outside use. Note that we use
208 # getoutput() from the _common utils, which is built on top of popen(). Using
200 # getoutput() from the _common utils, which is built on top of popen(). Using
209 # pexpect to get subprocess output produces difficult to parse output, since
201 # pexpect to get subprocess output produces difficult to parse output, since
210 # programs think they are talking to a tty and produce highly formatted output
202 # programs think they are talking to a tty and produce highly formatted output
211 # (ls is a good example) that makes them hard.
203 # (ls is a good example) that makes them hard.
212 system = ProcessHandler().system
204 system = ProcessHandler().system
213
205
214 def check_pid(pid):
206 def check_pid(pid):
215 try:
207 try:
216 os.kill(pid, 0)
208 os.kill(pid, 0)
217 except OSError as err:
209 except OSError as err:
218 if err.errno == errno.ESRCH:
210 if err.errno == errno.ESRCH:
219 return False
211 return False
220 elif err.errno == errno.EPERM:
212 elif err.errno == errno.EPERM:
221 # Don't have permission to signal the process - probably means it exists
213 # Don't have permission to signal the process - probably means it exists
222 return True
214 return True
223 raise
215 raise
224 else:
216 else:
225 return True
217 return True
@@ -1,205 +1,184
1 """Windows-specific implementation of process utilities.
1 """Windows-specific implementation of process utilities.
2
2
3 This file is only meant to be imported by process.py, not by end-users.
3 This file is only meant to be imported by process.py, not by end-users.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2010-2011 The IPython Development Team
7 # Copyright (C) 2010-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 # stdlib
17 # stdlib
18 import os
18 import os
19 import sys
19 import sys
20 import ctypes
20 import ctypes
21 import time
21 import time
22
22
23 from ctypes import c_int, POINTER
23 from ctypes import c_int, POINTER
24 from ctypes.wintypes import LPCWSTR, HLOCAL
24 from ctypes.wintypes import LPCWSTR, HLOCAL
25 from subprocess import STDOUT, TimeoutExpired
25 from subprocess import STDOUT, TimeoutExpired
26 from threading import Thread
26 from threading import Thread
27
27
28 # our own imports
28 # our own imports
29 from ._process_common import read_no_interrupt, process_handler, arg_split as py_arg_split
29 from ._process_common import read_no_interrupt, process_handler, arg_split as py_arg_split
30 from . import py3compat
30 from . import py3compat
31 from .encoding import DEFAULT_ENCODING
31 from .encoding import DEFAULT_ENCODING
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Function definitions
34 # Function definitions
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37 class AvoidUNCPath(object):
37 class AvoidUNCPath(object):
38 """A context manager to protect command execution from UNC paths.
38 """A context manager to protect command execution from UNC paths.
39
39
40 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
40 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
41 This context manager temporarily changes directory to the 'C:' drive on
41 This context manager temporarily changes directory to the 'C:' drive on
42 entering, and restores the original working directory on exit.
42 entering, and restores the original working directory on exit.
43
43
44 The context manager returns the starting working directory *if* it made a
44 The context manager returns the starting working directory *if* it made a
45 change and None otherwise, so that users can apply the necessary adjustment
45 change and None otherwise, so that users can apply the necessary adjustment
46 to their system calls in the event of a change.
46 to their system calls in the event of a change.
47
47
48 Examples
48 Examples
49 --------
49 --------
50 ::
50 ::
51 cmd = 'dir'
51 cmd = 'dir'
52 with AvoidUNCPath() as path:
52 with AvoidUNCPath() as path:
53 if path is not None:
53 if path is not None:
54 cmd = '"pushd %s &&"%s' % (path, cmd)
54 cmd = '"pushd %s &&"%s' % (path, cmd)
55 os.system(cmd)
55 os.system(cmd)
56 """
56 """
57 def __enter__(self):
57 def __enter__(self):
58 self.path = os.getcwd()
58 self.path = os.getcwd()
59 self.is_unc_path = self.path.startswith(r"\\")
59 self.is_unc_path = self.path.startswith(r"\\")
60 if self.is_unc_path:
60 if self.is_unc_path:
61 # change to c drive (as cmd.exe cannot handle UNC addresses)
61 # change to c drive (as cmd.exe cannot handle UNC addresses)
62 os.chdir("C:")
62 os.chdir("C:")
63 return self.path
63 return self.path
64 else:
64 else:
65 # We return None to signal that there was no change in the working
65 # We return None to signal that there was no change in the working
66 # directory
66 # directory
67 return None
67 return None
68
68
69 def __exit__(self, exc_type, exc_value, traceback):
69 def __exit__(self, exc_type, exc_value, traceback):
70 if self.is_unc_path:
70 if self.is_unc_path:
71 os.chdir(self.path)
71 os.chdir(self.path)
72
72
73
73
74 def _find_cmd(cmd):
75 """Find the full path to a .bat or .exe using the win32api module."""
76 try:
77 from win32api import SearchPath
78 except ImportError as e:
79 raise ImportError('you need to have pywin32 installed for this to work') from e
80 else:
81 PATH = os.environ['PATH']
82 extensions = ['.exe', '.com', '.bat', '.py']
83 path = None
84 for ext in extensions:
85 try:
86 path = SearchPath(PATH, cmd, ext)[0]
87 except:
88 pass
89 if path is None:
90 raise OSError("command %r not found" % cmd)
91 else:
92 return path
93
94
95 def _system_body(p):
74 def _system_body(p):
96 """Callback for _system."""
75 """Callback for _system."""
97 enc = DEFAULT_ENCODING
76 enc = DEFAULT_ENCODING
98
77
99 def stdout_read():
78 def stdout_read():
100 for line in read_no_interrupt(p.stdout).splitlines():
79 for line in read_no_interrupt(p.stdout).splitlines():
101 line = line.decode(enc, 'replace')
80 line = line.decode(enc, 'replace')
102 print(line, file=sys.stdout)
81 print(line, file=sys.stdout)
103
82
104 def stderr_read():
83 def stderr_read():
105 for line in read_no_interrupt(p.stderr).splitlines():
84 for line in read_no_interrupt(p.stderr).splitlines():
106 line = line.decode(enc, 'replace')
85 line = line.decode(enc, 'replace')
107 print(line, file=sys.stderr)
86 print(line, file=sys.stderr)
108
87
109 Thread(target=stdout_read).start()
88 Thread(target=stdout_read).start()
110 Thread(target=stderr_read).start()
89 Thread(target=stderr_read).start()
111
90
112 # Wait to finish for returncode. Unfortunately, Python has a bug where
91 # Wait to finish for returncode. Unfortunately, Python has a bug where
113 # wait() isn't interruptible (https://bugs.python.org/issue28168) so poll in
92 # wait() isn't interruptible (https://bugs.python.org/issue28168) so poll in
114 # a loop instead of just doing `return p.wait()`.
93 # a loop instead of just doing `return p.wait()`.
115 while True:
94 while True:
116 result = p.poll()
95 result = p.poll()
117 if result is None:
96 if result is None:
118 time.sleep(0.01)
97 time.sleep(0.01)
119 else:
98 else:
120 return result
99 return result
121
100
122
101
123 def system(cmd):
102 def system(cmd):
124 """Win32 version of os.system() that works with network shares.
103 """Win32 version of os.system() that works with network shares.
125
104
126 Note that this implementation returns None, as meant for use in IPython.
105 Note that this implementation returns None, as meant for use in IPython.
127
106
128 Parameters
107 Parameters
129 ----------
108 ----------
130 cmd : str or list
109 cmd : str or list
131 A command to be executed in the system shell.
110 A command to be executed in the system shell.
132
111
133 Returns
112 Returns
134 -------
113 -------
135 int : child process' exit code.
114 int : child process' exit code.
136 """
115 """
137 # The controller provides interactivity with both
116 # The controller provides interactivity with both
138 # stdin and stdout
117 # stdin and stdout
139 #import _process_win32_controller
118 #import _process_win32_controller
140 #_process_win32_controller.system(cmd)
119 #_process_win32_controller.system(cmd)
141
120
142 with AvoidUNCPath() as path:
121 with AvoidUNCPath() as path:
143 if path is not None:
122 if path is not None:
144 cmd = '"pushd %s &&"%s' % (path, cmd)
123 cmd = '"pushd %s &&"%s' % (path, cmd)
145 return process_handler(cmd, _system_body)
124 return process_handler(cmd, _system_body)
146
125
147 def getoutput(cmd):
126 def getoutput(cmd):
148 """Return standard output of executing cmd in a shell.
127 """Return standard output of executing cmd in a shell.
149
128
150 Accepts the same arguments as os.system().
129 Accepts the same arguments as os.system().
151
130
152 Parameters
131 Parameters
153 ----------
132 ----------
154 cmd : str or list
133 cmd : str or list
155 A command to be executed in the system shell.
134 A command to be executed in the system shell.
156
135
157 Returns
136 Returns
158 -------
137 -------
159 stdout : str
138 stdout : str
160 """
139 """
161
140
162 with AvoidUNCPath() as path:
141 with AvoidUNCPath() as path:
163 if path is not None:
142 if path is not None:
164 cmd = '"pushd %s &&"%s' % (path, cmd)
143 cmd = '"pushd %s &&"%s' % (path, cmd)
165 out = process_handler(cmd, lambda p: p.communicate()[0], STDOUT)
144 out = process_handler(cmd, lambda p: p.communicate()[0], STDOUT)
166
145
167 if out is None:
146 if out is None:
168 out = b''
147 out = b''
169 return py3compat.decode(out)
148 return py3compat.decode(out)
170
149
171 try:
150 try:
172 CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
151 CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW
173 CommandLineToArgvW.arg_types = [LPCWSTR, POINTER(c_int)]
152 CommandLineToArgvW.arg_types = [LPCWSTR, POINTER(c_int)]
174 CommandLineToArgvW.restype = POINTER(LPCWSTR)
153 CommandLineToArgvW.restype = POINTER(LPCWSTR)
175 LocalFree = ctypes.windll.kernel32.LocalFree
154 LocalFree = ctypes.windll.kernel32.LocalFree
176 LocalFree.res_type = HLOCAL
155 LocalFree.res_type = HLOCAL
177 LocalFree.arg_types = [HLOCAL]
156 LocalFree.arg_types = [HLOCAL]
178
157
179 def arg_split(commandline, posix=False, strict=True):
158 def arg_split(commandline, posix=False, strict=True):
180 """Split a command line's arguments in a shell-like manner.
159 """Split a command line's arguments in a shell-like manner.
181
160
182 This is a special version for windows that use a ctypes call to CommandLineToArgvW
161 This is a special version for windows that use a ctypes call to CommandLineToArgvW
183 to do the argv splitting. The posix parameter is ignored.
162 to do the argv splitting. The posix parameter is ignored.
184
163
185 If strict=False, process_common.arg_split(...strict=False) is used instead.
164 If strict=False, process_common.arg_split(...strict=False) is used instead.
186 """
165 """
187 #CommandLineToArgvW returns path to executable if called with empty string.
166 #CommandLineToArgvW returns path to executable if called with empty string.
188 if commandline.strip() == "":
167 if commandline.strip() == "":
189 return []
168 return []
190 if not strict:
169 if not strict:
191 # not really a cl-arg, fallback on _process_common
170 # not really a cl-arg, fallback on _process_common
192 return py_arg_split(commandline, posix=posix, strict=strict)
171 return py_arg_split(commandline, posix=posix, strict=strict)
193 argvn = c_int()
172 argvn = c_int()
194 result_pointer = CommandLineToArgvW(py3compat.cast_unicode(commandline.lstrip()), ctypes.byref(argvn))
173 result_pointer = CommandLineToArgvW(py3compat.cast_unicode(commandline.lstrip()), ctypes.byref(argvn))
195 result_array_type = LPCWSTR * argvn.value
174 result_array_type = LPCWSTR * argvn.value
196 result = [arg for arg in result_array_type.from_address(ctypes.addressof(result_pointer.contents))]
175 result = [arg for arg in result_array_type.from_address(ctypes.addressof(result_pointer.contents))]
197 retval = LocalFree(result_pointer)
176 retval = LocalFree(result_pointer)
198 return result
177 return result
199 except AttributeError:
178 except AttributeError:
200 arg_split = py_arg_split
179 arg_split = py_arg_split
201
180
202 def check_pid(pid):
181 def check_pid(pid):
203 # OpenProcess returns 0 if no such process (of ours) exists
182 # OpenProcess returns 0 if no such process (of ours) exists
204 # positive int otherwise
183 # positive int otherwise
205 return bool(ctypes.windll.kernel32.OpenProcess(1,0,pid))
184 return bool(ctypes.windll.kernel32.OpenProcess(1,0,pid))
General Comments 0
You need to be logged in to leave comments. Login now