11 # Alias Python2 exception to Python3
12 InterruptedError
= select
.error
14 if sys
.version_info
[0] >= 3:
17 string_types
= (unicode, str)
20 def is_executable_file(path
):
21 """Checks that path is an executable regular file, or a symlink towards one.
23 This is roughly ``os.path isfile(path) and os.access(path, os.X_OK)``.
26 fpath
= os
.path
.realpath(path
)
28 if not os
.path
.isfile(fpath
):
29 # non-files (directories, fifo, etc.)
32 mode
= os
.stat(fpath
).st_mode
34 if (sys
.platform
.startswith('sunos')
35 and os
.getuid() == 0):
36 # When root on Solaris, os.X_OK is True for *all* files, irregardless
37 # of their executability -- instead, any permission bit of any user,
38 # group, or other is fine enough.
40 # (This may be true for other "Unix98" OS's such as HP-UX and AIX)
41 return bool(mode
& (stat
.S_IXUSR |
45 return os
.access(fpath
, os
.X_OK
)
48 def which(filename
, env
=None):
49 '''This takes a given filename; tries to find it in the environment path;
50 then checks if it is executable. This returns the full path to the filename
51 if found and executable. Otherwise this returns None.'''
53 # Special case where filename contains an explicit path.
54 if os
.path
.dirname(filename
) != '' and is_executable_file(filename
):
61 pathlist
= p
.split(os
.pathsep
)
63 ff
= os
.path
.join(path
, filename
)
64 if is_executable_file(ff
):
69 def split_command_line(command_line
):
71 '''This splits a command line into a list of arguments. It splits arguments
72 on spaces, but handles embedded quotes, doublequotes, and escaped
73 characters. It's impossible to do this with a regular expression, so I
74 wrote a little state machine to parse the command line. '''
79 # Constants to name the states we can be in.
84 # The state when consuming whitespace between commands.
88 for c
in command_line
:
89 if state
== state_basic
or state
== state_whitespace
:
91 # Escape the next character
95 state
= state_singlequote
98 state
= state_doublequote
100 # Add arg to arg_list if we aren't in the middle of whitespace.
101 if state
== state_whitespace
:
107 state
= state_whitespace
111 elif state
== state_esc
:
114 elif state
== state_singlequote
:
119 elif state
== state_doublequote
:
130 def select_ignore_interrupts(iwtd
, owtd
, ewtd
, timeout
=None):
132 '''This is a wrapper around select.select() that ignores signals. If
133 select.select raises a select.error exception and errno is an EINTR
134 error then it is ignored. Mainly this is used to ignore sigwinch
135 (terminal resize). '''
137 # if select() is interrupted by a signal (errno==EINTR) then
138 # we loop back and enter the select() again.
139 if timeout
is not None:
140 end_time
= time
.time() + timeout
143 return select
.select(iwtd
, owtd
, ewtd
, timeout
)
144 except InterruptedError
:
145 err
= sys
.exc_info()[1]
146 if err
.args
[0] == errno
.EINTR
:
147 # if we loop back we have to subtract the
148 # amount of time we already waited.
149 if timeout
is not None:
150 timeout
= end_time
- time
.time()
154 # something else caused the select.error, so
155 # this actually is an exception.
159 def poll_ignore_interrupts(fds
, timeout
=None):
160 '''Simple wrapper around poll to register file descriptors and
163 if timeout
is not None:
164 end_time
= time
.time() + timeout
166 poller
= select
.poll()
168 poller
.register(fd
, select
.POLLIN | select
.POLLPRI | select
.POLLHUP | select
.POLLERR
)
172 timeout_ms
= None if timeout
is None else timeout
* 1000
173 results
= poller
.poll(timeout_ms
)
174 return [afd
for afd
, _
in results
]
175 except InterruptedError
:
176 err
= sys
.exc_info()[1]
177 if err
.args
[0] == errno
.EINTR
:
178 # if we loop back we have to subtract the
179 # amount of time we already waited.
180 if timeout
is not None:
181 timeout
= end_time
- time
.time()
185 # something else caused the select.error, so
186 # this actually is an exception.