xref: /aosp_15_r20/external/cronet/build/fuchsia/test/serve_repo.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1#!/usr/bin/env vpython3
2# Copyright 2022 The Chromium Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5"""Implements commands for serving a TUF repository."""
6
7import argparse
8import contextlib
9import sys
10
11from typing import Iterator, Optional
12
13from common import REPO_ALIAS, catch_sigterm, register_device_args, \
14                   run_ffx_command, wait_for_sigterm
15
16_REPO_NAME = 'chromium-test-package-server'
17
18
19def _stop_serving(repo_name: str, target: Optional[str]) -> None:
20    """Stop serving a repository."""
21
22    # Attempt to clean up.
23    run_ffx_command(
24        cmd=['target', 'repository', 'deregister', '-r', repo_name],
25        target_id=target,
26        check=False)
27    run_ffx_command(cmd=['repository', 'remove', repo_name], check=False)
28    run_ffx_command(cmd=['repository', 'server', 'stop'], check=False)
29
30
31def _start_serving(repo_dir: str, repo_name: str,
32                   target: Optional[str]) -> None:
33    """Start serving a repository to a target device.
34
35    Args:
36        repo_dir: directory the repository is served from.
37        repo_name: repository name.
38        target: Fuchsia device the repository is served to.
39    """
40
41    run_ffx_command(cmd=('config', 'set', 'repository.server.mode', '\"ffx\"'))
42
43    run_ffx_command(cmd=['repository', 'server', 'start'])
44    run_ffx_command(
45        cmd=['repository', 'add-from-pm', repo_dir, '-r', repo_name])
46    run_ffx_command(cmd=[
47        'target', 'repository', 'register', '-r', repo_name, '--alias',
48        REPO_ALIAS
49    ],
50                    target_id=target)
51
52
53def register_serve_args(arg_parser: argparse.ArgumentParser) -> None:
54    """Register common arguments for repository serving."""
55
56    serve_args = arg_parser.add_argument_group('serve',
57                                               'repo serving arguments')
58    serve_args.add_argument('--serve-repo',
59                            dest='repo',
60                            help='Directory the repository is served from.')
61    serve_args.add_argument('--repo-name',
62                            default=_REPO_NAME,
63                            help='Name of the repository.')
64
65
66def run_serve_cmd(cmd: str, args: argparse.Namespace) -> None:
67    """Helper for running serve commands."""
68
69    if cmd == 'start':
70        _start_serving(args.repo, args.repo_name, args.target_id)
71    elif cmd == 'stop':
72        _stop_serving(args.repo_name, args.target_id)
73    else:
74        assert cmd == 'run'
75        catch_sigterm()
76        with serve_repository(args):
77            # Clients can assume the repo is up and running once the repo-name
78            # is printed out.
79            print(args.repo_name, flush=True)
80            wait_for_sigterm('shutting down the repo server.')
81
82
83@contextlib.contextmanager
84def serve_repository(args: argparse.Namespace) -> Iterator[None]:
85    """Context manager for serving a repository."""
86    run_serve_cmd('start', args)
87    try:
88        yield None
89    finally:
90        run_serve_cmd('stop', args)
91
92
93def main():
94    """Stand-alone function for serving a repository."""
95
96    parser = argparse.ArgumentParser()
97    parser.add_argument('cmd',
98                        choices=['start', 'stop', 'run'],
99                        help='Choose to start|stop|run repository serving. ' \
100                             '"start" command will start the repo and exit; ' \
101                             '"run" command will start the repo and wait ' \
102                             'until ctrl-c or sigterm.')
103    register_device_args(parser)
104    register_serve_args(parser)
105    args = parser.parse_args()
106    if (args.cmd == 'start' or args.cmd == 'run') and not args.repo:
107        raise ValueError('Directory the repository is serving from needs '
108                         'to be specified.')
109
110    run_serve_cmd(args.cmd, args)
111
112
113if __name__ == '__main__':
114    sys.exit(main())
115