in src/buildstream/sandbox/_sandboxreapi.py [0:0]
def _run(self, command, *, flags, cwd, env):
context = self._get_context()
cascache = context.get_cascache()
# set up virtual dircetory
vdir = self.get_virtual_directory()
if not self._has_command(command[0], env):
raise SandboxCommandError(
"Staged artifacts do not provide command " "'{}'".format(command[0]), reason="missing-command"
)
# Ensure working directory exists
if len(cwd) > 1:
assert cwd.startswith("/")
vdir.open_directory(cwd[1:], create=True)
# Ensure directories required for sandboxed execution exist
for directory in ["dev", "proc", "tmp"]:
vsubdir = vdir.open_directory(directory, create=True)
if flags & _SandboxFlags.ROOT_READ_ONLY:
vsubdir._set_subtree_read_only(False)
# Create directories for all marked directories. This emulates
# some of the behaviour of other sandboxes, which create these
# to use as mount points.
read_write_directories = []
mount_sources = self._get_mount_sources()
for directory in self._get_marked_directories():
if directory in mount_sources:
# Bind mount
mount_point = directory.lstrip(os.path.sep)
mount_source = mount_sources[directory]
# Ensure mount point exists in sandbox
if not vdir.exists(mount_point):
if os.path.isdir(mount_source):
# Mounting a directory, mount point must be a directory
vdir.open_directory(mount_point, create=True)
else:
# Mounting a file or device node, mount point must be a file
split_mount_point = mount_point.rsplit(os.path.sep, 1)
parent_vdir = vdir.open_directory(split_mount_point[0], create=True)
parent_vdir._create_empty_file(split_mount_point[1])
else:
# Read-write directory
marked_vdir = vdir.open_directory(directory.lstrip(os.path.sep), create=True)
read_write_directories.append(directory)
if flags & _SandboxFlags.ROOT_READ_ONLY:
marked_vdir._set_subtree_read_only(False)
if flags & _SandboxFlags.ROOT_READ_ONLY:
vdir._set_subtree_read_only(True)
else:
# The whole sandbox is writable
read_write_directories = [os.path.sep]
# Generate Action proto
input_root_digest = vdir._get_digest()
platform = self._create_platform(flags)
command_proto = self._create_command(command, cwd, env, read_write_directories, platform)
command_digest = cascache.add_object(buffer=command_proto.SerializeToString())
action = remote_execution_pb2.Action(
command_digest=command_digest, input_root_digest=input_root_digest, platform=platform
)
action_result = self._execute_action(action, flags) # pylint: disable=assignment-from-no-return
# Get output of build
self._process_job_output(
cwd, action_result.output_directories, action_result.output_files, failure=action_result.exit_code != 0
)
# Non-zero exit code means a normal error during the build:
# the remote execution system has worked correctly but the command failed.
return action_result.exit_code