tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

serve_repo.py (4166B)


      1 # Copyright 2022 The Chromium Authors
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 """Implements commands for serving a TUF repository."""
      5 
      6 import argparse
      7 import contextlib
      8 import json
      9 import logging
     10 from typing import Iterator, Optional
     11 
     12 import monitors
     13 
     14 from common import run_ffx_command, REPO_ALIAS
     15 
     16 _REPO_NAME = 'chromium-test-package-server'
     17 
     18 
     19 def _stop_serving(repo_name: str, target: Optional[str]) -> None:
     20    """Stop serving a repository."""
     21 
     22    # Attempt to clean up.
     23    with monitors.time_consumption('repository', 'deregister'):
     24        run_ffx_command(
     25            cmd=['target', 'repository', 'deregister', '-r', repo_name],
     26            target_id=target,
     27            check=False)
     28 
     29    with monitors.time_consumption('repository', 'stop'):
     30        run_ffx_command(cmd=['repository', 'server', 'stop', repo_name],
     31                        check=False)
     32 
     33 
     34 def _start_serving(repo_dir: str, repo_name: str,
     35                   target: Optional[str]) -> None:
     36    """Start serving a repository to a target device.
     37 
     38    Args:
     39        repo_dir: directory the repository is served from.
     40        repo_name: repository name.
     41        target: Fuchsia device the repository is served to.
     42    """
     43 
     44    cmd = [
     45        'repository', 'server', 'start', '--background',
     46        '--address', '[::]:0',
     47        '--repository', repo_name, '--repo-path', repo_dir, '--no-device'
     48    ]
     49 
     50    with monitors.time_consumption('repository', 'start'):
     51        start_cmd = run_ffx_command(cmd=cmd, check=False)
     52 
     53    logging.warning('ffx repository server start returns %d: %s %s',
     54                          start_cmd.returncode,
     55                          start_cmd.stderr, start_cmd.stdout)
     56 
     57    _assert_server_running(repo_name)
     58 
     59    cmd = [
     60        'target', 'repository', 'register', '-r', repo_name, '--alias',
     61        REPO_ALIAS
     62    ]
     63    with monitors.time_consumption('repository', 'register'):
     64        run_ffx_command(cmd=cmd, target_id=target)
     65 
     66 
     67 def _assert_server_running(repo_name: str) -> None:
     68    """Raises RuntimeError if the repository server is not running."""
     69 
     70    with monitors.time_consumption('repository', 'list'):
     71        list_cmd = run_ffx_command(cmd=[
     72            '--machine', 'json', 'repository', 'server', 'list', '--name',
     73            repo_name
     74        ],
     75                                   check=False,
     76                                   capture_output=True)
     77    try:
     78        response = json.loads(list_cmd.stdout.strip())
     79        if 'ok' in response and response['ok']['data']:
     80            if response['ok']['data'][0]['name'] != repo_name:
     81                raise RuntimeError(
     82                    'Repository server %s is not running. Output: %s stderr: %s'
     83                    % (repo_name, list_cmd.stdout, list_cmd.stderr))
     84            return
     85    except json.decoder.JSONDecodeError as error:
     86        # Log the json parsing error, but don't raise an exception since it
     87        # does not have the full context of the error.
     88        logging.error('Unexpected json string: %s, exception: %s, stderr: %s',
     89                list_cmd.stdout, error, list_cmd.stderr)
     90    raise RuntimeError(
     91        'Repository server %s is not running. Output: %s stderr: %s'
     92        % (repo_name, list_cmd.stdout, list_cmd.stderr))
     93 
     94 def register_serve_args(arg_parser: argparse.ArgumentParser) -> None:
     95    """Register common arguments for repository serving."""
     96 
     97    serve_args = arg_parser.add_argument_group('serve',
     98                                               'repo serving arguments')
     99    serve_args.add_argument('--serve-repo',
    100                            dest='repo',
    101                            help='Directory the repository is served from.')
    102    serve_args.add_argument('--repo-name',
    103                            default=_REPO_NAME,
    104                            help='Name of the repository.')
    105 
    106 @contextlib.contextmanager
    107 def serve_repository(args: argparse.Namespace) -> Iterator[None]:
    108    """Context manager for serving a repository."""
    109    _start_serving(args.repo, args.repo_name, args.target_id)
    110    try:
    111        yield None
    112    finally:
    113        _stop_serving(args.repo_name, args.target_id)