Changeset 5608

Show
Ignore:
Timestamp:
07/26/12 05:10:52 (7 years ago)
Author:
justinc
Message:

Refactoring of main to fix #1066. The new main method should be
considered stable and should *not* be changed unless necessary.
Our external parties are using our code and assuming it will not change.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • seattle/branches/repy_v2/repy/repy.py

    r5607 r5608  
    9494 
    9595 
    96 def main(resourcefn, program, args): 
    97  
    98   # Armon: Initialize the circular logger before starting the nanny 
    99   if logfile: 
    100     # time to set up the circular logger 
    101     loggerfo = loggingrepy.circular_logger(logfile) 
    102     # and redirect err and out there... 
    103     sys.stdout = loggerfo 
    104     sys.stderr = loggerfo 
    105   else: 
    106     # let's make it so that the output (via print) is always flushed 
    107     sys.stdout = loggingrepy.flush_logger(sys.stdout) 
    108      
    109   # start the nanny up and read the resource file.   
    110   nanny.start_resource_nanny(resourcefn) 
    111  
    112   # now, let's fire up the cpu / disk / memory monitor... 
    113   nonportable.monitor_cpu_disk_and_mem() 
    114  
    115   # Armon: Update our IP cache 
    116   emulcomm.update_ip_cache() 
     96def get_safe_context(args): 
    11797 
    11898 
     
    146126  usercontext["getlasterror"] = emulmisc.getlasterror 
    147127       
    148   # grab the user code from the file 
    149   try: 
    150     filehandle = open(program) 
    151     usercode = filehandle.read() 
    152     filehandle.close() 
    153   except: 
    154     print "Failed to read the specified file: '"+program+"'" 
    155     raise 
    156  
    157   # Armon: Create the main namespace 
    158   try: 
    159     main_namespace = virtual_namespace.VirtualNamespace(usercode, program) 
    160   except CodeUnsafeError, e: 
    161     print "Specified repy program is unsafe!" 
    162     print "Static-code analysis failed with error: "+str(e) 
    163     harshexit.harshexit(5) 
    164  
    165   # Let the code string get GC'ed 
    166   usercode = None 
    167  
    168   # I'll use this to detect when the program is idle so I know when to quit... 
    169   idlethreadcount =  threading.activeCount() 
    170  
    171128  # call the initialize function 
    172129  usercontext['callfunc'] = 'initialize' 
    173130  usercontext['callargs'] = args[:] 
     131 
     132 
     133  return usercontext 
     134 
     135 
     136 
     137 
     138def execute_namespace_until_completion(thisnamespace, thiscontext): 
     139 
     140  # I'll use this to detect when the program is idle so I know when to quit... 
     141  idlethreadcount =  threading.activeCount() 
     142 
    174143  
     144  # add my thread to the set of threads that are used... 
    175145  event_id = idhelper.getuniqueid() 
    176146  try: 
     
    180150              "initialize' event.\n(Exception was: %s)" % e.message, 140) 
    181151  
    182   try: 
    183     main_namespace.evaluate(usercontext) 
     152   
     153  try: 
     154    thisnamespace.evaluate(thiscontext) 
    184155  except SystemExit: 
    185156    raise 
     
    197168    time.sleep(0.25) 
    198169 
    199  
    200   # Once there are no more pending events for the user thread, we exit 
    201   harshexit.harshexit(0) 
     170  # Once there are no more events, return... 
     171  return 
     172 
    202173 
    203174 
     
    243214 
    244215 
    245 if __name__ == '__main__': 
    246   global logfile 
    247  
    248   # Armon: The CMD line path to repy is the first argument 
    249   repy_location = sys.argv[0] 
    250  
    251   # Get the directory repy is in 
    252   repy_directory = os.path.dirname(repy_location) 
     216def init_repy_location(repy_directory): 
     217 
    253218   
    254219  # Translate into an absolute path 
     
    277242  sys.path = newsyspath 
    278243 
    279    
    280   args = sys.argv[1:] 
    281  
    282   try: 
    283     optlist, fnlist = getopt.getopt(args, '', [ 
     244 
     245 
     246   
     247def init_commandline_options(args): 
     248 
     249  # let's get the arguments! 
     250 
     251  try: 
     252    optlist, extraargs = getopt.getopt(args, '', [ 
    284253      'ip=', 'iface=', 'nootherips', 'logfile=', 
    285254      'stop=', 'status=', 'cwd=', 'servicelog' 
     
    302271  statusfile = None 
    303272 
    304   if len(fnlist) < 2: 
     273  if len(extraargs) < 2: 
    305274    usage("Must supply a resource file and a program file to execute") 
    306275    sys.exit(1) 
     
    358327  statusstorage.write_status("Started") 
    359328 
    360   resourcefn = fnlist[0] 
    361   progname = fnlist[1] 
    362   progargs = fnlist[2:] 
    363329 
    364330  # We also need to pass in whether or not we are going to be using the service 
    365331  # log for repy.  We provide the repy directory so that the vessel information 
    366332  # can be found regardless of where we are called from... 
    367   tracebackrepy.initialize(servicelog, absolute_repy_directory) 
    368  
    369   try: 
    370     main(resourcefn, progname, progargs) 
     333  tracebackrepy.initialize(servicelog, repy_constants.REPY_START_DIR) 
     334 
     335  # Armon: Initialize the circular logger before starting the nanny 
     336  if logfile: 
     337    # time to set up the circular logger 
     338    loggerfo = loggingrepy.circular_logger(logfile) 
     339    # and redirect err and out there... 
     340    sys.stdout = loggerfo 
     341    sys.stderr = loggerfo 
     342  else: 
     343    # let's make it so that the output (via print) is always flushed 
     344    sys.stdout = loggingrepy.flush_logger(sys.stdout) 
     345 
     346 
     347  # we need to give the left over arguments to repy so it can function 
     348  return extraargs 
     349 
     350 
     351 
     352def initialize_nanny(resourcefn): 
     353  # start the nanny up and read the resource file.   
     354  # JAC: Should this take a string instead? 
     355  nanny.start_resource_nanny(resourcefn) 
     356 
     357  # now, let's fire up the cpu / disk / memory monitor... 
     358  nonportable.monitor_cpu_disk_and_mem() 
     359 
     360  # JAC: I believe this is needed for interface / ip-based restrictions 
     361  emulcomm.update_ip_cache() 
     362 
     363 
     364 
     365def main(): 
     366  # JAC: This function should be kept as stable if possible.   Others who 
     367  # extend Repy may be doing essentially the same thing in their main and 
     368  # your changes may not be reflected there! 
     369 
     370 
     371  # Armon: The CMD line path to repy is the first argument 
     372  repy_location = sys.argv[0] 
     373 
     374  # Get the directory repy is in 
     375  repy_directory = os.path.dirname(repy_location) 
     376   
     377  init_repy_location(repy_directory) 
     378   
     379 
     380  ### PARSE OPTIONS.   These are command line in our case, but could be from 
     381  ### anywhere if this is repurposed... 
     382 
     383  args = sys.argv[1:] 
     384 
     385  # do a huge amount of initialization. 
     386  # The repy location must be set first!!! 
     387  remainingargs = init_commandline_options(args) 
     388 
     389 
     390  # what remains is the resourcefn progname [args...] 
     391  resourcefn = remainingargs[0] 
     392  progname = remainingargs[1] 
     393  progargs = remainingargs[2:] 
     394 
     395  ### start resource restrictions, etc. for the nanny 
     396  initialize_nanny(resourcefn) 
     397 
     398 
     399  # grab the user code from the file 
     400  try: 
     401    filehandle = open(progname) 
     402    usercode = filehandle.read() 
     403    filehandle.close() 
     404  except: 
     405    print "Failed to read the specified program file: '"+progname+"'" 
     406    raise 
     407 
     408  # create the namespace... 
     409  try: 
     410    newnamespace = virtual_namespace.VirtualNamespace(usercode, progname) 
     411  except CodeUnsafeError, e: 
     412    print "Specified repy program is unsafe!" 
     413    print "Static-code analysis failed with error: "+str(e) 
     414    harshexit.harshexit(5) 
     415 
     416  # allow the (potentially large) code string to be garbage collected 
     417  usercode = None 
     418 
     419 
     420  # get a new namespace 
     421  newcontext = get_safe_context(progargs) 
     422 
     423  # one could insert a new function for repy code here by changing newcontext  
     424  # to contain an additional function. 
     425 
     426 
     427  # run the code to completion... 
     428  execute_namespace_until_completion(newnamespace, newcontext) 
     429 
     430 
     431  # No more pending events for the user thread, we exit 
     432  harshexit.harshexit(0) 
     433 
     434 
     435 
     436if __name__ == '__main__': 
     437  try: 
     438    main() 
    371439  except SystemExit: 
    372440    harshexit.harshexit(4)