#!/usr/bin/env python # used in a script with shebang in 1 of 2 ways # #!/path/to/re-l relative_interpreter # #!/usr/bin/env re-l relative_interpreter # the latter requires support for more than 1 parameter to the intpreter (not on linux) # # will set SCRIPT_FILE and SCRIPT_PATH # example: # #!/usr/local/bin/re-l python # or, going with the form that just requires re-l be in the path # #!/usr/bin/env re-l python # # these assume the script is in the same folder as the python interpreter. other deeper locations are also valid, like: # #!/usr/bin/env re-l ../Resources/Python.app/Contents/MacOS/Python # # Many systems only allow 1 parameter with Shebang. On these systems, re-l # must be installed in a standard location, then the following syntax can be used # and it will use the interpreter re-lative to the script's path # #!/usr/bin/re-l python # # Alternatively, re-l can be used in a proprietary way as follows: # #!/usr/bin/env re-l # #:python # # #Created by jpgarcia. #Copyright (c) 2015-2017 University of Wisconsin SSEC. All rights reserved. # import os,sys import logging LOG = logging.debug PY2 = sys.version_info[0] == 2 if not PY2: text_type = str string_types = (str,) unichr = chr makestring = lambda x: x if isinstance(x,str) else x.decode("utf-8") def cmp(a,b): #FIXME if len(a)!=len(b): return 1 for x in range(len(a)): if a[x]!=b[x]: return 1 return 0 asuni = lambda x: text_type( x.decode('utf-8') if hasattr(x,'decode') else x) else: text_type = unicode string_types = (str, unicode) unichr = unichr makestring = lambda x: x asuni = lambda x: text_type( x.decode('utf-8') if hasattr(x,'decode') else x) def getLine(f,linenumber=1): fil=open(f,mode='rU') v=asuni('') for x in range(linenumber): try: v=fil.readline(512).strip() v=asuni(v) except UnicodeDecodeError: v=asuni('') return v def isRelScript(filepath): return getLine(filepath,linenumber=1)==asuni('#!/usr/bin/env re-l') def extractRelInterpreter(filepath): l=getLine(filepath,linenumber=2) assert(l.startswith('#:')) return l.split(':',1)[1].strip() def relexec(interpreter,scriptfile,*_args): args=[None,None]+list(_args) LOG('%s %s' % (interpreter,scriptfile)) scriptpath=os.path.dirname(os.path.realpath(scriptfile)) interpreter=os.path.normpath(os.path.join(scriptpath,interpreter)) LOG('%s %s' % (scriptpath,interpreter)) args[0]=interpreter args[1]=scriptfile #print replacements LOG('running interpreter '+interpreter+' with parameters '+repr(args)) LOG('script_path=%s' % (scriptpath)) assert(os.path.exists(interpreter) and not os.path.isdir(interpreter)) assert(os.path.exists(scriptfile) and not os.path.isdir(scriptfile)) assert(os.path.exists(scriptpath) and os.path.isdir(scriptpath)) env=os.environ.copy() env['SCRIPT_FILE']=scriptfile env['SCRIPT_PATH']=scriptpath os.execve(interpreter,args,env) raise RuntimeError('Exec Failed') def main(): if len(sys.argv)==2 or isRelScript(sys.argv[1]): assert(isRelScript(sys.argv[1])) relexec(extractRelInterpreter(sys.argv[1]),sys.argv[1],*sys.argv[2:]) else: relexec(sys.argv[1],sys.argv[2],*sys.argv[3:]) if __name__ == '__main__': main()