# probe.py -- probe Popen's ability to look up executables # in the environment's PATH # # This script tries many possible combinations, adding directories to # os.environ['PATH'], supplying or not supplying an 'env' parameter to # Popen, adding or not adding directories to env['PATH'] when it is # passed, and trying both values for the 'shell' parameter. import tempfile,os,sys,shutil from os.path import join, sep, pathsep,split,realpath,normcase from subprocess import * from cStringIO import StringIO # Translate a temporary root directory path into three locations we'll # place executables, corresponding to locations in the PATH of the # environment in which Python was launched, the def ABC(root): return [join(root,x) for x in 'prelaunch', 'os_environ', 'explicit_env'] # # This script should be invoked by the user with no arguments other # than the following two options. If another argument is passed, it # means the script is invoking itself again with an explicit # environment prepared whose PATH contains a known directory: that # argument # options = ['--no-error-cases', '--invoke-filename'] # Look for a non-option argument root = ([d for d in sys.argv[1:] if d not in options] or [None])[0] # If not found, set up the root and the PATH and make a recursive # invocation of this script if not root: root = realpath(tempfile.mkdtemp()) A,B,C = ABC(root) os.environ['PATH'] = A + pathsep + os.environ.get('PATH','') code = Popen([sys.executable]+sys.argv+[root], stdin=None).wait() sys.exit(code) A,B,C = ABC(root) shutil.rmtree(root) os.mkdir(root) print 'Root directory:', root # Make sure the environment was properly set up by the outer script assert os.environ['PATH'].startswith(A+pathsep) # Write a script called 'wherami' that prints its location. for d in ((A,B,C) if '--no-error-cases' in sys.argv else (B,C)): os.mkdir(d) if sys.platform == 'win32': executable = 'whereami.bat' open(join(d, executable), 'w').write('@echo off\necho %~dp0') else: executable = 'whereami' f = join(d, executable) open(f,'w').write('''\ #!/bin/sh LSOF=$(lsof -p $$ | grep -E "/"$(basename $0)"$") MY_PATH=$(echo $LSOF | sed -r s/'^([^\/]+)\/'/'\/'/1 2>/dev/null) if [ $? -ne 0 ]; then ## OSX MY_PATH=$(echo $LSOF | sed -E s/'^([^\/]+)\/'/'\/'/1 2>/dev/null) fi dirname $MY_PATH ''') os.chmod(f, 0777) def whereami(*args, **kw): print 11*' ', try: proc = Popen((executable if '--invoke-filename' in sys.argv else 'whereami',)+args, stdout=PIPE,stderr=PIPE,**kw) stdout,stderr = proc.communicate() except Exception,e: print '**** Exception:', e else: if normcase(stdout.strip()).startswith(root): print '(code=%s) found in subdirectory:'% proc.returncode, stdout.strip()[len(root+sep):] else: print '**** (code=%s) UNEXPECTED stdout:' % proc.returncode, repr(stdout), 'stderr:', '\n'+stderr prelaunch_environ = os.environ.copy() prelaunch_PATH = prelaunch_environ.get('PATH','') env_C = os.environ.copy(); env_C['PATH'] = C+pathsep+prelaunch_PATH for os_path_prefix in '',B+pathsep: os.environ['PATH'] = os_path_prefix+prelaunch_PATH print print "* script %sin os.environ['PATH']'" % ('' if os_path_prefix else 'not ') for subprocess_env in None, prelaunch_environ, env_C: print if not subprocess_env: print " * Not passing env argument" else: if subprocess_env is prelaunch_environ: print " * Passing prelaunch environment as explicit env" else: print " * Passing explicit environment" subprocess_env = subprocess_env.copy() for shell in False,True: print 7*' ','* shell =',shell whereami(env=subprocess_env,shell=shell)