Commit 59b436df authored by Jürg Billeter's avatar Jürg Billeter
Browse files

sandbox: Add queue_context_manager() method

parent 15d56e06
Loading
Loading
Loading
Loading
+62 −12
Original line number Diff line number Diff line
@@ -29,7 +29,8 @@ See also: :ref:`sandboxing`.
"""

import os
from collections import namedtuple
from collections import deque, namedtuple
from contextlib import contextmanager

from .._exceptions import ImplError, BstError
from ..storage._filebaseddirectory import FileBasedDirectory
@@ -73,6 +74,22 @@ class SandboxFlags():
    """


# _QueueEntryType()
#
# A type for sandbox queue entries.
#
class _QueueEntryType():

    # A queued command.
    COMMAND = 1

    # A queued context manager enter.
    CONTEXT_MANAGER_ENTER = 2

    # A queued context manager exit.
    CONTEXT_MANAGER_EXIT = 3


class Sandbox():
    """Sandbox()

@@ -265,7 +282,8 @@ class Sandbox():

        *Since: 1.4*
        """
        entry = namedtuple('QueueEntry', ['command', 'cwd', 'env', 'start_callback', 'complete_callback'])
        entry = namedtuple('QueueEntry', ['type', 'command', 'cwd', 'env', 'start_callback', 'complete_callback'])
        entry.type = _QueueEntryType.COMMAND
        entry.command = command
        entry.cwd = self._get_work_directory(cwd=cwd)
        entry.env = self._get_environment(cwd=cwd, env=env)
@@ -273,6 +291,24 @@ class Sandbox():
        entry.complete_callback = complete_callback
        self._queue.append(entry)

    @contextmanager
    def queue_context_manager(self, cm):
        """Queue entering and exiting a context manager

        Args:
           cm: A context manager

        *Since: 1.4*
        """
        entry = namedtuple('QueueEntry', ['type', 'cm'])
        entry.type = _QueueEntryType.CONTEXT_MANAGER_ENTER
        entry.cm = cm
        self._queue.append(entry)
        yield
        entry = namedtuple('QueueEntry', ['type'])
        entry.type = _QueueEntryType.CONTEXT_MANAGER_EXIT
        self._queue.append(entry)

    def run_queue(self, flags):
        """Run a command in the sandbox.

@@ -289,7 +325,11 @@ class Sandbox():
        queue = self._queue
        self._queue = []

        # Stack of pending context manager exit methods
        exit_stack = deque()
        try:
            for entry in queue:
                if entry.type == _QueueEntryType.COMMAND:
                    if entry.start_callback:
                        entry.start_callback()
                    if entry.command:
@@ -299,6 +339,16 @@ class Sandbox():
                        entry.complete_callback(exit_code)
                    if exit_code != 0:
                        break
                elif entry.type == _QueueEntryType.CONTEXT_MANAGER_ENTER:
                    entry.cm.__enter__()
                    exit_stack.append(entry.cm.__exit__)
                elif entry.type == _QueueEntryType.CONTEXT_MANAGER_EXIT:
                    exit_cb = exit_stack.pop()
                    exit_cb(None, None, None)
        finally:
            while exit_stack:
                exit_cb = exit_stack.pop()
                exit_cb(None, None, None)

    ################################################
    #               Private methods                #