Add a safe stacking context manager.

See docstrings for the specifics of why py2.6's nested with statement
isn't trustable; this form is, and has the benefit of collapsing
with statements down into a single block.

BUG=None
TEST=cbuildbot x86-generic-full # ctrl+c it, verify things ran as
     # they should have.

Change-Id: I63c985c17d630ed92cf2012573a001890ff07bb3
Reviewed-on: https://gerrit.chromium.org/gerrit/22559
Commit-Ready: Brian Harring <ferringb@chromium.org>
Reviewed-by: Brian Harring <ferringb@chromium.org>
Tested-by: Brian Harring <ferringb@chromium.org>
diff --git a/scripts/cbuildbot.py b/scripts/cbuildbot.py
index baa2d1f..1078cc1 100644
--- a/scripts/cbuildbot.py
+++ b/scripts/cbuildbot.py
@@ -1116,27 +1116,28 @@
                  'rather than the root of it.  This is not supported.'
                  % options.buildroot)
 
-  with cleanup.EnforcedCleanupSection() as critical_section:
-    with sudo.SudoKeepAlive():
+  with cros_lib.ContextManagerStack() as stack:
+    critical_section = stack.Add(cleanup.EnforcedCleanupSection)
+    stack.Add(sudo.SudoKeepAlive)
+    if not options.resume:
       # If we're in resume mode, use our parents tempdir rather than
       # nesting another layer.
-      with cros_lib.AllowDisabling(
-          not options.resume, osutils.TempDirContextManager, 'cbuildbot-tmp'):
-        logging.debug("Cbuildbot tempdir is %r.", os.environ.get('TMP'))
-        with cros_lib.AllowDisabling(options.cgroups,
-                                     cgroups.SimpleContainChildren,
-                                     'cbuildbot'):
-          # Mark everything between EnforcedCleanupSection and here as having to
-          # be rolled back via the contextmanager cleanup handlers.  This
-          # ensures that sudo bits cannot outlive cbuildbot, that anything
-          # cgroups would kill gets killed, etc.
-          critical_section.ForkWatchdog()
+      stack.Add(osutils.TempDirContextManager, 'cbuildbot-tmp')
+      logging.debug("Cbuildbot tempdir is %r.", os.environ.get('TMP'))
+    if options.cgroups:
+      stack.Add(cgroups.SimpleContainChildren, 'cbuildbot')
 
-          with cros_lib.AllowDisabling(options.timeout > 0,
-                                       cros_lib.Timeout, options.timeout):
-            if not options.buildbot:
-              build_config = cbuildbot_config.OverrideConfigForTrybot(
-                  build_config,
-                  options.remote_trybot)
+    # Mark everything between EnforcedCleanupSection and here as having to
+    # be rolled back via the contextmanager cleanup handlers.  This
+    # ensures that sudo bits cannot outlive cbuildbot, that anything
+    # cgroups would kill gets killed, etc.
+    critical_section.ForkWatchdog()
+    if options.timeout > 0:
+      stack.Add(cros_lib.Timeout, options.timeout)
 
-            _RunBuildStagesWrapper(options, build_config)
+    if not options.buildbot:
+      build_config = cbuildbot_config.OverrideConfigForTrybot(
+          build_config,
+          options.remote_trybot)
+
+    _RunBuildStagesWrapper(options, build_config)