From 794d151bef1419277c71c780789042b32a929a3f Mon Sep 17 00:00:00 2001 From: Haibo Lin Date: Wed, 11 Dec 2019 15:59:26 +0800 Subject: [PATCH] Remove productimg phase JIRA: COMPOSE-4004 Signed-off-by: Haibo Lin --- doc/_static/phases.png | Bin 24469 -> 22936 bytes doc/_static/phases.svg | 719 +++++++++++++++---------------- doc/configuration.rst | 38 -- doc/phases.rst | 6 - pungi/checks.py | 25 +- pungi/metadata.py | 8 - pungi/paths.py | 10 - pungi/phases/__init__.py | 1 - pungi/phases/product_img.py | 276 ------------ pungi/scripts/config_validate.py | 1 - pungi/scripts/pungi_koji.py | 22 +- tests/test_checks.py | 18 +- 12 files changed, 371 insertions(+), 753 deletions(-) delete mode 100644 pungi/phases/product_img.py diff --git a/doc/_static/phases.png b/doc/_static/phases.png index bca203e0ec0a5c64c16348d38aee406ea4332592..d5e4cebbe976f29d87671d6fad7d04c40b364420 100644 GIT binary patch literal 22936 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 literal 24469 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 D>C7|n diff --git a/doc/_static/phases.svg b/doc/_static/phases.svg index 7bbc5e1f..5f10e8cb 100644 --- a/doc/_static/phases.svg +++ b/doc/_static/phases.svg @@ -1,6 +1,4 @@ - - + inkscape:export-filename="/home/lsedlar/repos/pungi/doc/_static/phases.png" + sodipodi:docname="phases.svg" + inkscape:version="1.0beta2 (2b71d25, 2019-12-03)" + version="1.1" + id="svg2" + viewBox="0 0 771.66458 221.50019" + height="221.50018" + width="771.66455"> + fit-margin-left="0" + fit-margin-top="0" + inkscape:guide-bbox="true" + showguides="true" + inkscape:document-rotation="0" + units="px" + inkscape:window-maximized="1" + inkscape:window-y="23" + inkscape:window-x="0" + inkscape:window-height="1035" + inkscape:window-width="1920" + showgrid="false" + inkscape:current-layer="layer1" + inkscape:document-units="px" + inkscape:cy="97.894202" + inkscape:cx="396.63448" + inkscape:zoom="1.169022" + inkscape:pageshadow="2" + inkscape:pageopacity="1" + borderopacity="1.0" + bordercolor="#666666" + pagecolor="#ffffff" + id="base" /> + refY="0" + refX="0" + id="Arrow1Lend" + style="overflow:visible" + inkscape:isstock="true"> + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1" + transform="matrix(-0.8,0,0,-0.8,-10,0)" + inkscape:connector-curvature="0" /> image/svg+xml - + + id="layer1" + transform="matrix(1.066667,0,0,1.066667,-2.473231,-910.85239)"> + id="g3411" + transform="translate(71.99326,-80.817124)"> + x="953.49097" + height="49.214859" + width="26.295755" + id="rect3340" + style="fill:#8ae234;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> Pkgset + x="51.554729" + id="tspan3362" + sodipodi:role="line">Pkgset + id="g3446" + transform="translate(-22.545013,-80.817124)"> - ImageChecksum - - - + height="115.80065" + x="953.49097" + y="554.10059" /> Test + x="556.95709" + y="971.54041">ImageChecksum + + Test + + + x="873.01788" + height="39.669899" + width="26.295755" + id="rect3336" + style="fill:#fce94f;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> Init + x="6.2600794" + id="tspan3358" + sodipodi:role="line">Init - - - Productimg - + id="path3642" + inkscape:connector-curvature="0" /> + width="26.295755" + height="231.47725" + x="873.01788" + y="103.46365" + transform="matrix(0,1,1,0,0,0)" /> Buildinstall + x="105.76799" + y="891.06732" + style="font-size:13.1479px;line-height:1.25">Buildinstall + width="26.295755" + height="54.197887" + x="905.2099" + y="103.28194" + transform="matrix(0,1,1,0,0,0)" /> Gather + x="106.1384" + y="923.25934" + style="font-size:13.1479px;line-height:1.25">Gather + x="905.2099" + height="72.729973" + width="26.295755" + id="rect3346" + style="fill:#ad7fa8;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> ExtraFiles + x="165.23042" + y="923.25934" + style="font-size:13.1479px;line-height:1.25">ExtraFiles - Createrepo - - - + height="78.636055" + x="905.2099" + y="241.10229" + transform="matrix(0,1,1,0,0,0)" /> OSTree + id="tspan3378" + x="243.95874" + y="921.86945" + style="font-size:13.1479px;line-height:1.25">Createrepo + transform="translate(-150.564,114.11662)" + id="g3408"> + + OSTree + + + id="g3653" + transform="translate(0.56706579)"> + x="1022.637" + height="101.85102" + width="26.295755" + id="rect3428" + style="fill:#fcaf3e;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> OSTreeInstaller + x="492.642" + sodipodi:role="line" + id="tspan283">OSTreeInstaller - - + + + Createiso - - - - Createiso + + + + LiveImages - - - - LiveImages + + + + ImageBuild - - - - ImageBuild + + + + LiveMedia - - - - LiveMedia + + + + OSBS - - - - OSBS + + + + ExtraIsos + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve">ExtraIsos + diff --git a/doc/configuration.rst b/doc/configuration.rst index 2ce9216b..5da06563 100644 --- a/doc/configuration.rst +++ b/doc/configuration.rst @@ -1046,44 +1046,6 @@ in the ``os/`` directory and media. The checksums generated are determined by } -Productimg Settings -=================== -Product images are placed on installation media and provide additional branding -and Anaconda changes specific to product variants. - -Options -------- - -**productimg** = False - (*bool*) -- create product images; requires buildinstall_method option - -**productimg_install_class** - (:ref:`scm_dict `, *str*) -- reference to install class **file** - -**productimg_po_files** - (:ref:`scm_dict `, *str*) -- reference to a **directory** with - po files for install class translations - - -Example -------- -:: - - productimg = True - productimg_install_class = { - "scm": "git", - "repo": "http://git.example.com/productimg.git", - "branch": None, - "file": "fedora23/%(variant_id)s.py", - } - productimg_po_files = { - "scm": "git", - "repo": "http://git.example.com/productimg.git", - "branch": None, - "dir": "po", - } - - CreateISO Settings ================== diff --git a/doc/phases.rst b/doc/phases.rst index 6b04932a..3307482c 100644 --- a/doc/phases.rst +++ b/doc/phases.rst @@ -78,12 +78,6 @@ compose fails in a later stage, the commit will not be reverted. Implementation wise, this phase runs ``rpm-ostree`` command in Koji runroot (to allow running on different arches). -Productimg ----------- - -Creates ``product.img`` files for customizing the bootable media created in -``buildinstall`` phase. - Createiso --------- diff --git a/pungi/checks.py b/pungi/checks.py index 775aaf1e..ba94c472 100644 --- a/pungi/checks.py +++ b/pungi/checks.py @@ -52,22 +52,18 @@ from productmd.composeinfo import COMPOSE_TYPES from . import util -def _will_productimg_run(conf): - return conf.get('productimg', False) and conf.get('buildinstall_method', '') - - def is_jigdo_needed(conf): return conf.get('create_jigdo', True) def is_isohybrid_needed(conf): - """The isohybrid command is needed locally only for productimg phase and + """The isohybrid command is needed locally only for createiso phase without runroot. If that is not going to run, we don't need to check for it. Additionally, the syslinux package is only available on x86_64 and i386. """ runroot_tag = conf.get('runroot_tag', '') - if runroot_tag and not _will_productimg_run(conf): + if runroot_tag: return False if platform.machine() not in ('x86_64', 'i686', 'i386'): print('Not checking for /usr/bin/isohybrid due to current architecture. ' @@ -77,10 +73,10 @@ def is_isohybrid_needed(conf): def is_genisoimage_needed(conf): - """This is only needed locally for productimg and createiso without runroot. + """This is only needed locally for createiso without runroot. """ runroot_tag = conf.get('runroot_tag', '') - if runroot_tag and not _will_productimg_run(conf): + if runroot_tag: return False return True @@ -98,7 +94,6 @@ tools = [ ("isomd5sum", "/usr/bin/checkisomd5", None), ("jigdo", "/usr/bin/jigdo-lite", is_jigdo_needed), ("genisoimage", "/usr/bin/genisoimage", is_genisoimage_needed), - ("gettext", "/usr/bin/msgfmt", _will_productimg_run), ("syslinux", "/usr/bin/isohybrid", is_isohybrid_needed), # createrepo, modifyrepo and mergerepo are not needed by default, only when # createrepo_c is not configured @@ -1269,11 +1264,8 @@ def make_schema(): "signing_key_password_file": {"type": "string"}, "signing_command": {"type": "string"}, "productimg": { - "type": "boolean", - "default": False + "deprecated": "remove it. Productimg phase has been removed" }, - "productimg_install_class": {"$ref": "#/definitions/str_or_scm_dict"}, - "productimg_po_files": {"$ref": "#/definitions/str_or_scm_dict"}, "iso_size": { "anyOf": [ {"type": "string"}, @@ -1396,13 +1388,6 @@ def get_num_cpus(): # encountered and its value satisfies the lambda, an error is reported for each # missing (for requires) option in the list. CONFIG_DEPS = { - "productimg": { - "requires": ( - (lambda x: bool(x), ["productimg_install_class"]), - (lambda x: bool(x), ["productimg_po_files"]), - ), - }, - "buildinstall_method": { "conflicts": ( (lambda val: val == "buildinstall", ["lorax_options"]), diff --git a/pungi/metadata.py b/pungi/metadata.py index 2bdae802..0b15d2bf 100644 --- a/pungi/metadata.py +++ b/pungi/metadata.py @@ -332,14 +332,6 @@ def write_tree_info(compose, arch, variant, timestamp=None, bi=None): ti.images.images[platform][image] = path ti.checksums.add(path, createrepo_checksum, root_dir=os_tree) - # add product.img to images-$arch - product_img = os.path.join(os_tree, "images", "product.img") - product_img_relpath = relative_path(product_img, os_tree.rstrip("/") + "/") - if os.path.isfile(product_img): - for platform in ti.images.images: - ti.images.images[platform]["product.img"] = product_img_relpath - ti.checksums.add(product_img_relpath, createrepo_checksum, root_dir=os_tree) - path = os.path.join(compose.paths.compose.os_tree(arch=arch, variant=variant), ".treeinfo") compose.log_info("Writing treeinfo: %s" % path) ti.dump(path) diff --git a/pungi/paths.py b/pungi/paths.py index ab39b876..192d94a8 100644 --- a/pungi/paths.py +++ b/pungi/paths.py @@ -324,16 +324,6 @@ class WorkPaths(object): path = os.path.join(path, file_name) return path - def product_img(self, variant, create_dir=True): - """ - Examples: - work/global/product-Server.img - """ - file_name = "product-%s.img" % variant - path = self.topdir(arch="global", create_dir=create_dir) - path = os.path.join(path, file_name) - return path - def iso_dir(self, arch, filename, create_dir=True): """ Examples: diff --git a/pungi/phases/__init__.py b/pungi/phases/__init__.py index 0ed3e564..d71947b9 100644 --- a/pungi/phases/__init__.py +++ b/pungi/phases/__init__.py @@ -21,7 +21,6 @@ from .weaver import WeaverPhase # noqa from .pkgset import PkgsetPhase # noqa from .gather import GatherPhase # noqa from .createrepo import CreaterepoPhase # noqa -from .product_img import ProductimgPhase # noqa from .buildinstall import BuildinstallPhase # noqa from .extra_files import ExtraFilesPhase # noqa from .createiso import CreateisoPhase # noqa diff --git a/pungi/phases/product_img.py b/pungi/phases/product_img.py deleted file mode 100644 index fb29706d..00000000 --- a/pungi/phases/product_img.py +++ /dev/null @@ -1,276 +0,0 @@ -# -*- coding: utf-8 -*- - - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; version 2 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Library General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . - - -""" -Expected product.img paths -========================== - -RHEL 6 ------- -installclasses/$variant.py -locale/$lang/LC_MESSAGES/comps.mo - -RHEL 7 ------- -run/install/product/installclasses/$variant.py -run/install/product/locale/$lang/LC_MESSAGES/comps.mo - -Compatibility symlinks ----------------------- -installclasses -> run/install/product/installclasses -locale -> run/install/product/locale -run/install/product/pyanaconda/installclasses -> ../installclasses -""" - - -import os -import fnmatch -import shutil -from six.moves import shlex_quote - -from kobo.shortcuts import run - -from pungi.arch import split_name_arch -from pungi.util import makedirs, pkg_is_rpm -from pungi.phases.base import PhaseBase -from pungi.wrappers import iso -from pungi.wrappers.scm import get_file_from_scm, get_dir_from_scm - - -class ProductimgPhase(PhaseBase): - """PRODUCTIMG""" - name = "productimg" - - def __init__(self, compose, pkgset_phase): - PhaseBase.__init__(self, compose) - # pkgset_phase provides package_sets and path_prefix - self.pkgset_phase = pkgset_phase - - def skip(self): - if PhaseBase.skip(self): - return True - if not self.compose.conf["productimg"]: - msg = "Config option 'productimg' not set. Skipping creating product images." - self.compose.log_debug(msg) - return True - if not self.compose.conf["buildinstall_method"]: - msg = "Not a bootable product. Skipping creating product images." - self.compose.log_debug(msg) - return True - return False - - def run(self): - # create PRODUCT.IMG - for variant in self.compose.get_variants(): - if variant.type != "variant" or variant.is_empty: - continue - create_product_img(self.compose, "global", variant) - - # copy PRODUCT.IMG - for arch in self.compose.get_arches(): - for variant in self.compose.get_variants(arch=arch): - if variant.type != "variant" or variant.is_empty: - continue - image = self.compose.paths.work.product_img(variant) - os_tree = self.compose.paths.compose.os_tree(arch, variant) - target_dir = os.path.join(os_tree, "images") - target_path = os.path.join(target_dir, "product.img") - if not os.path.isfile(target_path): - makedirs(target_dir) - shutil.copy2(image, target_path) - - for arch in self.compose.get_arches(): - for variant in self.compose.get_variants(arch=arch): - if variant.type != "variant" or variant.is_empty: - continue - rebuild_boot_iso(self.compose, arch, variant, self.pkgset_phase.package_sets) - - -def create_product_img(compose, arch, variant): - # product.img is noarch (at least on rhel6 and rhel7) - arch = "global" - - msg = "Creating product.img (arch: %s, variant: %s)" % (arch, variant) - image = compose.paths.work.product_img(variant) - if os.path.exists(image): - compose.log_warning("[SKIP ] %s" % msg) - return - - compose.log_info("[BEGIN] %s" % msg) - - product_tmp = compose.mkdtemp(prefix="product_img_") - install_class = compose.conf["productimg_install_class"].copy() - install_class["file"] = install_class["file"] % {"variant_id": variant.id.lower()} - install_dir = os.path.join(product_tmp, "installclasses") - makedirs(install_dir) - get_file_from_scm(install_class, target_path=install_dir) - - po_files = compose.conf["productimg_po_files"] - po_tmp = compose.mkdtemp(prefix="pofiles_") - get_dir_from_scm(po_files, po_tmp, compose=compose) - for po_file in os.listdir(po_tmp): - if not po_file.endswith(".po"): - continue - lang = po_file[:-3] - target_dir = os.path.join(product_tmp, "locale", lang, "LC_MESSAGES") - makedirs(target_dir) - run(["msgfmt", "--output-file", os.path.join(target_dir, "comps.mo"), os.path.join(po_tmp, po_file)]) - - shutil.rmtree(po_tmp) - - ret, __ = run(["which", "guestmount"], can_fail=True) - guestmount_available = not bool(ret) # return code 0 means that guestmount is available - - mount_tmp = compose.mkdtemp(prefix="product_img_mount_") - cmds = [ - # allocate image - "dd if=/dev/zero of=%s bs=1k count=5760" % shlex_quote(image), - # create file system - "mke2fs -F %s" % shlex_quote(image), - # use guestmount to mount the image, which doesn't require root privileges - # LIBGUESTFS_BACKEND=direct: running qemu directly without libvirt - "LIBGUESTFS_BACKEND=direct guestmount -a %s -m /dev/sda %s" % (shlex_quote(image), shlex_quote(mount_tmp)) if guestmount_available - else "mount -o loop %s %s" % (shlex_quote(image), shlex_quote(mount_tmp)), - "mkdir -p %s/run/install/product" % shlex_quote(mount_tmp), - "cp -rp %s/* %s/run/install/product/" % (shlex_quote(product_tmp), shlex_quote(mount_tmp)), - "mkdir -p %s/run/install/product/pyanaconda" % shlex_quote(mount_tmp), - # compat symlink: installclasses -> run/install/product/installclasses - "ln -s run/install/product/installclasses %s" % shlex_quote(mount_tmp), - # compat symlink: locale -> run/install/product/locale - "ln -s run/install/product/locale %s" % shlex_quote(mount_tmp), - # compat symlink: run/install/product/pyanaconda/installclasses -> ../installclasses - "ln -s ../installclasses %s/run/install/product/pyanaconda/installclasses" % shlex_quote(mount_tmp), - "fusermount -u %s" % shlex_quote(mount_tmp) if guestmount_available - else "umount %s" % shlex_quote(mount_tmp), - # tweak last mount path written in the image - "tune2fs -M /run/install/product %s" % shlex_quote(image), - ] - run(" && ".join(cmds)) - shutil.rmtree(mount_tmp) - - shutil.rmtree(product_tmp) - - compose.log_info("[DONE ] %s" % msg) - - -def rebuild_boot_iso(compose, arch, variant, package_sets): - os_tree = compose.paths.compose.os_tree(arch, variant) - buildinstall_dir = compose.paths.work.buildinstall_dir(arch) - boot_iso = os.path.join(os_tree, "images", "boot.iso") - product_img = compose.paths.work.product_img(variant) - buildinstall_boot_iso = os.path.join(buildinstall_dir, "images", "boot.iso") - buildinstall_method = compose.conf["buildinstall_method"] - log_file = compose.paths.log.log_file(arch, "rebuild_boot_iso-%s.%s" % (variant, arch)) - - msg = "Rebuilding boot.iso (arch: %s, variant: %s)" % (arch, variant) - - if not os.path.isfile(boot_iso): - # nothing to do - compose.log_warning("[SKIP ] %s" % msg) - return - - compose.log_info("[BEGIN] %s" % msg) - - # read the original volume id - volume_id = iso.get_volume_id(boot_iso) - - # remove the original boot.iso (created during buildinstall) from the os dir - os.remove(boot_iso) - - tmp_dir = compose.mkdtemp(prefix="boot_iso_") - mount_dir = compose.mkdtemp(prefix="boot_iso_mount_") - - cmd = "mount -o loop %s %s" % (shlex_quote(buildinstall_boot_iso), shlex_quote(mount_dir)) - run(cmd, logfile=log_file, show_cmd=True) - - images_dir = os.path.join(tmp_dir, "images") - os.makedirs(images_dir) - shutil.copy2(product_img, os.path.join(images_dir, "product.img")) - - if os.path.isfile(os.path.join(mount_dir, "isolinux", "isolinux.bin")): - os.makedirs(os.path.join(tmp_dir, "isolinux")) - shutil.copy2(os.path.join(mount_dir, "isolinux", "isolinux.bin"), os.path.join(tmp_dir, "isolinux")) - - graft_points = iso.get_graft_points([mount_dir, tmp_dir]) - graft_points_path = os.path.join(compose.paths.work.topdir(arch=arch), "boot-%s.%s.iso-graft-points" % (variant, arch)) - iso.write_graft_points(graft_points_path, graft_points, exclude=["*/TRANS.TBL", "*/boot.cat"]) - - mkisofs_kwargs = {} - boot_files = None - if buildinstall_method == "lorax": - # TODO: $arch instead of ppc - mkisofs_kwargs["boot_args"] = iso.get_boot_options(arch, "/usr/share/lorax/config_files/ppc") - elif buildinstall_method == "buildinstall": - boot_files = explode_anaconda(compose, arch, variant, package_sets) - mkisofs_kwargs["boot_args"] = iso.get_boot_options(arch, boot_files) - - # ppc(64) doesn't seem to support utf-8 - if arch in ("ppc", "ppc64"): - mkisofs_kwargs["input_charset"] = None - - mkisofs_cmd = iso.get_mkisofs_cmd(boot_iso, None, volid=volume_id, exclude=["./lost+found"], graft_points=graft_points_path, **mkisofs_kwargs) - run(mkisofs_cmd, logfile=log_file, show_cmd=True) - - cmd = "umount %s" % shlex_quote(mount_dir) - run(cmd, logfile=log_file, show_cmd=True) - - if arch == "x86_64": - isohybrid_cmd = "isohybrid --uefi %s" % shlex_quote(boot_iso) - run(isohybrid_cmd, logfile=log_file, show_cmd=True) - elif arch == "i386": - isohybrid_cmd = "isohybrid %s" % shlex_quote(boot_iso) - run(isohybrid_cmd, logfile=log_file, show_cmd=True) - - # implant MD5SUM to iso - isomd5sum_cmd = iso.get_implantisomd5_cmd(boot_iso, compose.supported) - isomd5sum_cmd = " ".join([shlex_quote(i) for i in isomd5sum_cmd]) - run(isomd5sum_cmd, logfile=log_file, show_cmd=True) - - if boot_files: - shutil.rmtree(boot_files) - shutil.rmtree(tmp_dir) - shutil.rmtree(mount_dir) - - compose.log_info("[DONE ] %s" % msg) - - -def explode_anaconda(compose, arch, variant, package_sets): - tmp_dir = compose.mkdtemp(prefix="anaconda_") - scm_dict = { - "scm": "rpm", - "repo": "anaconda.%s" % arch, - "file": [ - "/usr/lib/anaconda-runtime/boot/*", - ] - } - # if scm is "rpm" and repo contains a package name, find the package(s) in package set - if scm_dict["scm"] == "rpm" and not (scm_dict["repo"].startswith("/") or "://" in scm_dict["repo"]): - rpms = [] - for pkgset in package_sets: - for pkgset_file in pkgset[arch]: - pkg_obj = pkgset[arch][pkgset_file] - if not pkg_is_rpm(pkg_obj): - continue - pkg_name, pkg_arch = split_name_arch(scm_dict["repo"]) - if fnmatch.fnmatch(pkg_obj.name, pkg_name) and (pkg_arch is None or pkg_arch == pkg_obj.arch): - compose.log_critical("%s %s %s" % (pkg_obj.name, pkg_name, pkg_arch)) - rpms.append(pkg_obj.file_path) - scm_dict["repo"] = rpms - - if not rpms: - return None - get_file_from_scm(scm_dict, tmp_dir, logger=compose._logger) - return tmp_dir diff --git a/pungi/scripts/config_validate.py b/pungi/scripts/config_validate.py index 68800981..0fa57689 100644 --- a/pungi/scripts/config_validate.py +++ b/pungi/scripts/config_validate.py @@ -115,7 +115,6 @@ def run(config, topdir, has_old, offline, defined_variables): pungi.phases.CreaterepoPhase(compose), pungi.phases.OstreeInstallerPhase(compose, buildinstall_phase), pungi.phases.OSTreePhase(compose), - pungi.phases.ProductimgPhase(compose, pkgset_phase), pungi.phases.CreateisoPhase(compose, buildinstall_phase), pungi.phases.ExtraIsosPhase(compose), pungi.phases.LiveImagesPhase(compose), diff --git a/pungi/scripts/pungi_koji.py b/pungi/scripts/pungi_koji.py index 48cbc25c..565ad678 100644 --- a/pungi/scripts/pungi_koji.py +++ b/pungi/scripts/pungi_koji.py @@ -35,6 +35,8 @@ COMPOSE = None def main(): global COMPOSE + PHASES_NAMES_MODIFIED = PHASES_NAMES + ['productimg'] + parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument( @@ -79,7 +81,7 @@ def main(): parser.add_argument( "--skip-phase", metavar="PHASE", - choices=PHASES_NAMES, + choices=PHASES_NAMES_MODIFIED, action="append", default=[], help="skip a compose phase", @@ -87,7 +89,7 @@ def main(): parser.add_argument( "--just-phase", metavar="PHASE", - choices=PHASES_NAMES, + choices=PHASES_NAMES_MODIFIED, action="append", default=[], help="run only a specified compose phase", @@ -224,6 +226,16 @@ def main(): if not pungi.checks.check_skip_phases(logger, opts.skip_phase): sys.exit(1) errors, warnings = pungi.checks.validate(conf) + + # TODO: workaround for config files containing skip_phase = productimg + # Remove when all config files are up to date + if 'productimg' in opts.skip_phase or 'productimg' in opts.just_phase: + print('WARNING: productimg phase has been removed, please remove it from --skip-phase or --just-phase option', file=sys.stderr) + for err in errors[:]: + if "'productimg' is not one of" in err: + errors.remove(err) + print("WARNING: %s" % err, file=sys.stderr) + if not opts.quiet: for warning in warnings: print(warning, file=sys.stderr) @@ -291,7 +303,6 @@ def run_compose(compose, create_latest_link=True, latest_link_status=None): createrepo_phase = pungi.phases.CreaterepoPhase(compose, pkgset_phase) ostree_installer_phase = pungi.phases.OstreeInstallerPhase(compose, buildinstall_phase, pkgset_phase) ostree_phase = pungi.phases.OSTreePhase(compose, pkgset_phase) - productimg_phase = pungi.phases.ProductimgPhase(compose, pkgset_phase) createiso_phase = pungi.phases.CreateisoPhase(compose, buildinstall_phase) extra_isos_phase = pungi.phases.ExtraIsosPhase(compose) liveimages_phase = pungi.phases.LiveImagesPhase(compose) @@ -303,7 +314,7 @@ def run_compose(compose, create_latest_link=True, latest_link_status=None): # check if all config options are set for phase in (init_phase, pkgset_phase, createrepo_phase, - buildinstall_phase, productimg_phase, gather_phase, + buildinstall_phase, gather_phase, extrafiles_phase, createiso_phase, liveimages_phase, livemedia_phase, image_build_phase, image_checksum_phase, test_phase, ostree_phase, ostree_installer_phase, @@ -374,9 +385,6 @@ def run_compose(compose, create_latest_link=True, latest_link_status=None): essentials_phase.start() essentials_phase.stop() - productimg_phase.start() - productimg_phase.stop() - # write treeinfo before ISOs are created for variant in compose.get_variants(): for arch in variant.arches + ["src"]: diff --git a/tests/test_checks.py b/tests/test_checks.py index 024553eb..1e1cbe35 100644 --- a/tests/test_checks.py +++ b/tests/test_checks.py @@ -89,8 +89,7 @@ class CheckDependenciesTestCase(unittest.TestCase): def test_isohybrid_not_required_on_arm(self): conf = { 'buildinstall_method': 'lorax', - 'productimg': True, - 'runroot_tag': 'dummy_tag', + 'runroot_tag': '', } with mock.patch('sys.stdout', new_callable=StringIO) as out: @@ -129,21 +128,6 @@ class CheckDependenciesTestCase(unittest.TestCase): self.assertEqual('', out.getvalue()) self.assertTrue(result) - def test_genisoimg_needed_for_productimg(self): - conf = { - 'runroot_tag': 'dummy_tag', - 'productimg': True, - 'buildinstall_method': 'lorax', - } - - with mock.patch('sys.stdout', new_callable=StringIO) as out: - with mock.patch('os.path.exists') as exists: - exists.side_effect = self.dont_find(['/usr/bin/genisoimage']) - result = checks.check(conf) - - self.assertIn('genisoimage', out.getvalue()) - self.assertFalse(result) - def test_requires_modifyrepo(self): with mock.patch('sys.stdout', new_callable=StringIO) as out: with mock.patch('os.path.exists') as exists: