blob: d7b5eb4901f80b51bbd6ffa35cc60874fa53c36c [file] [log] [blame]
#!/usr/bin/env vpython3
# Copyright 2022 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Implements commands for serving a TUF repository."""
import argparse
import contextlib
import json
import logging
import os
import sys
from common import REPO_ALIAS, register_device_args, run_ffx_command
from ffx_integration import get_config
# Contains information about the active ephemeral repository.
_REPO_CONFIG_FILE = os.path.join('/', 'tmp', 'fuchsia-repo-config')
_REPO_NAME = 'chromium-test-package-server'
def _ensure_ffx_config(key: str, value: str) -> bool:
"""Ensures ffx config for a given key is value. Returns True if the config
was changed, False otherwise."""
if get_config(key) == value:
return False
run_ffx_command(['config', 'set', key, value])
return True
def _stop_serving() -> None:
"""Stop serving a repository configured in _REPO_CONFIG_FILE."""
if not os.path.exists(_REPO_CONFIG_FILE):
logging.warning('Could not find repository configuration.')
return
with open(_REPO_CONFIG_FILE, 'r') as file:
data = json.load(file)
# Attempt to clean up.
run_ffx_command(
['target', 'repository', 'deregister', '-r', data['repo_name']],
data['target'],
check=False)
run_ffx_command(['repository', 'remove', data['repo_name']], check=False)
run_ffx_command(['repository', 'server', 'stop'], check=False)
os.remove(_REPO_CONFIG_FILE)
def _start_serving(repo_dir: str, repo_name: str, target: str) -> None:
"""Start serving a repository.
Args:
repo_dir: directory the repository is served from.
repo_name: repository name.
target: Fuchsia device the repository is served to.
"""
if os.path.exists(_REPO_CONFIG_FILE):
_stop_serving()
# Check ffx configs, restart daemon if the configuration was updated.
config_updated = False
config_updated |= _ensure_ffx_config('ffx_repository', 'true')
config_updated |= _ensure_ffx_config('repository.server.mode', '\"ffx\"')
if config_updated:
run_ffx_command(['doctor', '--restart-daemon'])
data = {}
data['repo_name'] = repo_name
data['target'] = target
with open(_REPO_CONFIG_FILE, 'w') as file:
json.dump(data, file)
run_ffx_command(['repository', 'server', 'start'])
run_ffx_command(['repository', 'add-from-pm', repo_dir, '-r', repo_name])
run_ffx_command([
'target', 'repository', 'register', '-r', repo_name, '--alias',
REPO_ALIAS
], target)
def register_serve_args(arg_parser: argparse.ArgumentParser) -> None:
"""Register common arguments for repository serving."""
serve_args = arg_parser.add_argument_group('serve',
'repo serving arguments')
serve_args.add_argument('--serve-repo',
dest='repo',
help='Directory the repository is served from.')
serve_args.add_argument('--repo-name',
default=_REPO_NAME,
help='Name of the repository.')
def run_serve_cmd(cmd: str, args: argparse.Namespace) -> None:
"""Helper for running serve commands."""
if cmd == 'start':
_start_serving(args.repo, args.repo_name, args.target_id)
else:
_stop_serving()
@contextlib.contextmanager
def serve_repository(args: argparse.Namespace) -> None:
"""Context manager for serving a repository."""
_start_serving(args.repo, args.repo_name, args.target_id)
try:
yield None
finally:
_stop_serving()
def main():
"""Stand-alone function for serving a repository."""
parser = argparse.ArgumentParser()
parser.add_argument('cmd',
choices=['start', 'stop'],
help='Choose to start|stop repository serving.')
register_device_args(parser)
register_serve_args(parser)
args = parser.parse_args()
run_serve_cmd(args.cmd, args)
if __name__ == '__main__':
sys.exit(main())