Package _setup :: Module shell
[hide private]
[frames] | no frames]

Source Code for Module _setup.shell

  1  # -*- coding: ascii -*- 
  2  # 
  3  # Copyright 2007, 2008, 2009, 2010 
  4  # Andr\xe9 Malo or his licensors, as applicable 
  5  # 
  6  # Licensed under the Apache License, Version 2.0 (the "License"); 
  7  # you may not use this file except in compliance with the License. 
  8  # You may obtain a copy of the License at 
  9  # 
 10  #     http://www.apache.org/licenses/LICENSE-2.0 
 11  # 
 12  # Unless required by applicable law or agreed to in writing, software 
 13  # distributed under the License is distributed on an "AS IS" BASIS, 
 14  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 15  # See the License for the specific language governing permissions and 
 16  # limitations under the License. 
 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   
38 -class ExitError(RuntimeError):
39 """ Exit error """
40 - def __init__(self, code):
41 RuntimeError.__init__(self, code) 42 self.code = code 43 self.signal = None
44 45
46 -class SignalError(ExitError):
47 """ Signal error """
48 - def __init__(self, code, signal):
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
61 -def native(path):
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
67 -def cp(src, dest):
68 """ Copy src to dest """ 69 _shutil.copy2(native(src), native(dest))
70 71
72 -def cp_r(src, dest):
73 """ Copy -r src to dest """ 74 _shutil.copytree(native(src), native(dest))
75 76
77 -def rm(dest):
78 """ Remove a file """ 79 try: 80 _os.unlink(native(dest)) 81 except OSError, e: 82 if _errno.ENOENT != e.errno: 83 raise
84
85 -def rm_rf(dest):
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 # helpers stolen from 2.4 tempfile module 98 try: 99 import fcntl as _fcntl 100 except ImportError:
101 - def _set_cloexec(fd):
102 """ Set close-on-exec (not implemented, but not an error) """ 103 # pylint: disable = W0613 104 pass
105 else:
106 - def _set_cloexec(fd):
107 """ Set close-on-exec """ 108 try: 109 flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0) 110 except IOError: 111 pass 112 else: 113 # flags read successfully, modify 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 # pylint: disable = W0622 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() # pylint: disable = E1101, W0212 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
150 -def _pipespawn(argv, env):
151 """ Pipe spawn """ 152 # pylint: disable = R0912 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
235 -def _filepipespawn(infile, outfile, argv, env):
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 # copy from python 2.4 sources (modulo docs and comments)
322 - def walk(top, topdown=True, onerror=None):
323 """ directory tree walker """ 324 # pylint: disable = C0103 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
379 -def frompath(executable):
380 """ Find executable in PATH """ 381 # Based on distutils.spawn.find_executable. 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 # the file exists, we have a shot at spawn working 400 return fname 401 else: 402 return executable + ext 403 404 return None
405