diff options
| author | Fredrik Gustafsson <fredrik.gustafsson@axis.com> | 2020-07-24 16:42:39 +0200 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2020-07-27 19:58:10 +0100 |
| commit | c5bea36b7275f1692f5847af84d320b674a4c62e (patch) | |
| tree | ad4222a7564b5710472b0673e0503cb03884f6d4 | |
| parent | 635305fe27b12fca554d694da00ba31d4b552d39 (diff) | |
| download | poky-c5bea36b7275f1692f5847af84d320b674a4c62e.tar.gz | |
rpm: Move package manager to its own dir
This is part of a refactor that will split the package manager
code so that it's possible to use other package managers in other
layers.
RP: Fixes to parse/build
(From OE-Core rev: 8b776ed9ed291dd8e112621561762449c7eb5ee2)
Signed-off-by: Fredrik Gustafsson <fredrigu@axis.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
| -rw-r--r-- | meta/lib/oe/package_manager/__init__.py | 400 | ||||
| -rw-r--r-- | meta/lib/oe/package_manager/rpm/__init__.py | 399 | ||||
| -rw-r--r-- | meta/lib/oe/package_manager/rpm/rootfs.py | 2 | ||||
| -rw-r--r-- | meta/lib/oe/package_manager/rpm/sdk.py | 2 | ||||
| -rw-r--r-- | meta/lib/oe/rootfs.py | 1 | ||||
| -rw-r--r-- | meta/lib/oe/sdk.py | 1 | ||||
| -rw-r--r-- | meta/lib/oeqa/utils/package_manager.py | 4 |
7 files changed, 408 insertions, 401 deletions
diff --git a/meta/lib/oe/package_manager/__init__.py b/meta/lib/oe/package_manager/__init__.py index 35e5cff073..36606d8cb3 100644 --- a/meta/lib/oe/package_manager/__init__.py +++ b/meta/lib/oe/package_manager/__init__.py | |||
| @@ -149,43 +149,6 @@ class Indexer(object, metaclass=ABCMeta): | |||
| 149 | def write_index(self): | 149 | def write_index(self): |
| 150 | pass | 150 | pass |
| 151 | 151 | ||
| 152 | |||
| 153 | class RpmIndexer(Indexer): | ||
| 154 | def write_index(self): | ||
| 155 | self.do_write_index(self.deploy_dir) | ||
| 156 | |||
| 157 | def do_write_index(self, deploy_dir): | ||
| 158 | if self.d.getVar('PACKAGE_FEED_SIGN') == '1': | ||
| 159 | signer = get_signer(self.d, self.d.getVar('PACKAGE_FEED_GPG_BACKEND')) | ||
| 160 | else: | ||
| 161 | signer = None | ||
| 162 | |||
| 163 | createrepo_c = bb.utils.which(os.environ['PATH'], "createrepo_c") | ||
| 164 | result = create_index("%s --update -q %s" % (createrepo_c, deploy_dir)) | ||
| 165 | if result: | ||
| 166 | bb.fatal(result) | ||
| 167 | |||
| 168 | # Sign repomd | ||
| 169 | if signer: | ||
| 170 | sig_type = self.d.getVar('PACKAGE_FEED_GPG_SIGNATURE_TYPE') | ||
| 171 | is_ascii_sig = (sig_type.upper() != "BIN") | ||
| 172 | signer.detach_sign(os.path.join(deploy_dir, 'repodata', 'repomd.xml'), | ||
| 173 | self.d.getVar('PACKAGE_FEED_GPG_NAME'), | ||
| 174 | self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE'), | ||
| 175 | armor=is_ascii_sig) | ||
| 176 | |||
| 177 | class RpmSubdirIndexer(RpmIndexer): | ||
| 178 | def write_index(self): | ||
| 179 | bb.note("Generating package index for %s" %(self.deploy_dir)) | ||
| 180 | self.do_write_index(self.deploy_dir) | ||
| 181 | for entry in os.walk(self.deploy_dir): | ||
| 182 | if os.path.samefile(self.deploy_dir, entry[0]): | ||
| 183 | for dir in entry[1]: | ||
| 184 | if dir != 'repodata': | ||
| 185 | dir_path = oe.path.join(self.deploy_dir, dir) | ||
| 186 | bb.note("Generating package index for %s" %(dir_path)) | ||
| 187 | self.do_write_index(dir_path) | ||
| 188 | |||
| 189 | class OpkgIndexer(Indexer): | 152 | class OpkgIndexer(Indexer): |
| 190 | def write_index(self): | 153 | def write_index(self): |
| 191 | arch_vars = ["ALL_MULTILIB_PACKAGE_ARCHS", | 154 | arch_vars = ["ALL_MULTILIB_PACKAGE_ARCHS", |
| @@ -323,10 +286,6 @@ class PkgsList(object, metaclass=ABCMeta): | |||
| 323 | def list_pkgs(self): | 286 | def list_pkgs(self): |
| 324 | pass | 287 | pass |
| 325 | 288 | ||
| 326 | class RpmPkgsList(PkgsList): | ||
| 327 | def list_pkgs(self): | ||
| 328 | return RpmPM(self.d, self.rootfs_dir, self.d.getVar('TARGET_VENDOR'), needfeed=False).list_installed() | ||
| 329 | |||
| 330 | class OpkgPkgsList(PkgsList): | 289 | class OpkgPkgsList(PkgsList): |
| 331 | def __init__(self, d, rootfs_dir, config_file): | 290 | def __init__(self, d, rootfs_dir, config_file): |
| 332 | super(OpkgPkgsList, self).__init__(d, rootfs_dir) | 291 | super(OpkgPkgsList, self).__init__(d, rootfs_dir) |
| @@ -737,363 +696,6 @@ def create_packages_dir(d, subrepo_dir, deploydir, taskname, filterbydependencie | |||
| 737 | else: | 696 | else: |
| 738 | raise | 697 | raise |
| 739 | 698 | ||
| 740 | class RpmPM(PackageManager): | ||
| 741 | def __init__(self, | ||
| 742 | d, | ||
| 743 | target_rootfs, | ||
| 744 | target_vendor, | ||
| 745 | task_name='target', | ||
| 746 | arch_var=None, | ||
| 747 | os_var=None, | ||
| 748 | rpm_repo_workdir="oe-rootfs-repo", | ||
| 749 | filterbydependencies=True, | ||
| 750 | needfeed=True): | ||
| 751 | super(RpmPM, self).__init__(d, target_rootfs) | ||
| 752 | self.target_vendor = target_vendor | ||
| 753 | self.task_name = task_name | ||
| 754 | if arch_var == None: | ||
| 755 | self.archs = self.d.getVar('ALL_MULTILIB_PACKAGE_ARCHS').replace("-","_") | ||
| 756 | else: | ||
| 757 | self.archs = self.d.getVar(arch_var).replace("-","_") | ||
| 758 | if task_name == "host": | ||
| 759 | self.primary_arch = self.d.getVar('SDK_ARCH') | ||
| 760 | else: | ||
| 761 | self.primary_arch = self.d.getVar('MACHINE_ARCH') | ||
| 762 | |||
| 763 | if needfeed: | ||
| 764 | self.rpm_repo_dir = oe.path.join(self.d.getVar('WORKDIR'), rpm_repo_workdir) | ||
| 765 | create_packages_dir(self.d, oe.path.join(self.rpm_repo_dir, "rpm"), d.getVar("DEPLOY_DIR_RPM"), "package_write_rpm", filterbydependencies) | ||
| 766 | |||
| 767 | self.saved_packaging_data = self.d.expand('${T}/saved_packaging_data/%s' % self.task_name) | ||
| 768 | if not os.path.exists(self.d.expand('${T}/saved_packaging_data')): | ||
| 769 | bb.utils.mkdirhier(self.d.expand('${T}/saved_packaging_data')) | ||
| 770 | self.packaging_data_dirs = ['etc/rpm', 'etc/rpmrc', 'etc/dnf', 'var/lib/rpm', 'var/lib/dnf', 'var/cache/dnf'] | ||
| 771 | self.solution_manifest = self.d.expand('${T}/saved/%s_solution' % | ||
| 772 | self.task_name) | ||
| 773 | if not os.path.exists(self.d.expand('${T}/saved')): | ||
| 774 | bb.utils.mkdirhier(self.d.expand('${T}/saved')) | ||
| 775 | |||
| 776 | def _configure_dnf(self): | ||
| 777 | # libsolv handles 'noarch' internally, we don't need to specify it explicitly | ||
| 778 | archs = [i for i in reversed(self.archs.split()) if i not in ["any", "all", "noarch"]] | ||
| 779 | # This prevents accidental matching against libsolv's built-in policies | ||
| 780 | if len(archs) <= 1: | ||
| 781 | archs = archs + ["bogusarch"] | ||
| 782 | # This architecture needs to be upfront so that packages using it are properly prioritized | ||
| 783 | archs = ["sdk_provides_dummy_target"] + archs | ||
| 784 | confdir = "%s/%s" %(self.target_rootfs, "etc/dnf/vars/") | ||
| 785 | bb.utils.mkdirhier(confdir) | ||
| 786 | open(confdir + "arch", 'w').write(":".join(archs)) | ||
| 787 | distro_codename = self.d.getVar('DISTRO_CODENAME') | ||
| 788 | open(confdir + "releasever", 'w').write(distro_codename if distro_codename is not None else '') | ||
| 789 | |||
| 790 | open(oe.path.join(self.target_rootfs, "etc/dnf/dnf.conf"), 'w').write("") | ||
| 791 | |||
| 792 | |||
| 793 | def _configure_rpm(self): | ||
| 794 | # We need to configure rpm to use our primary package architecture as the installation architecture, | ||
| 795 | # and to make it compatible with other package architectures that we use. | ||
| 796 | # Otherwise it will refuse to proceed with packages installation. | ||
| 797 | platformconfdir = "%s/%s" %(self.target_rootfs, "etc/rpm/") | ||
| 798 | rpmrcconfdir = "%s/%s" %(self.target_rootfs, "etc/") | ||
| 799 | bb.utils.mkdirhier(platformconfdir) | ||
| 800 | open(platformconfdir + "platform", 'w').write("%s-pc-linux" % self.primary_arch) | ||
| 801 | with open(rpmrcconfdir + "rpmrc", 'w') as f: | ||
| 802 | f.write("arch_compat: %s: %s\n" % (self.primary_arch, self.archs if len(self.archs) > 0 else self.primary_arch)) | ||
| 803 | f.write("buildarch_compat: %s: noarch\n" % self.primary_arch) | ||
| 804 | |||
| 805 | open(platformconfdir + "macros", 'w').write("%_transaction_color 7\n") | ||
| 806 | if self.d.getVar('RPM_PREFER_ELF_ARCH'): | ||
| 807 | open(platformconfdir + "macros", 'a').write("%%_prefer_color %s" % (self.d.getVar('RPM_PREFER_ELF_ARCH'))) | ||
| 808 | |||
| 809 | if self.d.getVar('RPM_SIGN_PACKAGES') == '1': | ||
| 810 | signer = get_signer(self.d, self.d.getVar('RPM_GPG_BACKEND')) | ||
| 811 | pubkey_path = oe.path.join(self.d.getVar('B'), 'rpm-key') | ||
| 812 | signer.export_pubkey(pubkey_path, self.d.getVar('RPM_GPG_NAME')) | ||
| 813 | rpm_bin = bb.utils.which(os.getenv('PATH'), "rpmkeys") | ||
| 814 | cmd = [rpm_bin, '--root=%s' % self.target_rootfs, '--import', pubkey_path] | ||
| 815 | try: | ||
| 816 | subprocess.check_output(cmd, stderr=subprocess.STDOUT) | ||
| 817 | except subprocess.CalledProcessError as e: | ||
| 818 | bb.fatal("Importing GPG key failed. Command '%s' " | ||
| 819 | "returned %d:\n%s" % (' '.join(cmd), e.returncode, e.output.decode("utf-8"))) | ||
| 820 | |||
| 821 | def create_configs(self): | ||
| 822 | self._configure_dnf() | ||
| 823 | self._configure_rpm() | ||
| 824 | |||
| 825 | def write_index(self): | ||
| 826 | lockfilename = self.d.getVar('DEPLOY_DIR_RPM') + "/rpm.lock" | ||
| 827 | lf = bb.utils.lockfile(lockfilename, False) | ||
| 828 | RpmIndexer(self.d, self.rpm_repo_dir).write_index() | ||
| 829 | bb.utils.unlockfile(lf) | ||
| 830 | |||
| 831 | def insert_feeds_uris(self, feed_uris, feed_base_paths, feed_archs): | ||
| 832 | from urllib.parse import urlparse | ||
| 833 | |||
| 834 | if feed_uris == "": | ||
| 835 | return | ||
| 836 | |||
| 837 | gpg_opts = '' | ||
| 838 | if self.d.getVar('PACKAGE_FEED_SIGN') == '1': | ||
| 839 | gpg_opts += 'repo_gpgcheck=1\n' | ||
| 840 | gpg_opts += 'gpgkey=file://%s/pki/packagefeed-gpg/PACKAGEFEED-GPG-KEY-%s-%s\n' % (self.d.getVar('sysconfdir'), self.d.getVar('DISTRO'), self.d.getVar('DISTRO_CODENAME')) | ||
| 841 | |||
| 842 | if self.d.getVar('RPM_SIGN_PACKAGES') != '1': | ||
| 843 | gpg_opts += 'gpgcheck=0\n' | ||
| 844 | |||
| 845 | bb.utils.mkdirhier(oe.path.join(self.target_rootfs, "etc", "yum.repos.d")) | ||
| 846 | remote_uris = self.construct_uris(feed_uris.split(), feed_base_paths.split()) | ||
| 847 | for uri in remote_uris: | ||
| 848 | repo_base = "oe-remote-repo" + "-".join(urlparse(uri).path.split("/")) | ||
| 849 | if feed_archs is not None: | ||
| 850 | for arch in feed_archs.split(): | ||
| 851 | repo_uri = uri + "/" + arch | ||
| 852 | repo_id = "oe-remote-repo" + "-".join(urlparse(repo_uri).path.split("/")) | ||
| 853 | repo_name = "OE Remote Repo:" + " ".join(urlparse(repo_uri).path.split("/")) | ||
| 854 | open(oe.path.join(self.target_rootfs, "etc", "yum.repos.d", repo_base + ".repo"), 'a').write( | ||
| 855 | "[%s]\nname=%s\nbaseurl=%s\n%s\n" % (repo_id, repo_name, repo_uri, gpg_opts)) | ||
| 856 | else: | ||
| 857 | repo_name = "OE Remote Repo:" + " ".join(urlparse(uri).path.split("/")) | ||
| 858 | repo_uri = uri | ||
| 859 | open(oe.path.join(self.target_rootfs, "etc", "yum.repos.d", repo_base + ".repo"), 'w').write( | ||
| 860 | "[%s]\nname=%s\nbaseurl=%s\n%s" % (repo_base, repo_name, repo_uri, gpg_opts)) | ||
| 861 | |||
| 862 | def _prepare_pkg_transaction(self): | ||
| 863 | os.environ['D'] = self.target_rootfs | ||
| 864 | os.environ['OFFLINE_ROOT'] = self.target_rootfs | ||
| 865 | os.environ['IPKG_OFFLINE_ROOT'] = self.target_rootfs | ||
| 866 | os.environ['OPKG_OFFLINE_ROOT'] = self.target_rootfs | ||
| 867 | os.environ['INTERCEPT_DIR'] = self.intercepts_dir | ||
| 868 | os.environ['NATIVE_ROOT'] = self.d.getVar('STAGING_DIR_NATIVE') | ||
| 869 | |||
| 870 | |||
| 871 | def install(self, pkgs, attempt_only = False): | ||
| 872 | if len(pkgs) == 0: | ||
| 873 | return | ||
| 874 | self._prepare_pkg_transaction() | ||
| 875 | |||
| 876 | bad_recommendations = self.d.getVar('BAD_RECOMMENDATIONS') | ||
| 877 | package_exclude = self.d.getVar('PACKAGE_EXCLUDE') | ||
| 878 | exclude_pkgs = (bad_recommendations.split() if bad_recommendations else []) + (package_exclude.split() if package_exclude else []) | ||
| 879 | |||
| 880 | output = self._invoke_dnf((["--skip-broken"] if attempt_only else []) + | ||
| 881 | (["-x", ",".join(exclude_pkgs)] if len(exclude_pkgs) > 0 else []) + | ||
| 882 | (["--setopt=install_weak_deps=False"] if self.d.getVar('NO_RECOMMENDATIONS') == "1" else []) + | ||
| 883 | (["--nogpgcheck"] if self.d.getVar('RPM_SIGN_PACKAGES') != '1' else ["--setopt=gpgcheck=True"]) + | ||
| 884 | ["install"] + | ||
| 885 | pkgs) | ||
| 886 | |||
| 887 | failed_scriptlets_pkgnames = collections.OrderedDict() | ||
| 888 | for line in output.splitlines(): | ||
| 889 | if line.startswith("Error in POSTIN scriptlet in rpm package"): | ||
| 890 | failed_scriptlets_pkgnames[line.split()[-1]] = True | ||
| 891 | |||
| 892 | if len(failed_scriptlets_pkgnames) > 0: | ||
| 893 | failed_postinsts_abort(list(failed_scriptlets_pkgnames.keys()), self.d.expand("${T}/log.do_${BB_CURRENTTASK}")) | ||
| 894 | |||
| 895 | def remove(self, pkgs, with_dependencies = True): | ||
| 896 | if not pkgs: | ||
| 897 | return | ||
| 898 | |||
| 899 | self._prepare_pkg_transaction() | ||
| 900 | |||
| 901 | if with_dependencies: | ||
| 902 | self._invoke_dnf(["remove"] + pkgs) | ||
| 903 | else: | ||
| 904 | cmd = bb.utils.which(os.getenv('PATH'), "rpm") | ||
| 905 | args = ["-e", "-v", "--nodeps", "--root=%s" %self.target_rootfs] | ||
| 906 | |||
| 907 | try: | ||
| 908 | bb.note("Running %s" % ' '.join([cmd] + args + pkgs)) | ||
| 909 | output = subprocess.check_output([cmd] + args + pkgs, stderr=subprocess.STDOUT).decode("utf-8") | ||
| 910 | bb.note(output) | ||
| 911 | except subprocess.CalledProcessError as e: | ||
| 912 | bb.fatal("Could not invoke rpm. Command " | ||
| 913 | "'%s' returned %d:\n%s" % (' '.join([cmd] + args + pkgs), e.returncode, e.output.decode("utf-8"))) | ||
| 914 | |||
| 915 | def upgrade(self): | ||
| 916 | self._prepare_pkg_transaction() | ||
| 917 | self._invoke_dnf(["upgrade"]) | ||
| 918 | |||
| 919 | def autoremove(self): | ||
| 920 | self._prepare_pkg_transaction() | ||
| 921 | self._invoke_dnf(["autoremove"]) | ||
| 922 | |||
| 923 | def remove_packaging_data(self): | ||
| 924 | self._invoke_dnf(["clean", "all"]) | ||
| 925 | for dir in self.packaging_data_dirs: | ||
| 926 | bb.utils.remove(oe.path.join(self.target_rootfs, dir), True) | ||
| 927 | |||
| 928 | def backup_packaging_data(self): | ||
| 929 | # Save the packaging dirs for increment rpm image generation | ||
| 930 | if os.path.exists(self.saved_packaging_data): | ||
| 931 | bb.utils.remove(self.saved_packaging_data, True) | ||
| 932 | for i in self.packaging_data_dirs: | ||
| 933 | source_dir = oe.path.join(self.target_rootfs, i) | ||
| 934 | target_dir = oe.path.join(self.saved_packaging_data, i) | ||
| 935 | if os.path.isdir(source_dir): | ||
| 936 | shutil.copytree(source_dir, target_dir, symlinks=True) | ||
| 937 | elif os.path.isfile(source_dir): | ||
| 938 | shutil.copy2(source_dir, target_dir) | ||
| 939 | |||
| 940 | def recovery_packaging_data(self): | ||
| 941 | # Move the rpmlib back | ||
| 942 | if os.path.exists(self.saved_packaging_data): | ||
| 943 | for i in self.packaging_data_dirs: | ||
| 944 | target_dir = oe.path.join(self.target_rootfs, i) | ||
| 945 | if os.path.exists(target_dir): | ||
| 946 | bb.utils.remove(target_dir, True) | ||
| 947 | source_dir = oe.path.join(self.saved_packaging_data, i) | ||
| 948 | if os.path.isdir(source_dir): | ||
| 949 | shutil.copytree(source_dir, target_dir, symlinks=True) | ||
| 950 | elif os.path.isfile(source_dir): | ||
| 951 | shutil.copy2(source_dir, target_dir) | ||
| 952 | |||
| 953 | def list_installed(self): | ||
| 954 | output = self._invoke_dnf(["repoquery", "--installed", "--queryformat", "Package: %{name} %{arch} %{version} %{name}-%{version}-%{release}.%{arch}.rpm\nDependencies:\n%{requires}\nRecommendations:\n%{recommends}\nDependenciesEndHere:\n"], | ||
| 955 | print_output = False) | ||
| 956 | packages = {} | ||
| 957 | current_package = None | ||
| 958 | current_deps = None | ||
| 959 | current_state = "initial" | ||
| 960 | for line in output.splitlines(): | ||
| 961 | if line.startswith("Package:"): | ||
| 962 | package_info = line.split(" ")[1:] | ||
| 963 | current_package = package_info[0] | ||
| 964 | package_arch = package_info[1] | ||
| 965 | package_version = package_info[2] | ||
| 966 | package_rpm = package_info[3] | ||
| 967 | packages[current_package] = {"arch":package_arch, "ver":package_version, "filename":package_rpm} | ||
| 968 | current_deps = [] | ||
| 969 | elif line.startswith("Dependencies:"): | ||
| 970 | current_state = "dependencies" | ||
| 971 | elif line.startswith("Recommendations"): | ||
| 972 | current_state = "recommendations" | ||
| 973 | elif line.startswith("DependenciesEndHere:"): | ||
| 974 | current_state = "initial" | ||
| 975 | packages[current_package]["deps"] = current_deps | ||
| 976 | elif len(line) > 0: | ||
| 977 | if current_state == "dependencies": | ||
| 978 | current_deps.append(line) | ||
| 979 | elif current_state == "recommendations": | ||
| 980 | current_deps.append("%s [REC]" % line) | ||
| 981 | |||
| 982 | return packages | ||
| 983 | |||
| 984 | def update(self): | ||
| 985 | self._invoke_dnf(["makecache", "--refresh"]) | ||
| 986 | |||
| 987 | def _invoke_dnf(self, dnf_args, fatal = True, print_output = True ): | ||
| 988 | os.environ['RPM_ETCCONFIGDIR'] = self.target_rootfs | ||
| 989 | |||
| 990 | dnf_cmd = bb.utils.which(os.getenv('PATH'), "dnf") | ||
| 991 | standard_dnf_args = ["-v", "--rpmverbosity=info", "-y", | ||
| 992 | "-c", oe.path.join(self.target_rootfs, "etc/dnf/dnf.conf"), | ||
| 993 | "--setopt=reposdir=%s" %(oe.path.join(self.target_rootfs, "etc/yum.repos.d")), | ||
| 994 | "--installroot=%s" % (self.target_rootfs), | ||
| 995 | "--setopt=logdir=%s" % (self.d.getVar('T')) | ||
| 996 | ] | ||
| 997 | if hasattr(self, "rpm_repo_dir"): | ||
| 998 | standard_dnf_args.append("--repofrompath=oe-repo,%s" % (self.rpm_repo_dir)) | ||
| 999 | cmd = [dnf_cmd] + standard_dnf_args + dnf_args | ||
| 1000 | bb.note('Running %s' % ' '.join(cmd)) | ||
| 1001 | try: | ||
| 1002 | output = subprocess.check_output(cmd,stderr=subprocess.STDOUT).decode("utf-8") | ||
| 1003 | if print_output: | ||
| 1004 | bb.debug(1, output) | ||
| 1005 | return output | ||
| 1006 | except subprocess.CalledProcessError as e: | ||
| 1007 | if print_output: | ||
| 1008 | (bb.note, bb.fatal)[fatal]("Could not invoke dnf. Command " | ||
| 1009 | "'%s' returned %d:\n%s" % (' '.join(cmd), e.returncode, e.output.decode("utf-8"))) | ||
| 1010 | else: | ||
| 1011 | (bb.note, bb.fatal)[fatal]("Could not invoke dnf. Command " | ||
| 1012 | "'%s' returned %d:" % (' '.join(cmd), e.returncode)) | ||
| 1013 | return e.output.decode("utf-8") | ||
| 1014 | |||
| 1015 | def dump_install_solution(self, pkgs): | ||
| 1016 | open(self.solution_manifest, 'w').write(" ".join(pkgs)) | ||
| 1017 | return pkgs | ||
| 1018 | |||
| 1019 | def load_old_install_solution(self): | ||
| 1020 | if not os.path.exists(self.solution_manifest): | ||
| 1021 | return [] | ||
| 1022 | with open(self.solution_manifest, 'r') as fd: | ||
| 1023 | return fd.read().split() | ||
| 1024 | |||
| 1025 | def _script_num_prefix(self, path): | ||
| 1026 | files = os.listdir(path) | ||
| 1027 | numbers = set() | ||
| 1028 | numbers.add(99) | ||
| 1029 | for f in files: | ||
| 1030 | numbers.add(int(f.split("-")[0])) | ||
| 1031 | return max(numbers) + 1 | ||
| 1032 | |||
| 1033 | def save_rpmpostinst(self, pkg): | ||
| 1034 | bb.note("Saving postinstall script of %s" % (pkg)) | ||
| 1035 | cmd = bb.utils.which(os.getenv('PATH'), "rpm") | ||
| 1036 | args = ["-q", "--root=%s" % self.target_rootfs, "--queryformat", "%{postin}", pkg] | ||
| 1037 | |||
| 1038 | try: | ||
| 1039 | output = subprocess.check_output([cmd] + args,stderr=subprocess.STDOUT).decode("utf-8") | ||
| 1040 | except subprocess.CalledProcessError as e: | ||
| 1041 | bb.fatal("Could not invoke rpm. Command " | ||
| 1042 | "'%s' returned %d:\n%s" % (' '.join([cmd] + args), e.returncode, e.output.decode("utf-8"))) | ||
| 1043 | |||
| 1044 | # may need to prepend #!/bin/sh to output | ||
| 1045 | |||
| 1046 | target_path = oe.path.join(self.target_rootfs, self.d.expand('${sysconfdir}/rpm-postinsts/')) | ||
| 1047 | bb.utils.mkdirhier(target_path) | ||
| 1048 | num = self._script_num_prefix(target_path) | ||
| 1049 | saved_script_name = oe.path.join(target_path, "%d-%s" % (num, pkg)) | ||
| 1050 | open(saved_script_name, 'w').write(output) | ||
| 1051 | os.chmod(saved_script_name, 0o755) | ||
| 1052 | |||
| 1053 | def _handle_intercept_failure(self, registered_pkgs): | ||
| 1054 | rpm_postinsts_dir = self.target_rootfs + self.d.expand('${sysconfdir}/rpm-postinsts/') | ||
| 1055 | bb.utils.mkdirhier(rpm_postinsts_dir) | ||
| 1056 | |||
| 1057 | # Save the package postinstalls in /etc/rpm-postinsts | ||
| 1058 | for pkg in registered_pkgs.split(): | ||
| 1059 | self.save_rpmpostinst(pkg) | ||
| 1060 | |||
| 1061 | def extract(self, pkg): | ||
| 1062 | output = self._invoke_dnf(["repoquery", "--queryformat", "%{location}", pkg]) | ||
| 1063 | pkg_name = output.splitlines()[-1] | ||
| 1064 | if not pkg_name.endswith(".rpm"): | ||
| 1065 | bb.fatal("dnf could not find package %s in repository: %s" %(pkg, output)) | ||
| 1066 | pkg_path = oe.path.join(self.rpm_repo_dir, pkg_name) | ||
| 1067 | |||
| 1068 | cpio_cmd = bb.utils.which(os.getenv("PATH"), "cpio") | ||
| 1069 | rpm2cpio_cmd = bb.utils.which(os.getenv("PATH"), "rpm2cpio") | ||
| 1070 | |||
| 1071 | if not os.path.isfile(pkg_path): | ||
| 1072 | bb.fatal("Unable to extract package for '%s'." | ||
| 1073 | "File %s doesn't exists" % (pkg, pkg_path)) | ||
| 1074 | |||
| 1075 | tmp_dir = tempfile.mkdtemp() | ||
| 1076 | current_dir = os.getcwd() | ||
| 1077 | os.chdir(tmp_dir) | ||
| 1078 | |||
| 1079 | try: | ||
| 1080 | cmd = "%s %s | %s -idmv" % (rpm2cpio_cmd, pkg_path, cpio_cmd) | ||
| 1081 | output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) | ||
| 1082 | except subprocess.CalledProcessError as e: | ||
| 1083 | bb.utils.remove(tmp_dir, recurse=True) | ||
| 1084 | bb.fatal("Unable to extract %s package. Command '%s' " | ||
| 1085 | "returned %d:\n%s" % (pkg_path, cmd, e.returncode, e.output.decode("utf-8"))) | ||
| 1086 | except OSError as e: | ||
| 1087 | bb.utils.remove(tmp_dir, recurse=True) | ||
| 1088 | bb.fatal("Unable to extract %s package. Command '%s' " | ||
| 1089 | "returned %d:\n%s at %s" % (pkg_path, cmd, e.errno, e.strerror, e.filename)) | ||
| 1090 | |||
| 1091 | bb.note("Extracted %s to %s" % (pkg_path, tmp_dir)) | ||
| 1092 | os.chdir(current_dir) | ||
| 1093 | |||
| 1094 | return tmp_dir | ||
| 1095 | |||
| 1096 | |||
| 1097 | class OpkgDpkgPM(PackageManager): | 699 | class OpkgDpkgPM(PackageManager): |
| 1098 | def __init__(self, d, target_rootfs): | 700 | def __init__(self, d, target_rootfs): |
| 1099 | """ | 701 | """ |
| @@ -1842,6 +1444,8 @@ class DpkgPM(OpkgDpkgPM): | |||
| 1842 | return tmp_dir | 1444 | return tmp_dir |
| 1843 | 1445 | ||
| 1844 | def generate_index_files(d): | 1446 | def generate_index_files(d): |
| 1447 | from oe.package_manager.rpm import RpmSubdirIndexer | ||
| 1448 | |||
| 1845 | classes = d.getVar('PACKAGE_CLASSES').replace("package_", "").split() | 1449 | classes = d.getVar('PACKAGE_CLASSES').replace("package_", "").split() |
| 1846 | 1450 | ||
| 1847 | indexer_map = { | 1451 | indexer_map = { |
diff --git a/meta/lib/oe/package_manager/rpm/__init__.py b/meta/lib/oe/package_manager/rpm/__init__.py index a2094304c9..6183f81d58 100644 --- a/meta/lib/oe/package_manager/rpm/__init__.py +++ b/meta/lib/oe/package_manager/rpm/__init__.py | |||
| @@ -1,3 +1,402 @@ | |||
| 1 | # | 1 | # |
| 2 | # SPDX-License-Identifier: GPL-2.0-only | 2 | # SPDX-License-Identifier: GPL-2.0-only |
| 3 | # | 3 | # |
| 4 | |||
| 5 | from oe.package_manager import * | ||
| 6 | |||
| 7 | class RpmIndexer(Indexer): | ||
| 8 | def write_index(self): | ||
| 9 | self.do_write_index(self.deploy_dir) | ||
| 10 | |||
| 11 | def do_write_index(self, deploy_dir): | ||
| 12 | if self.d.getVar('PACKAGE_FEED_SIGN') == '1': | ||
| 13 | signer = get_signer(self.d, self.d.getVar('PACKAGE_FEED_GPG_BACKEND')) | ||
| 14 | else: | ||
| 15 | signer = None | ||
| 16 | |||
| 17 | createrepo_c = bb.utils.which(os.environ['PATH'], "createrepo_c") | ||
| 18 | result = create_index("%s --update -q %s" % (createrepo_c, deploy_dir)) | ||
| 19 | if result: | ||
| 20 | bb.fatal(result) | ||
| 21 | |||
| 22 | # Sign repomd | ||
| 23 | if signer: | ||
| 24 | sig_type = self.d.getVar('PACKAGE_FEED_GPG_SIGNATURE_TYPE') | ||
| 25 | is_ascii_sig = (sig_type.upper() != "BIN") | ||
| 26 | signer.detach_sign(os.path.join(deploy_dir, 'repodata', 'repomd.xml'), | ||
| 27 | self.d.getVar('PACKAGE_FEED_GPG_NAME'), | ||
| 28 | self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE'), | ||
| 29 | armor=is_ascii_sig) | ||
| 30 | |||
| 31 | class RpmSubdirIndexer(RpmIndexer): | ||
| 32 | def write_index(self): | ||
| 33 | bb.note("Generating package index for %s" %(self.deploy_dir)) | ||
| 34 | self.do_write_index(self.deploy_dir) | ||
| 35 | for entry in os.walk(self.deploy_dir): | ||
| 36 | if os.path.samefile(self.deploy_dir, entry[0]): | ||
| 37 | for dir in entry[1]: | ||
| 38 | if dir != 'repodata': | ||
| 39 | dir_path = oe.path.join(self.deploy_dir, dir) | ||
| 40 | bb.note("Generating package index for %s" %(dir_path)) | ||
| 41 | self.do_write_index(dir_path) | ||
| 42 | |||
| 43 | |||
| 44 | class RpmPkgsList(PkgsList): | ||
| 45 | def list_pkgs(self): | ||
| 46 | return RpmPM(self.d, self.rootfs_dir, self.d.getVar('TARGET_VENDOR'), needfeed=False).list_installed() | ||
| 47 | |||
| 48 | class RpmPM(PackageManager): | ||
| 49 | def __init__(self, | ||
| 50 | d, | ||
| 51 | target_rootfs, | ||
| 52 | target_vendor, | ||
| 53 | task_name='target', | ||
| 54 | arch_var=None, | ||
| 55 | os_var=None, | ||
| 56 | rpm_repo_workdir="oe-rootfs-repo", | ||
| 57 | filterbydependencies=True, | ||
| 58 | needfeed=True): | ||
| 59 | super(RpmPM, self).__init__(d, target_rootfs) | ||
| 60 | self.target_vendor = target_vendor | ||
| 61 | self.task_name = task_name | ||
| 62 | if arch_var == None: | ||
| 63 | self.archs = self.d.getVar('ALL_MULTILIB_PACKAGE_ARCHS').replace("-","_") | ||
| 64 | else: | ||
| 65 | self.archs = self.d.getVar(arch_var).replace("-","_") | ||
| 66 | if task_name == "host": | ||
| 67 | self.primary_arch = self.d.getVar('SDK_ARCH') | ||
| 68 | else: | ||
| 69 | self.primary_arch = self.d.getVar('MACHINE_ARCH') | ||
| 70 | |||
| 71 | if needfeed: | ||
| 72 | self.rpm_repo_dir = oe.path.join(self.d.getVar('WORKDIR'), rpm_repo_workdir) | ||
| 73 | create_packages_dir(self.d, oe.path.join(self.rpm_repo_dir, "rpm"), d.getVar("DEPLOY_DIR_RPM"), "package_write_rpm", filterbydependencies) | ||
| 74 | |||
| 75 | self.saved_packaging_data = self.d.expand('${T}/saved_packaging_data/%s' % self.task_name) | ||
| 76 | if not os.path.exists(self.d.expand('${T}/saved_packaging_data')): | ||
| 77 | bb.utils.mkdirhier(self.d.expand('${T}/saved_packaging_data')) | ||
| 78 | self.packaging_data_dirs = ['etc/rpm', 'etc/rpmrc', 'etc/dnf', 'var/lib/rpm', 'var/lib/dnf', 'var/cache/dnf'] | ||
| 79 | self.solution_manifest = self.d.expand('${T}/saved/%s_solution' % | ||
| 80 | self.task_name) | ||
| 81 | if not os.path.exists(self.d.expand('${T}/saved')): | ||
| 82 | bb.utils.mkdirhier(self.d.expand('${T}/saved')) | ||
| 83 | |||
| 84 | def _configure_dnf(self): | ||
| 85 | # libsolv handles 'noarch' internally, we don't need to specify it explicitly | ||
| 86 | archs = [i for i in reversed(self.archs.split()) if i not in ["any", "all", "noarch"]] | ||
| 87 | # This prevents accidental matching against libsolv's built-in policies | ||
| 88 | if len(archs) <= 1: | ||
| 89 | archs = archs + ["bogusarch"] | ||
| 90 | # This architecture needs to be upfront so that packages using it are properly prioritized | ||
| 91 | archs = ["sdk_provides_dummy_target"] + archs | ||
| 92 | confdir = "%s/%s" %(self.target_rootfs, "etc/dnf/vars/") | ||
| 93 | bb.utils.mkdirhier(confdir) | ||
| 94 | open(confdir + "arch", 'w').write(":".join(archs)) | ||
| 95 | distro_codename = self.d.getVar('DISTRO_CODENAME') | ||
| 96 | open(confdir + "releasever", 'w').write(distro_codename if distro_codename is not None else '') | ||
| 97 | |||
| 98 | open(oe.path.join(self.target_rootfs, "etc/dnf/dnf.conf"), 'w').write("") | ||
| 99 | |||
| 100 | |||
| 101 | def _configure_rpm(self): | ||
| 102 | # We need to configure rpm to use our primary package architecture as the installation architecture, | ||
| 103 | # and to make it compatible with other package architectures that we use. | ||
| 104 | # Otherwise it will refuse to proceed with packages installation. | ||
| 105 | platformconfdir = "%s/%s" %(self.target_rootfs, "etc/rpm/") | ||
| 106 | rpmrcconfdir = "%s/%s" %(self.target_rootfs, "etc/") | ||
| 107 | bb.utils.mkdirhier(platformconfdir) | ||
| 108 | open(platformconfdir + "platform", 'w').write("%s-pc-linux" % self.primary_arch) | ||
| 109 | with open(rpmrcconfdir + "rpmrc", 'w') as f: | ||
| 110 | f.write("arch_compat: %s: %s\n" % (self.primary_arch, self.archs if len(self.archs) > 0 else self.primary_arch)) | ||
| 111 | f.write("buildarch_compat: %s: noarch\n" % self.primary_arch) | ||
| 112 | |||
| 113 | open(platformconfdir + "macros", 'w').write("%_transaction_color 7\n") | ||
| 114 | if self.d.getVar('RPM_PREFER_ELF_ARCH'): | ||
| 115 | open(platformconfdir + "macros", 'a').write("%%_prefer_color %s" % (self.d.getVar('RPM_PREFER_ELF_ARCH'))) | ||
| 116 | |||
| 117 | if self.d.getVar('RPM_SIGN_PACKAGES') == '1': | ||
| 118 | signer = get_signer(self.d, self.d.getVar('RPM_GPG_BACKEND')) | ||
| 119 | pubkey_path = oe.path.join(self.d.getVar('B'), 'rpm-key') | ||
| 120 | signer.export_pubkey(pubkey_path, self.d.getVar('RPM_GPG_NAME')) | ||
| 121 | rpm_bin = bb.utils.which(os.getenv('PATH'), "rpmkeys") | ||
| 122 | cmd = [rpm_bin, '--root=%s' % self.target_rootfs, '--import', pubkey_path] | ||
| 123 | try: | ||
| 124 | subprocess.check_output(cmd, stderr=subprocess.STDOUT) | ||
| 125 | except subprocess.CalledProcessError as e: | ||
| 126 | bb.fatal("Importing GPG key failed. Command '%s' " | ||
| 127 | "returned %d:\n%s" % (' '.join(cmd), e.returncode, e.output.decode("utf-8"))) | ||
| 128 | |||
| 129 | def create_configs(self): | ||
| 130 | self._configure_dnf() | ||
| 131 | self._configure_rpm() | ||
| 132 | |||
| 133 | def write_index(self): | ||
| 134 | lockfilename = self.d.getVar('DEPLOY_DIR_RPM') + "/rpm.lock" | ||
| 135 | lf = bb.utils.lockfile(lockfilename, False) | ||
| 136 | RpmIndexer(self.d, self.rpm_repo_dir).write_index() | ||
| 137 | bb.utils.unlockfile(lf) | ||
| 138 | |||
| 139 | def insert_feeds_uris(self, feed_uris, feed_base_paths, feed_archs): | ||
| 140 | from urllib.parse import urlparse | ||
| 141 | |||
| 142 | if feed_uris == "": | ||
| 143 | return | ||
| 144 | |||
| 145 | gpg_opts = '' | ||
| 146 | if self.d.getVar('PACKAGE_FEED_SIGN') == '1': | ||
| 147 | gpg_opts += 'repo_gpgcheck=1\n' | ||
| 148 | gpg_opts += 'gpgkey=file://%s/pki/packagefeed-gpg/PACKAGEFEED-GPG-KEY-%s-%s\n' % (self.d.getVar('sysconfdir'), self.d.getVar('DISTRO'), self.d.getVar('DISTRO_CODENAME')) | ||
| 149 | |||
| 150 | if self.d.getVar('RPM_SIGN_PACKAGES') != '1': | ||
| 151 | gpg_opts += 'gpgcheck=0\n' | ||
| 152 | |||
| 153 | bb.utils.mkdirhier(oe.path.join(self.target_rootfs, "etc", "yum.repos.d")) | ||
| 154 | remote_uris = self.construct_uris(feed_uris.split(), feed_base_paths.split()) | ||
| 155 | for uri in remote_uris: | ||
| 156 | repo_base = "oe-remote-repo" + "-".join(urlparse(uri).path.split("/")) | ||
| 157 | if feed_archs is not None: | ||
| 158 | for arch in feed_archs.split(): | ||
| 159 | repo_uri = uri + "/" + arch | ||
| 160 | repo_id = "oe-remote-repo" + "-".join(urlparse(repo_uri).path.split("/")) | ||
| 161 | repo_name = "OE Remote Repo:" + " ".join(urlparse(repo_uri).path.split("/")) | ||
| 162 | open(oe.path.join(self.target_rootfs, "etc", "yum.repos.d", repo_base + ".repo"), 'a').write( | ||
| 163 | "[%s]\nname=%s\nbaseurl=%s\n%s\n" % (repo_id, repo_name, repo_uri, gpg_opts)) | ||
| 164 | else: | ||
| 165 | repo_name = "OE Remote Repo:" + " ".join(urlparse(uri).path.split("/")) | ||
| 166 | repo_uri = uri | ||
| 167 | open(oe.path.join(self.target_rootfs, "etc", "yum.repos.d", repo_base + ".repo"), 'w').write( | ||
| 168 | "[%s]\nname=%s\nbaseurl=%s\n%s" % (repo_base, repo_name, repo_uri, gpg_opts)) | ||
| 169 | |||
| 170 | def _prepare_pkg_transaction(self): | ||
| 171 | os.environ['D'] = self.target_rootfs | ||
| 172 | os.environ['OFFLINE_ROOT'] = self.target_rootfs | ||
| 173 | os.environ['IPKG_OFFLINE_ROOT'] = self.target_rootfs | ||
| 174 | os.environ['OPKG_OFFLINE_ROOT'] = self.target_rootfs | ||
| 175 | os.environ['INTERCEPT_DIR'] = self.intercepts_dir | ||
| 176 | os.environ['NATIVE_ROOT'] = self.d.getVar('STAGING_DIR_NATIVE') | ||
| 177 | |||
| 178 | |||
| 179 | def install(self, pkgs, attempt_only = False): | ||
| 180 | if len(pkgs) == 0: | ||
| 181 | return | ||
| 182 | self._prepare_pkg_transaction() | ||
| 183 | |||
| 184 | bad_recommendations = self.d.getVar('BAD_RECOMMENDATIONS') | ||
| 185 | package_exclude = self.d.getVar('PACKAGE_EXCLUDE') | ||
| 186 | exclude_pkgs = (bad_recommendations.split() if bad_recommendations else []) + (package_exclude.split() if package_exclude else []) | ||
| 187 | |||
| 188 | output = self._invoke_dnf((["--skip-broken"] if attempt_only else []) + | ||
| 189 | (["-x", ",".join(exclude_pkgs)] if len(exclude_pkgs) > 0 else []) + | ||
| 190 | (["--setopt=install_weak_deps=False"] if self.d.getVar('NO_RECOMMENDATIONS') == "1" else []) + | ||
| 191 | (["--nogpgcheck"] if self.d.getVar('RPM_SIGN_PACKAGES') != '1' else ["--setopt=gpgcheck=True"]) + | ||
| 192 | ["install"] + | ||
| 193 | pkgs) | ||
| 194 | |||
| 195 | failed_scriptlets_pkgnames = collections.OrderedDict() | ||
| 196 | for line in output.splitlines(): | ||
| 197 | if line.startswith("Error in POSTIN scriptlet in rpm package"): | ||
| 198 | failed_scriptlets_pkgnames[line.split()[-1]] = True | ||
| 199 | |||
| 200 | if len(failed_scriptlets_pkgnames) > 0: | ||
| 201 | failed_postinsts_abort(list(failed_scriptlets_pkgnames.keys()), self.d.expand("${T}/log.do_${BB_CURRENTTASK}")) | ||
| 202 | |||
| 203 | def remove(self, pkgs, with_dependencies = True): | ||
| 204 | if not pkgs: | ||
| 205 | return | ||
| 206 | |||
| 207 | self._prepare_pkg_transaction() | ||
| 208 | |||
| 209 | if with_dependencies: | ||
| 210 | self._invoke_dnf(["remove"] + pkgs) | ||
| 211 | else: | ||
| 212 | cmd = bb.utils.which(os.getenv('PATH'), "rpm") | ||
| 213 | args = ["-e", "-v", "--nodeps", "--root=%s" %self.target_rootfs] | ||
| 214 | |||
| 215 | try: | ||
| 216 | bb.note("Running %s" % ' '.join([cmd] + args + pkgs)) | ||
| 217 | output = subprocess.check_output([cmd] + args + pkgs, stderr=subprocess.STDOUT).decode("utf-8") | ||
| 218 | bb.note(output) | ||
| 219 | except subprocess.CalledProcessError as e: | ||
| 220 | bb.fatal("Could not invoke rpm. Command " | ||
| 221 | "'%s' returned %d:\n%s" % (' '.join([cmd] + args + pkgs), e.returncode, e.output.decode("utf-8"))) | ||
| 222 | |||
| 223 | def upgrade(self): | ||
| 224 | self._prepare_pkg_transaction() | ||
| 225 | self._invoke_dnf(["upgrade"]) | ||
| 226 | |||
| 227 | def autoremove(self): | ||
| 228 | self._prepare_pkg_transaction() | ||
| 229 | self._invoke_dnf(["autoremove"]) | ||
| 230 | |||
| 231 | def remove_packaging_data(self): | ||
| 232 | self._invoke_dnf(["clean", "all"]) | ||
| 233 | for dir in self.packaging_data_dirs: | ||
| 234 | bb.utils.remove(oe.path.join(self.target_rootfs, dir), True) | ||
| 235 | |||
| 236 | def backup_packaging_data(self): | ||
| 237 | # Save the packaging dirs for increment rpm image generation | ||
| 238 | if os.path.exists(self.saved_packaging_data): | ||
| 239 | bb.utils.remove(self.saved_packaging_data, True) | ||
| 240 | for i in self.packaging_data_dirs: | ||
| 241 | source_dir = oe.path.join(self.target_rootfs, i) | ||
| 242 | target_dir = oe.path.join(self.saved_packaging_data, i) | ||
| 243 | if os.path.isdir(source_dir): | ||
| 244 | shutil.copytree(source_dir, target_dir, symlinks=True) | ||
| 245 | elif os.path.isfile(source_dir): | ||
| 246 | shutil.copy2(source_dir, target_dir) | ||
| 247 | |||
| 248 | def recovery_packaging_data(self): | ||
| 249 | # Move the rpmlib back | ||
| 250 | if os.path.exists(self.saved_packaging_data): | ||
| 251 | for i in self.packaging_data_dirs: | ||
| 252 | target_dir = oe.path.join(self.target_rootfs, i) | ||
| 253 | if os.path.exists(target_dir): | ||
| 254 | bb.utils.remove(target_dir, True) | ||
| 255 | source_dir = oe.path.join(self.saved_packaging_data, i) | ||
| 256 | if os.path.isdir(source_dir): | ||
| 257 | shutil.copytree(source_dir, target_dir, symlinks=True) | ||
| 258 | elif os.path.isfile(source_dir): | ||
| 259 | shutil.copy2(source_dir, target_dir) | ||
| 260 | |||
| 261 | def list_installed(self): | ||
| 262 | output = self._invoke_dnf(["repoquery", "--installed", "--queryformat", "Package: %{name} %{arch} %{version} %{name}-%{version}-%{release}.%{arch}.rpm\nDependencies:\n%{requires}\nRecommendations:\n%{recommends}\nDependenciesEndHere:\n"], | ||
| 263 | print_output = False) | ||
| 264 | packages = {} | ||
| 265 | current_package = None | ||
| 266 | current_deps = None | ||
| 267 | current_state = "initial" | ||
| 268 | for line in output.splitlines(): | ||
| 269 | if line.startswith("Package:"): | ||
| 270 | package_info = line.split(" ")[1:] | ||
| 271 | current_package = package_info[0] | ||
| 272 | package_arch = package_info[1] | ||
| 273 | package_version = package_info[2] | ||
| 274 | package_rpm = package_info[3] | ||
| 275 | packages[current_package] = {"arch":package_arch, "ver":package_version, "filename":package_rpm} | ||
| 276 | current_deps = [] | ||
| 277 | elif line.startswith("Dependencies:"): | ||
| 278 | current_state = "dependencies" | ||
| 279 | elif line.startswith("Recommendations"): | ||
| 280 | current_state = "recommendations" | ||
| 281 | elif line.startswith("DependenciesEndHere:"): | ||
| 282 | current_state = "initial" | ||
| 283 | packages[current_package]["deps"] = current_deps | ||
| 284 | elif len(line) > 0: | ||
| 285 | if current_state == "dependencies": | ||
| 286 | current_deps.append(line) | ||
| 287 | elif current_state == "recommendations": | ||
| 288 | current_deps.append("%s [REC]" % line) | ||
| 289 | |||
| 290 | return packages | ||
| 291 | |||
| 292 | def update(self): | ||
| 293 | self._invoke_dnf(["makecache", "--refresh"]) | ||
| 294 | |||
| 295 | def _invoke_dnf(self, dnf_args, fatal = True, print_output = True ): | ||
| 296 | os.environ['RPM_ETCCONFIGDIR'] = self.target_rootfs | ||
| 297 | |||
| 298 | dnf_cmd = bb.utils.which(os.getenv('PATH'), "dnf") | ||
| 299 | standard_dnf_args = ["-v", "--rpmverbosity=info", "-y", | ||
| 300 | "-c", oe.path.join(self.target_rootfs, "etc/dnf/dnf.conf"), | ||
| 301 | "--setopt=reposdir=%s" %(oe.path.join(self.target_rootfs, "etc/yum.repos.d")), | ||
| 302 | "--installroot=%s" % (self.target_rootfs), | ||
| 303 | "--setopt=logdir=%s" % (self.d.getVar('T')) | ||
| 304 | ] | ||
| 305 | if hasattr(self, "rpm_repo_dir"): | ||
| 306 | standard_dnf_args.append("--repofrompath=oe-repo,%s" % (self.rpm_repo_dir)) | ||
| 307 | cmd = [dnf_cmd] + standard_dnf_args + dnf_args | ||
| 308 | bb.note('Running %s' % ' '.join(cmd)) | ||
| 309 | try: | ||
| 310 | output = subprocess.check_output(cmd,stderr=subprocess.STDOUT).decode("utf-8") | ||
| 311 | if print_output: | ||
| 312 | bb.debug(1, output) | ||
| 313 | return output | ||
| 314 | except subprocess.CalledProcessError as e: | ||
| 315 | if print_output: | ||
| 316 | (bb.note, bb.fatal)[fatal]("Could not invoke dnf. Command " | ||
| 317 | "'%s' returned %d:\n%s" % (' '.join(cmd), e.returncode, e.output.decode("utf-8"))) | ||
| 318 | else: | ||
| 319 | (bb.note, bb.fatal)[fatal]("Could not invoke dnf. Command " | ||
| 320 | "'%s' returned %d:" % (' '.join(cmd), e.returncode)) | ||
| 321 | return e.output.decode("utf-8") | ||
| 322 | |||
| 323 | def dump_install_solution(self, pkgs): | ||
| 324 | open(self.solution_manifest, 'w').write(" ".join(pkgs)) | ||
| 325 | return pkgs | ||
| 326 | |||
| 327 | def load_old_install_solution(self): | ||
| 328 | if not os.path.exists(self.solution_manifest): | ||
| 329 | return [] | ||
| 330 | with open(self.solution_manifest, 'r') as fd: | ||
| 331 | return fd.read().split() | ||
| 332 | |||
| 333 | def _script_num_prefix(self, path): | ||
| 334 | files = os.listdir(path) | ||
| 335 | numbers = set() | ||
| 336 | numbers.add(99) | ||
| 337 | for f in files: | ||
| 338 | numbers.add(int(f.split("-")[0])) | ||
| 339 | return max(numbers) + 1 | ||
| 340 | |||
| 341 | def save_rpmpostinst(self, pkg): | ||
| 342 | bb.note("Saving postinstall script of %s" % (pkg)) | ||
| 343 | cmd = bb.utils.which(os.getenv('PATH'), "rpm") | ||
| 344 | args = ["-q", "--root=%s" % self.target_rootfs, "--queryformat", "%{postin}", pkg] | ||
| 345 | |||
| 346 | try: | ||
| 347 | output = subprocess.check_output([cmd] + args,stderr=subprocess.STDOUT).decode("utf-8") | ||
| 348 | except subprocess.CalledProcessError as e: | ||
| 349 | bb.fatal("Could not invoke rpm. Command " | ||
| 350 | "'%s' returned %d:\n%s" % (' '.join([cmd] + args), e.returncode, e.output.decode("utf-8"))) | ||
| 351 | |||
| 352 | # may need to prepend #!/bin/sh to output | ||
| 353 | |||
| 354 | target_path = oe.path.join(self.target_rootfs, self.d.expand('${sysconfdir}/rpm-postinsts/')) | ||
| 355 | bb.utils.mkdirhier(target_path) | ||
| 356 | num = self._script_num_prefix(target_path) | ||
| 357 | saved_script_name = oe.path.join(target_path, "%d-%s" % (num, pkg)) | ||
| 358 | open(saved_script_name, 'w').write(output) | ||
| 359 | os.chmod(saved_script_name, 0o755) | ||
| 360 | |||
| 361 | def _handle_intercept_failure(self, registered_pkgs): | ||
| 362 | rpm_postinsts_dir = self.target_rootfs + self.d.expand('${sysconfdir}/rpm-postinsts/') | ||
| 363 | bb.utils.mkdirhier(rpm_postinsts_dir) | ||
| 364 | |||
| 365 | # Save the package postinstalls in /etc/rpm-postinsts | ||
| 366 | for pkg in registered_pkgs.split(): | ||
| 367 | self.save_rpmpostinst(pkg) | ||
| 368 | |||
| 369 | def extract(self, pkg): | ||
| 370 | output = self._invoke_dnf(["repoquery", "--queryformat", "%{location}", pkg]) | ||
| 371 | pkg_name = output.splitlines()[-1] | ||
| 372 | if not pkg_name.endswith(".rpm"): | ||
| 373 | bb.fatal("dnf could not find package %s in repository: %s" %(pkg, output)) | ||
| 374 | pkg_path = oe.path.join(self.rpm_repo_dir, pkg_name) | ||
| 375 | |||
| 376 | cpio_cmd = bb.utils.which(os.getenv("PATH"), "cpio") | ||
| 377 | rpm2cpio_cmd = bb.utils.which(os.getenv("PATH"), "rpm2cpio") | ||
| 378 | |||
| 379 | if not os.path.isfile(pkg_path): | ||
| 380 | bb.fatal("Unable to extract package for '%s'." | ||
| 381 | "File %s doesn't exists" % (pkg, pkg_path)) | ||
| 382 | |||
| 383 | tmp_dir = tempfile.mkdtemp() | ||
| 384 | current_dir = os.getcwd() | ||
| 385 | os.chdir(tmp_dir) | ||
| 386 | |||
| 387 | try: | ||
| 388 | cmd = "%s %s | %s -idmv" % (rpm2cpio_cmd, pkg_path, cpio_cmd) | ||
| 389 | output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) | ||
| 390 | except subprocess.CalledProcessError as e: | ||
| 391 | bb.utils.remove(tmp_dir, recurse=True) | ||
| 392 | bb.fatal("Unable to extract %s package. Command '%s' " | ||
| 393 | "returned %d:\n%s" % (pkg_path, cmd, e.returncode, e.output.decode("utf-8"))) | ||
| 394 | except OSError as e: | ||
| 395 | bb.utils.remove(tmp_dir, recurse=True) | ||
| 396 | bb.fatal("Unable to extract %s package. Command '%s' " | ||
| 397 | "returned %d:\n%s at %s" % (pkg_path, cmd, e.errno, e.strerror, e.filename)) | ||
| 398 | |||
| 399 | bb.note("Extracted %s to %s" % (pkg_path, tmp_dir)) | ||
| 400 | os.chdir(current_dir) | ||
| 401 | |||
| 402 | return tmp_dir | ||
diff --git a/meta/lib/oe/package_manager/rpm/rootfs.py b/meta/lib/oe/package_manager/rpm/rootfs.py index 3d9eb95528..2de5752b91 100644 --- a/meta/lib/oe/package_manager/rpm/rootfs.py +++ b/meta/lib/oe/package_manager/rpm/rootfs.py | |||
| @@ -3,10 +3,10 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | from oe.rootfs import Rootfs | 5 | from oe.rootfs import Rootfs |
| 6 | from oe.package_manager import RpmPM | ||
| 7 | from oe.manifest import Manifest | 6 | from oe.manifest import Manifest |
| 8 | from oe.utils import execute_pre_post_process | 7 | from oe.utils import execute_pre_post_process |
| 9 | from oe.package_manager.rpm.manifest import RpmManifest | 8 | from oe.package_manager.rpm.manifest import RpmManifest |
| 9 | from oe.package_manager.rpm import RpmPM | ||
| 10 | 10 | ||
| 11 | class RpmRootfs(Rootfs): | 11 | class RpmRootfs(Rootfs): |
| 12 | def __init__(self, d, manifest_dir, progress_reporter=None, logcatcher=None): | 12 | def __init__(self, d, manifest_dir, progress_reporter=None, logcatcher=None): |
diff --git a/meta/lib/oe/package_manager/rpm/sdk.py b/meta/lib/oe/package_manager/rpm/sdk.py index ab816f43df..4d3f9461ef 100644 --- a/meta/lib/oe/package_manager/rpm/sdk.py +++ b/meta/lib/oe/package_manager/rpm/sdk.py | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | from oe.utils import execute_pre_post_process | 5 | from oe.utils import execute_pre_post_process |
| 6 | from oe.sdk import Sdk | 6 | from oe.sdk import Sdk |
| 7 | from oe.manifest import Manifest | 7 | from oe.manifest import Manifest |
| 8 | from oe.package_manager import RpmPM | 8 | from oe.package_manager.rpm import RpmPM |
| 9 | import glob | 9 | import glob |
| 10 | 10 | ||
| 11 | class RpmSdk(Sdk): | 11 | class RpmSdk(Sdk): |
diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py index 17ca323588..a37f1e8147 100644 --- a/meta/lib/oe/rootfs.py +++ b/meta/lib/oe/rootfs.py | |||
| @@ -13,6 +13,7 @@ import re | |||
| 13 | from oe.package_manager.rpm.manifest import RpmManifest | 13 | from oe.package_manager.rpm.manifest import RpmManifest |
| 14 | from oe.package_manager.ipk.manifest import OpkgManifest | 14 | from oe.package_manager.ipk.manifest import OpkgManifest |
| 15 | from oe.package_manager.deb.manifest import DpkgManifest | 15 | from oe.package_manager.deb.manifest import DpkgManifest |
| 16 | from oe.package_manager.rpm import RpmPkgsList | ||
| 16 | 17 | ||
| 17 | class Rootfs(object, metaclass=ABCMeta): | 18 | class Rootfs(object, metaclass=ABCMeta): |
| 18 | """ | 19 | """ |
diff --git a/meta/lib/oe/sdk.py b/meta/lib/oe/sdk.py index 2f8cbd03d7..3a4c9bb7ca 100644 --- a/meta/lib/oe/sdk.py +++ b/meta/lib/oe/sdk.py | |||
| @@ -117,6 +117,7 @@ def sdk_list_installed_packages(d, target, rootfs_dir=None): | |||
| 117 | 117 | ||
| 118 | rootfs_dir = [sdk_output, os.path.join(sdk_output, target_path)][target is True] | 118 | rootfs_dir = [sdk_output, os.path.join(sdk_output, target_path)][target is True] |
| 119 | 119 | ||
| 120 | from oe.package_manager.rpm import RpmPkgsList | ||
| 120 | img_type = d.getVar('IMAGE_PKGTYPE') | 121 | img_type = d.getVar('IMAGE_PKGTYPE') |
| 121 | if img_type == "rpm": | 122 | if img_type == "rpm": |
| 122 | arch_var = ["SDK_PACKAGE_ARCHS", None][target is True] | 123 | arch_var = ["SDK_PACKAGE_ARCHS", None][target is True] |
diff --git a/meta/lib/oeqa/utils/package_manager.py b/meta/lib/oeqa/utils/package_manager.py index 2d358f7172..15ffd59231 100644 --- a/meta/lib/oeqa/utils/package_manager.py +++ b/meta/lib/oeqa/utils/package_manager.py | |||
| @@ -12,7 +12,9 @@ def get_package_manager(d, root_path): | |||
| 12 | """ | 12 | """ |
| 13 | Returns an OE package manager that can install packages in root_path. | 13 | Returns an OE package manager that can install packages in root_path. |
| 14 | """ | 14 | """ |
| 15 | from oe.package_manager import RpmPM, OpkgPM, DpkgPM | 15 | from oe.package_manager import OpkgPM, DpkgPM |
| 16 | from oe.package_manager.rpm import RpmPM | ||
| 17 | |||
| 16 | 18 | ||
| 17 | pkg_class = d.getVar("IMAGE_PKGTYPE") | 19 | pkg_class = d.getVar("IMAGE_PKGTYPE") |
| 18 | if pkg_class == "rpm": | 20 | if pkg_class == "rpm": |
