| # Copyright 2023 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| """Sets up the isolate daemon environment to run test on the bots.""" |
| |
| import os |
| import tempfile |
| |
| from typing import Optional |
| |
| from contextlib import AbstractContextManager |
| |
| from common import get_ffx_isolate_dir,has_ffx_isolate_dir, \ |
| set_ffx_isolate_dir, is_daemon_running, \ |
| start_ffx_daemon, stop_ffx_daemon |
| from ffx_integration import ScopedFfxConfig |
| from modification_waiter import ModificationWaiter |
| |
| |
| class IsolateDaemon(AbstractContextManager): |
| """Sets up the environment of an isolate ffx daemon.""" |
| |
| class IsolateDir(AbstractContextManager): |
| """Sets up the ffx isolate dir to a temporary folder if it's not set.""" |
| def __init__(self): |
| if has_ffx_isolate_dir(): |
| self._temp_dir = None |
| else: |
| self._temp_dir = tempfile.TemporaryDirectory() |
| |
| def __enter__(self): |
| if self._temp_dir: |
| set_ffx_isolate_dir(self._temp_dir.__enter__()) |
| return self |
| |
| def __exit__(self, exc_type, exc_value, traceback): |
| if self._temp_dir: |
| try: |
| self._temp_dir.__exit__(exc_type, exc_value, traceback) |
| except OSError: |
| # Ignore the errors when cleaning up the temporary folder. |
| pass |
| return False |
| |
| class RepoProcessDir(AbstractContextManager): |
| """Sets up a temporary folder for the repository server process dir. |
| The default location, $XDG_STATE_HOME turns out to be in the |
| a binding to a directory on the host machine. The isolate directory is |
| a docker Volume. The performance of the isolate dir is much better than |
| the performance of using the volume based directory, especially on |
| arm64 hosts. |
| """ |
| def __init__(self): |
| # don't try to access the isolate dir at this point, it may not be |
| # set up yet. |
| self._process_dir_config = None |
| |
| def __enter__(self): |
| self._process_dir_config = ScopedFfxConfig( |
| 'repository.process_dir', |
| f'{get_ffx_isolate_dir()}/repo_proc') |
| self._process_dir_config.__enter__() |
| return self |
| |
| def __exit__(self, exc_type, exc_value, traceback): |
| return self._process_dir_config.__exit__(exc_type, exc_value, |
| traceback) |
| |
| def __init__(self, logs_dir: Optional[str]): |
| assert not has_ffx_isolate_dir() or not is_daemon_running() |
| self._inits = [ |
| self.IsolateDir(), |
| # The RepoProcess dir must be 'entered' after the IsolateDir, so the |
| # iso directory is set up first. |
| self.RepoProcessDir(), |
| ModificationWaiter(logs_dir), |
| # Keep the alphabetical order. |
| ScopedFfxConfig('ffx.isolated', 'true'), |
| ScopedFfxConfig('daemon.autostart', 'false'), |
| # fxb/126212: The timeout rate determines the timeout for each file |
| # transfer based on the size of the file / this rate (in MB). |
| # Decreasing the rate to 1 (from 5) increases the timeout in |
| # swarming, where large files can take longer to transfer. |
| ScopedFfxConfig('fastboot.flash.timeout_rate', '1'), |
| ScopedFfxConfig('fastboot.reboot.reconnect_timeout', '120'), |
| ScopedFfxConfig('fastboot.usb.disabled', 'true'), |
| ScopedFfxConfig('log.level', 'debug') |
| ] |
| if logs_dir: |
| self._inits.append(ScopedFfxConfig('log.dir', logs_dir)) |
| |
| # Updating configurations to meet the requirement of isolate. |
| def __enter__(self): |
| # This environment variable needs to be set before stopping ffx daemon |
| # to avoid sending unnecessary analytics. |
| os.environ['FUCHSIA_ANALYTICS_DISABLED'] = '1' |
| stop_ffx_daemon() |
| for init in self._inits: |
| init.__enter__() |
| start_ffx_daemon() |
| return self |
| |
| def __exit__(self, exc_type, exc_value, traceback): |
| for init in self._inits: |
| init.__exit__(exc_type, exc_value, traceback) |
| stop_ffx_daemon() |