code: def run(self, variables=None, overrides=None):
          
  
          old_dir = os.getcwd()
          try:
              os.chdir(self.run_directory)
  
              initialized_steps = self.prepare(variables)
              owned_resources = {}
  
              try:
                  print("Running in %s" % self.run_directory)
                  initialized_resources, owned_resources = self._prepare_resources(variables, overrides)
  
                  for i, (step, decl) in enumerate(zip(initialized_steps, self.steps)):
                      print("===> Step %d: %s\t Description: %s" % (i+1, self.steps[i][0].__name__, \
                          self.steps[i][1].get('description', '')))
  
                      runtime, out = _run_step(step, decl, initialized_resources)
  
                      print("======> Time Elapsed: %.2f seconds" % runtime)
                      if out is not None:
                          print(out[1])
              finally:
                  self._cleanup_resources(owned_resources)
          finally:
              os.chdir(old_dir)
docs: Initialize and run this recipe.
  
          By default all necessary shared resources are created and destroyed in
          this function unless you pass them preinitizlied in overrides, in
          which case they are used as is.  The overrides parameter is designed
          to allow testability of iotile-ship recipes by inspecting the shared
          resources after the recipe has finished to ensure that it was properly
          set up.
  
          Args:
              variables (dict): An optional dictionary of variable assignments.
                  There must be a single assignment for all free variables that
                  do not have a default value, otherwise the recipe will not
                  run.
              overrides (dict): An optional dictionary of shared resource
                  objects that should be used instead of creating that resource
                  and destroying it inside this function.