1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 =================
19 Shell utilities
20 =================
21
22 Shell utilities.
23 """
24 from __future__ import generators
25
26 __author__ = u"Andr\xe9 Malo"
27 __docformat__ = "restructuredtext en"
28
29 import errno as _errno
30 import fnmatch as _fnmatch
31 import os as _os
32 import shutil as _shutil
33 import sys as _sys
34 import tempfile as _tempfile
35
36 cwd = _os.path.dirname(_os.path.abspath(_sys.argv[0]))
37
39 """ Exit error """
41 RuntimeError.__init__(self, code)
42 self.code = code
43 self.signal = None
44
45
47 """ Signal error """
49 ExitError.__init__(self, code)
50 import signal as _signal
51 self.signal = signal
52 for key, val in vars(_signal).iteritems():
53 if key.startswith('SIG') and not key.startswith('SIG_'):
54 if val == signal:
55 self.signalstr = key[3:]
56 break
57 else:
58 self.signalstr = '%04d' % signal
59
60
62 """ Convert slash path to native """
63 path = _os.path.join(*path.split('/'))
64 return _os.path.normpath(_os.path.join(cwd, path))
65
66
68 """ Copy src to dest """
69 _shutil.copy2(native(src), native(dest))
70
71
73 """ Copy -r src to dest """
74 _shutil.copytree(native(src), native(dest))
75
76
78 """ Remove a file """
79 try:
80 _os.unlink(native(dest))
81 except OSError, e:
82 if _errno.ENOENT != e.errno:
83 raise
84
86 """ Remove a tree """
87 dest = native(dest)
88 if _os.path.exists(dest):
89 for path in files(dest, '*'):
90 _os.chmod(native(path), 0644)
91 _shutil.rmtree(dest)
92
93
94 try:
95 mkstemp = _tempfile.mkstemp
96 except AttributeError:
97
98 try:
99 import fcntl as _fcntl
100 except ImportError:
102 """ Set close-on-exec (not implemented, but not an error) """
103
104 pass
105 else:
107 """ Set close-on-exec """
108 try:
109 flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
110 except IOError:
111 pass
112 else:
113
114 flags |= _fcntl.FD_CLOEXEC
115 _fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
116
117 _text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
118 _text_openflags |= getattr(_os, 'O_NOINHERIT', 0)
119 _text_openflags |= getattr(_os, 'O_NOFOLLOW', 0)
120
121 _bin_openflags = _text_openflags
122 _bin_openflags |= getattr(_os, 'O_BINARY', 0)
123
124 - def mkstemp(suffix="", prefix=_tempfile.gettempprefix(), dir=None,
125 text=False):
126 """ Create secure temp file """
127
128 if dir is None:
129 dir = _tempfile.gettempdir()
130 if text:
131 flags = _text_openflags
132 else:
133 flags = _bin_openflags
134 count = 100
135 while count > 0:
136 j = _tempfile._counter.get_next()
137 fname = _os.path.join(dir, prefix + str(j) + suffix)
138 try:
139 fd = _os.open(fname, flags, 0600)
140 except OSError, e:
141 if e.errno == _errno.EEXIST:
142 count -= 1
143 continue
144 raise
145 _set_cloexec(fd)
146 return fd, _os.path.abspath(fname)
147 raise IOError, (_errno.EEXIST, "No usable temporary file name found")
148
149
151 """ Pipe spawn """
152
153 import pickle as _pickle
154 fd, name = mkstemp('.py')
155 try:
156 _os.write(fd, (r"""
157 import os
158 import pickle
159 import sys
160
161 argv = pickle.loads(%(argv)s)
162 env = pickle.loads(%(env)s)
163
164 pid = os.spawnve(os.P_NOWAIT, argv[0], argv, env)
165 result = os.waitpid(pid, 0)[1]
166 if result == 0:
167 sys.exit(0)
168 signalled = getattr(os, 'WIFSIGNALED', None)
169 if signalled is not None:
170 if signalled(result):
171 print "\n%%d %%d" %% (os.WTERMSIG(result), result & 7)
172 sys.exit(2)
173 print "\n%%d" %% (result & 7,)
174 sys.exit(3)
175 """.strip() + "\n") % {
176 'argv': repr(_pickle.dumps(argv)),
177 'env': repr(_pickle.dumps(env)),
178 })
179 fd, _ = None, _os.close(fd)
180 if _sys.platform == 'win32':
181 argv = []
182 for arg in [_sys.executable, name]:
183 if ' ' in arg or arg.startswith('"'):
184 arg = '"%s"' % arg.replace('"', '\\"')
185 argv.append(arg)
186 argv = ' '.join(argv)
187 shell = True
188 close_fds = False
189 else:
190 argv = [_sys.executable, name]
191 shell = False
192 close_fds = True
193
194 res = 0
195 try:
196 import subprocess
197 except ImportError:
198 import popen2 as _popen2
199 proc = _popen2.Popen3(argv, False)
200 try:
201 proc.tochild.close()
202 result = proc.fromchild.read()
203 finally:
204 res = proc.wait()
205 else:
206 proc = subprocess.Popen(argv,
207 shell=shell,
208 stdin=subprocess.PIPE,
209 stdout=subprocess.PIPE,
210 close_fds=close_fds,
211 )
212 try:
213 proc.stdin.close()
214 result = proc.stdout.read()
215 finally:
216 res = proc.wait()
217 if res != 0:
218 if res == 2:
219 signal, code = map(int, result.splitlines()[-1].split())
220 raise SignalError(signal, code)
221 elif res == 3:
222 code = int(result.splitlines()[-1].strip())
223 raise ExitError(code)
224 raise ExitError(res)
225
226 return result
227 finally:
228 try:
229 if fd is not None:
230 _os.close(fd)
231 finally:
232 _os.unlink(name)
233
234
236 """ File Pipe spawn """
237 import pickle as _pickle
238 fd, name = mkstemp('.py')
239 try:
240 _os.write(fd, ("""
241 import os
242 import pickle
243 import sys
244
245 infile = pickle.loads(%(infile)s)
246 outfile = pickle.loads(%(outfile)s)
247 argv = pickle.loads(%(argv)s)
248 env = pickle.loads(%(env)s)
249
250 if infile is not None:
251 infile = file(infile, 'rb')
252 os.dup2(infile.fileno(), 0)
253 infile.close()
254 if outfile is not None:
255 outfile = file(outfile, 'wb')
256 os.dup2(outfile.fileno(), 1)
257 outfile.close()
258
259 pid = os.spawnve(os.P_NOWAIT, argv[0], argv, env)
260 result = os.waitpid(pid, 0)[1]
261 sys.exit(result & 7)
262 """.strip() + "\n") % {
263 'infile': repr(_pickle.dumps(_os.path.abspath(infile))),
264 'outfile': repr(_pickle.dumps(_os.path.abspath(outfile))),
265 'argv': repr(_pickle.dumps(argv)),
266 'env': repr(_pickle.dumps(env)),
267 })
268 fd, _ = None, _os.close(fd)
269 if _sys.platform == 'win32':
270 argv = []
271 for arg in [_sys.executable, name]:
272 if ' ' in arg or arg.startswith('"'):
273 arg = '"%s"' % arg.replace('"', '\\"')
274 argv.append(arg)
275 argv = ' '.join(argv)
276 else:
277 argv = [_sys.executable, name]
278
279 pid = _os.spawnve(_os.P_NOWAIT, argv[0], argv, env)
280 return _os.waitpid(pid, 0)[1]
281 finally:
282 try:
283 if fd is not None:
284 _os.close(fd)
285 finally:
286 _os.unlink(name)
287
288
289 -def spawn(*argv, **kwargs):
290 """ Spawn a process """
291 if _sys.platform == 'win32':
292 newargv = []
293 for arg in argv:
294 if not arg or ' ' in arg or arg.startswith('"'):
295 arg = '"%s"' % arg.replace('"', '\\"')
296 newargv.append(arg)
297 argv = newargv
298 env = kwargs.get('env')
299 if env is None:
300 env = _os.environ
301
302 echo = kwargs.get('echo')
303 if echo:
304 print ' '.join(argv)
305 filepipe = kwargs.get('filepipe')
306 if filepipe:
307 return _filepipespawn(
308 kwargs.get('stdin'), kwargs.get('stdout'), argv, env
309 )
310 pipe = kwargs.get('stdout')
311 if pipe:
312 return _pipespawn(argv, env)
313
314 pid = _os.spawnve(_os.P_NOWAIT, argv[0], argv, env)
315 return _os.waitpid(pid, 0)[1]
316
317
318 try:
319 walk = _os.walk
320 except AttributeError:
321
322 - def walk(top, topdown=True, onerror=None):
323 """ directory tree walker """
324
325 join, isdir, islink = _os.path.join, _os.path.isdir, _os.path.islink
326 listdir, error = _os.listdir, _os.error
327
328 try:
329 names = listdir(top)
330 except error, err:
331 if onerror is not None:
332 onerror(err)
333 return
334
335 dirs, nondirs = [], []
336 for name in names:
337 if isdir(join(top, name)):
338 dirs.append(name)
339 else:
340 nondirs.append(name)
341
342 if topdown:
343 yield top, dirs, nondirs
344 for name in dirs:
345 path = join(top, name)
346 if not islink(path):
347 for x in walk(path, topdown, onerror):
348 yield x
349 if not topdown:
350 yield top, dirs, nondirs
351
352
353 -def files(base, wildcard='[!.]*', recursive=1, prune=('.svn', 'CVS')):
354 """ Determine a filelist """
355 for dirpath, dirnames, filenames in walk(native(base)):
356 for item in prune:
357 if item in dirnames:
358 dirnames.remove(item)
359
360 filenames.sort()
361 for name in _fnmatch.filter(filenames, wildcard):
362 dest = _os.path.join(dirpath, name)
363 if dest.startswith(cwd):
364 dest = dest.replace(cwd, '', 1)
365 aslist = []
366 head, tail = _os.path.split(dest)
367 while tail:
368 aslist.append(tail)
369 head, tail = _os.path.split(head)
370 aslist.reverse()
371 dest = '/'.join(aslist)
372 yield dest
373
374 if not recursive:
375 break
376 dirnames.sort()
377
378
380 """ Find executable in PATH """
381
382 path = _os.environ.get('PATH', '')
383 paths = [
384 _os.path.expanduser(item)
385 for item in path.split(_os.pathsep)
386 ]
387 ext = _os.path.splitext(executable)[1]
388 exts = ['']
389 if _sys.platform == 'win32' or _os.name == 'os2':
390 eext = ['.exe', '.bat', '.py']
391 if ext not in eext:
392 exts.extend(eext)
393
394 for ext in exts:
395 if not _os.path.isfile(executable + ext):
396 for path in paths:
397 fname = _os.path.join(path, executable + ext)
398 if _os.path.isfile(fname):
399
400 return fname
401 else:
402 return executable + ext
403
404 return None
405