From 0924161b2c0cd2752312e00170e0165931ff24f9 Mon Sep 17 00:00:00 2001 From: Abdulwasiu Apalowo Date: Fri, 23 Dec 2022 00:33:21 +0100 Subject: lcitool container: Add "build" subcommand This adds the "build" subcommand which is used to build container image from args.projects and args.target. The Dockerfile string generated from using the `DockerfileFormatter` class is copied to a temporary file which is passed to the build command. Tags are generated by prefixing the target name with "lcitool.", e.g "lcitool.fedora-36" to prevent trashing the output of "podman images" with incomprehensible tags. If an image is present, it is removed before starting another build to ensure the image is built from scratch. Ensure that (--target & --projects) arguments are passed with "build" subcommand. Signed-off-by: Abdulwasiu Apalowo --- lcitool/application.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ lcitool/commandline.py | 19 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/lcitool/application.py b/lcitool/application.py index 5b12d18..c5bbbab 100644 --- a/lcitool/application.py +++ b/lcitool/application.py @@ -6,9 +6,11 @@ import logging import sys +import textwrap from pathlib import Path from pkg_resources import resource_filename +from tempfile import TemporaryDirectory, NamedTemporaryFile from lcitool import util, LcitoolError from lcitool.config import Config @@ -326,6 +328,48 @@ class Application: else: print("No engine available") + def _action_container_build(self, args): + self._entrypoint_debug(args) + + params = {} + client = self._get_client(args.engine) + + container_tempdir = TemporaryDirectory(prefix="container", + dir=util.get_temp_dir()) + params["tempdir"] = container_tempdir.name + + tag = f"lcitool.{args.target}" + + # remove image and prepare to build a new one. + client.rmi(tag) + + targets = Targets() + packages = Packages() + projects = Projects() + projects_expanded = projects.expand_names(args.projects) + target = BuildTarget(targets, packages, args.target, args.cross_arch) + + _file = None + file_content = DockerfileFormatter(projects).format( + target, + projects_expanded + ) + with NamedTemporaryFile("w", + delete=False, + dir=params["tempdir"]) as fd: + fd.write(textwrap.dedent(file_content)) + _file = fd.name + + log.debug(f"Generated dockerfile copied to {_file}") + + try: + client.build(tag=tag, filepath=_file, **params) + except ContainerError as ex: + raise ApplicationError(ex.message) + + log.debug(f"Generated image tag --> {tag}") + print(f"Image '{tag}' successfully built.") + def run(self, args): try: util.set_extra_data_dir(args.data_dir) diff --git a/lcitool/commandline.py b/lcitool/commandline.py index 8bd60c6..9e69c49 100644 --- a/lcitool/commandline.py +++ b/lcitool/commandline.py @@ -298,6 +298,14 @@ class CommandLine: ) container_engineparser.set_defaults(func=Application._action_list_engines) + build_containerparser = containersubparser.add_parser( + "build", + help="Build container image", + parents=[installtargetopt, container_projectopt, engineopt, + crossarchopt], + ) + build_containerparser.set_defaults(func=Application._action_container_build) + # Validate "container" args def _validate(self, args): """ @@ -308,6 +316,17 @@ class CommandLine: :return: args. """ + if vars(args).get("container") \ + and args.container in ["build", "run", "shell"]: + + # Ensure that (--target & --projects) argument are passed with + # "build" subcommand. + if args.container == "build": + if args.projects and args.target: + return args + else: + log.error("--target and --projects are required") + sys.exit(1) return args def parse(self): -- cgit v1.1