From 9ef7d8b93ac0361c467453bd51f7f813a39c6663 Mon Sep 17 00:00:00 2001 From: Charles Short Date: Tue, 15 Aug 2023 10:43:45 -0400 Subject: [PATCH] Add "repo" command Add a "repo" command to create the Debian package archive. The purpose of the "repo" command is that allows the user to create, manage, and add new Debian packages locally which can be used to update ostree branches if the user does not have access to a network. The way that the "repo" command works is that, the "repo" makes system calls to reprepro to manage the archive. Reprepro was chosen because its simple to use, proven, and there is plenty of documentation. In-order for the package feed for it to be effective, one usually has a web front end so that apt can interact with the repository. To set one up please read the following documentaiton: https://wiki.debian.org/DebianRepository/SetupWithReprepro This commits also adds an "init" sub-command which will initialize the configuration of a Debian package repository created by reprepro. Testing: PASSED Installed apt-ostree from git repo. PASSED Run "sudo apt-ostree repo init \ --origin starlingx-updates --release bookworm" PASSED Check for /var/repository directory on target. PASSED Check "/var/repository/conf/distributions" to see the "Origin:" matches up with the CLI. Story: 2010867 Task: 48556 Change-Id: I9fd56ab78ec6d164b4486b4ef7ad3592dae56ed7 Signed-off-by: Charles Short --- apt_ostree/cmd/options.py | 55 ++++++++++++++++++++++++++ apt_ostree/cmd/repo/__init__.py | 19 +++++++++ apt_ostree/cmd/repo/init.py | 34 ++++++++++++++++ apt_ostree/cmd/shell.py | 2 + apt_ostree/repo.py | 52 ++++++++++++++++++++++++ apt_ostree/tests/repo/__init__.py | 0 apt_ostree/tests/repo/test_repo_cli.py | 18 +++++++++ docker/Dockerfile | 3 +- 8 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 apt_ostree/cmd/repo/__init__.py create mode 100644 apt_ostree/cmd/repo/init.py create mode 100644 apt_ostree/repo.py create mode 100644 apt_ostree/tests/repo/__init__.py create mode 100644 apt_ostree/tests/repo/test_repo_cli.py diff --git a/apt_ostree/cmd/options.py b/apt_ostree/cmd/options.py index 74f77d7..0d2f5bb 100644 --- a/apt_ostree/cmd/options.py +++ b/apt_ostree/cmd/options.py @@ -11,6 +11,8 @@ import click from apt_ostree.cmd import State +"""global options""" + def debug_option(f): def callback(ctxt, param, value): @@ -53,6 +55,9 @@ def edit_option(f): )(f) +"""compose options""" + + def repo_option(f): """ostree repo path option""" def callback(ctxt, param, value): @@ -102,3 +107,53 @@ def compose_options(f): f = branch_option(f) f = edit_option(f) return f + + +"""Package feed options""" + + +def feed_option(f): + """package feed directory""" + def callback(ctxt, param, value): + state = ctxt.ensure_object(State) + state.feed = pathlib.Path(value) + return value + return click.option( + "--feed", + help="Directory to store package repository", + nargs=1, + required=True, + default="/var/repository", + callback=callback + )(f) + + +def release_option(f): + """release option""" + def callback(ctxt, param, value): + state = ctxt.ensure_object(State) + state.release = value + return value + return click.option( + "--release", + help="Debian codename release", + nargs=1, + required=True, + callback=callback, + type=click.Choice(["bookworm", "bullseye"]), + )(f) + + +def origin_option(f): + """Origin option""" + def callback(ctxt, param, value): + state = ctxt.ensure_object(State) + state.origin = value + return value + return click.option( + "--origin", + help="Debian package origin (e.g. updates)", + nargs=1, + required=True, + callback=callback + )(f) diff --git a/apt_ostree/cmd/repo/__init__.py b/apt_ostree/cmd/repo/__init__.py new file mode 100644 index 0000000..aa5cd1f --- /dev/null +++ b/apt_ostree/cmd/repo/__init__.py @@ -0,0 +1,19 @@ +""" +Copyright (c) 2023 Wind River Systems, Inc. + +SPDX-License-Identifier: Apache-2.0 + +""" + +import click + +from apt_ostree.cmd.repo.init import init + + +@click.group(help="Commands to create/manage Debian package repository") +@click.pass_context +def repo(ctxt): + pass + + +repo.add_command(init) diff --git a/apt_ostree/cmd/repo/init.py b/apt_ostree/cmd/repo/init.py new file mode 100644 index 0000000..60dcf22 --- /dev/null +++ b/apt_ostree/cmd/repo/init.py @@ -0,0 +1,34 @@ +""" +Copyright (c) 2023 Wind River Systems, Inc. + +SPDX-License-Identifier: Apache-2.0 + +""" + +import shutil +import sys + +import click + + +from apt_ostree.cmd.options import feed_option +from apt_ostree.cmd.options import origin_option +from apt_ostree.cmd.options import release_option +from apt_ostree.cmd import pass_state_context +from apt_ostree.log import complete_step +from apt_ostree.repo import Repo + + +@click.command(help="Create a Debian package repsoitory.") +@pass_state_context +@feed_option +@release_option +@origin_option +def init(state, feed, release, origin): + if shutil.which("reprepro") is None: + click.secho("reprepro was not found in your $PATH") + sys.exit(0) + + with complete_step( + f"Creating Debian package repository in {state.feed}."): + Repo(state).init() diff --git a/apt_ostree/cmd/shell.py b/apt_ostree/cmd/shell.py index 7875545..c61d8c4 100644 --- a/apt_ostree/cmd/shell.py +++ b/apt_ostree/cmd/shell.py @@ -13,6 +13,7 @@ from apt_ostree.cmd.compose import compose from apt_ostree.cmd.options import debug_option from apt_ostree.cmd.options import workspace_option from apt_ostree.cmd import pass_state_context +from apt_ostree.cmd.repo import repo from apt_ostree.cmd.version import version from apt_ostree.log import setup_log @@ -39,4 +40,5 @@ def main(): cli.add_command(compose) +cli.add_command(repo) cli.add_command(version) diff --git a/apt_ostree/repo.py b/apt_ostree/repo.py new file mode 100644 index 0000000..c574cf0 --- /dev/null +++ b/apt_ostree/repo.py @@ -0,0 +1,52 @@ +""" +Copyright (c) 2023 Wind River Systems, Inc. + +SPDX-License-Identifier: Apache-2.0 + +""" +import sys +import textwrap + +from apt_ostree.log import log_step + + +class Repo: + def __init__(self, state): + self.state = state + self.repo = self.state.feed + + self.label = "StarlingX project udpates." + self.arch = "amd64" + self.description = "Apt repository for StarlingX updates." + + def init(self): + """Create a debian archive from scratch.""" + log_step("Creating Debian package archive.") + self.repo = self.repo.joinpath("conf") + if not self.repo.exists(): + log_step("Creating package feed directory") + self.repo.mkdir(parents=True, exist_ok=True) + + config = self.repo.joinpath("distributions") + if config.exists(): + log_step("Found existing configuration") + sys.exit(1) + else: + log_step("Creating reprepro configuration") + config.write_text( + textwrap.dedent(f"""\ + Origin: {self.state.origin} + Label: {self.label} + Codename: {self.state.release} + Architectures: amd64 + Components: {self.state.origin} + Description: {self.description} + """) + ) + options = self.repo.joinpath("options") + if not options.exists(): + options.write_text( + textwrap.dedent(f"""\ + basedir {self.repo} + """) + ) diff --git a/apt_ostree/tests/repo/__init__.py b/apt_ostree/tests/repo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apt_ostree/tests/repo/test_repo_cli.py b/apt_ostree/tests/repo/test_repo_cli.py new file mode 100644 index 0000000..8cb62f8 --- /dev/null +++ b/apt_ostree/tests/repo/test_repo_cli.py @@ -0,0 +1,18 @@ +""" +Copyright (c) 2023 Wind River Systems, Inc. + +SPDX-License-Identifier: Apache-2.0 + +""" + +from apt_ostree.cmd.shell import cli +from apt_ostree.tests import base +from click.testing import CliRunner + + +class TestRepoCLI(base.TestCase): + + def test_repo_help(self): + runner = CliRunner() + result = runner.invoke(cli, ["repo", "--help"]) + assert result.exit_code == 0 diff --git a/docker/Dockerfile b/docker/Dockerfile index 3a653e7..a4c433a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -14,7 +14,8 @@ RUN apt-get update && \ python3-click \ python3-pip \ python3-pbr \ - python3-rich + python3-rich \ + reprepro ADD assets/pip.conf /etc/pip.conf