from abc import ABCMeta, abstractmethod import os import re import bb class Manifest(object, metaclass=ABCMeta): """ This is an abstract class. Do not instantiate this directly. """ PKG_TYPE_MUST_INSTALL = "mip" PKG_TYPE_MULTILIB = "mlp" PKG_TYPE_LANGUAGE = "lgp" PKG_TYPE_ATTEMPT_ONLY = "aop" MANIFEST_TYPE_IMAGE = "image" MANIFEST_TYPE_SDK_HOST = "sdk_host" MANIFEST_TYPE_SDK_TARGET = "sdk_target" var_maps = { MANIFEST_TYPE_IMAGE: { "PACKAGE_INSTALL": PKG_TYPE_MUST_INSTALL, "PACKAGE_INSTALL_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY, "LINGUAS_INSTALL": PKG_TYPE_LANGUAGE }, MANIFEST_TYPE_SDK_HOST: { "TOOLCHAIN_HOST_TASK": PKG_TYPE_MUST_INSTALL, "TOOLCHAIN_HOST_TASK_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY }, MANIFEST_TYPE_SDK_TARGET: { "TOOLCHAIN_TARGET_TASK": PKG_TYPE_MUST_INSTALL, "TOOLCHAIN_TARGET_TASK_ATTEMPTONLY": PKG_TYPE_ATTEMPT_ONLY } } INSTALL_ORDER = [ PKG_TYPE_LANGUAGE, PKG_TYPE_MUST_INSTALL, PKG_TYPE_ATTEMPT_ONLY, PKG_TYPE_MULTILIB ] initial_manifest_file_header = \ "# This file was generated automatically and contains the packages\n" \ "# passed on to the package manager in order to create the rootfs.\n\n" \ "# Format:\n" \ "# ,\n" \ "# where:\n" \ "# can be:\n" \ "# 'mip' = must install package\n" \ "# 'aop' = attempt only package\n" \ "# 'mlp' = multilib package\n" \ "# 'lgp' = language package\n\n" def __init__(self, d, manifest_dir=None, manifest_type=MANIFEST_TYPE_IMAGE): self.d = d self.manifest_type = manifest_type if manifest_dir is None: if manifest_type != self.MANIFEST_TYPE_IMAGE: self.manifest_dir = self.d.getVar('SDK_DIR') else: self.manifest_dir = self.d.getVar('WORKDIR') else: self.manifest_dir = manifest_dir bb.utils.mkdirhier(self.manifest_dir) self.initial_manifest = os.path.join(self.manifest_dir, "%s_initial_manifest" % manifest_type) self.final_manifest = os.path.join(self.manifest_dir, "%s_final_manifest" % manifest_type) self.full_manifest = os.path.join(self.manifest_dir, "%s_full_manifest" % manifest_type) # packages in the following vars will be split in 'must install' and # 'multilib' self.vars_to_split = ["PACKAGE_INSTALL", "TOOLCHAIN_HOST_TASK", "TOOLCHAIN_TARGET_TASK"] """ This creates a standard initial manifest for core-image-(minimal|sato|sato-sdk). This will be used for testing until the class is implemented properly! """ def _create_dummy_initial(self): image_rootfs = self.d.getVar('IMAGE_ROOTFS') pkg_list = dict() if image_rootfs.find("core-image-sato-sdk") > 0: pkg_list[self.PKG_TYPE_MUST_INSTALL] = \ "packagegroup-core-x11-sato-games packagegroup-base-extended " \ "packagegroup-core-x11-sato packagegroup-core-x11-base " \ "packagegroup-core-sdk packagegroup-core-tools-debug " \ "packagegroup-core-boot packagegroup-core-tools-testapps " \ "packagegroup-core-eclipse-debug packagegroup-core-qt-demoapps " \ "apt packagegroup-core-tools-profile psplash " \ "packagegroup-core-standalone-sdk-target " \ "packagegroup-core-ssh-openssh dpkg kernel-dev" pkg_list[self.PKG_TYPE_LANGUAGE] = \ "locale-base-en-us locale-base-en-gb" elif image_rootfs.find("core-image-sato") > 0: pkg_list[self.PKG_TYPE_MUST_INSTALL] = \ "packagegroup-core-ssh-dropbear packagegroup-core-x11-sato-games " \ "packagegroup-core-x11-base psplash apt dpkg packagegroup-base-extended " \ "packagegroup-core-x11-sato packagegroup-core-boot" pkg_list['lgp'] = \ "locale-base-en-us locale-base-en-gb" elif image_rootfs.find("core-image-minimal") > 0: pkg_list[self.PKG_TYPE_MUST_INSTALL] = "packagegroup-core-boot" with open(self.initial_manifest, "w+") as manifest: manifest.write(self.initial_manifest_file_header) for pkg_type in pkg_list: for pkg in pkg_list[pkg_type].split(): manifest.write("%s,%s\n" % (pkg_type, pkg)) """ This will create the initial manifest which will be used by Rootfs class to generate the rootfs """ @abstractmethod def create_initial(self): pass """ This creates the manifest after everything has been installed. """ @abstractmethod def create_final(self): pass """ This creates the manifest after the package in initial manifest has been dummy installed. It lists all *to be installed* packages. There is no real installation, just a test. """ @abstractmethod def create_full(self, pm): pass """ The following function parses an initial manifest and returns a dictionary object with the must install, attempt only, multilib and language packages. """ def parse_initial_manifest(self): pkgs = dict() with open(self.initial_manifest) as manifest: for line in manifest.read().split('\n'): comment = re.match("^#.*", line) pattern = "^(%s|%s|%s|%s),(.*)$" % \ (self.PKG_TYPE_MUST_INSTALL, self.PKG_TYPE_ATTEMPT_ONLY, self.PKG_TYPE_MULTILIB, self.PKG_TYPE_LANGUAGE) pkg = re.match(pattern, line) if comment is not None: continue if pkg is not None: pkg_type = pkg.group(1) pkg_name = pkg.group(2) if not pkg_type in pkgs: pkgs[pkg_type] = [pkg_name] else: pkgs[pkg_type].append(pkg_name) return pkgs ''' This following function parses a full manifest and return a list object with packages. ''' def parse_full_manifest(self): installed_pkgs = list() if not os.path.exists(self.full_manifest): bb.note('full manifest not exist') return installed_pkgs with open(self.full_manifest, 'r') as manifest: for pkg in manifest.read().split('\n'): installed_pkgs.append(pkg.strip()) return installed_pkgs class RpmManifest(Manifest): """ Returns a dictionary object with mip and mlp packages. """ def _split_multilib(self, pkg_list): pkgs = dict() for pkg in pkg_list.split(): pkg_type = self.PKG_TYPE_MUST_INSTALL ml_variants = self.d.getVar('MULTILIB_VARIANTS').split() for ml_variant in ml_variants: if pkg.startswith(ml_variant + '-'): pkg_type = self.PKG_TYPE_MULTILIB if not pkg_type in pkgs: pkgs[pkg_type] = pkg else: pkgs[pkg_type] += " " + pkg return pkgs def create_initial(self): pkgs = dict() with open(self.initial_manifest, "w+") as manifest: manifest.write(self.initial_manifest_file_header) for var in self.var_maps[self.manifest_type]: if var in self.vars_to_split: split_pkgs = self._split_multilib(self.d.getVar(var)) if split_pkgs is not None: pkgs = dict(list(pkgs.items()) + list(split_pkgs.items())) else: pkg_list = self.d.getVar(var) if pkg_list is not None: pkgs[self.var_maps[self.manifest_type][var]] = self.d.getVar(var) for pkg_type in pkgs: for pkg in pkgs[pkg_type].split(): manifest.write("%s,%s\n" % (pkg_type, pkg)) def create_final(self): pass def create_full(self, pm): pass class OpkgManifest(Manifest): """ Returns a dictionary object with mip and mlp packages. """ def _split_multilib(self, pkg_list): pkgs = dict() for pkg in pkg_list.split(): pkg_type = self.PKG_TYPE_MUST_INSTALL ml_variants = self.d.getVar('MULTILIB_VARIANTS').split() for ml_variant in ml_variants: if pkg.startswith(ml_variant + '-'): pkg_type = self.PKG_TYPE_MULTILIB if not pkg_type in pkgs: pkgs[pkg_type] = pkg else: pkgs[pkg_type] += " " + pkg return pkgs def create_initial(self): pkgs = dict() with open(self.initial_manifest, "w+") as manifest: manifest.write(self.initial_manifest_file_header) for var in self.var_maps[self.manifest_type]: if var in self.vars_to_split: split_pkgs = self._split_multilib(self.d.getVar(var)) if split_pkgs is not None: pkgs = dict(list(pkgs.items()) + list(split_pkgs.items())) else: pkg_list = self.d.getVar(var) if pkg_list is not None: pkgs[self.var_maps[self.manifest_type][var]] = self.d.getVar(var) for pkg_type in sorted(pkgs): for pkg in sorted(pkgs[pkg_type].split()): manifest.write("%s,%s\n" % (pkg_type, pkg)) def create_final(self): pass def create_full(self, pm): if not os.path.exists(self.initial_manifest): self.create_initial() initial_manifest = self.parse_initial_manifest() pkgs_to_install = list() for pkg_type in initial_manifest: pkgs_to_install += initial_manifest[pkg_type] if len(pkgs_to_install) == 0: return output = pm.dummy_install(pkgs_to_install) with open(self.full_manifest, 'w+') as manifest: pkg_re = re.compile('^Installing ([^ ]+) [^ ].*') for line in set(output.split('\n')): m = pkg_re.match(line) if m: manifest.write(m.group(1) + '\n') return class DpkgManifest(Manifest): def create_initial(self): with open(self.initial_manifest, "w+") as manifest: manifest.write(self.initial_manifest_file_header) for var in self.var_maps[self.manifest_type]: pkg_list = self.d.getVar(var) if pkg_list is None: continue for pkg in pkg_list.split(): manifest.write("%s,%s\n" % (self.var_maps[self.manifest_type][var], pkg)) def create_final(self): pass def create_full(self, pm): pass def create_manifest(d, final_manifest=False, manifest_dir=None, manifest_type=Manifest.MANIFEST_TYPE_IMAGE): manifest_map = {'rpm': RpmManifest, 'ipk': OpkgManifest, 'deb': DpkgManifest} manifest = manifest_map[d.getVar('IMAGE_PKGTYPE')](d, manifest_dir, manifest_type) if final_manifest: manifest.create_final() else: manifest.create_initial() if __name__ == "__main__": pass