Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 1 | # |
Patrick Williams | 92b42cb | 2022-09-03 06:53:57 -0500 | [diff] [blame] | 2 | # Copyright OpenEmbedded Contributors |
| 3 | # |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 4 | # SPDX-License-Identifier: GPL-2.0-only |
| 5 | # |
| 6 | |
| 7 | import shutil |
| 8 | import subprocess |
| 9 | from oe.package_manager import * |
| 10 | |
| 11 | class RpmIndexer(Indexer): |
| 12 | def write_index(self): |
| 13 | self.do_write_index(self.deploy_dir) |
| 14 | |
| 15 | def do_write_index(self, deploy_dir): |
| 16 | if self.d.getVar('PACKAGE_FEED_SIGN') == '1': |
| 17 | signer = get_signer(self.d, self.d.getVar('PACKAGE_FEED_GPG_BACKEND')) |
| 18 | else: |
| 19 | signer = None |
| 20 | |
| 21 | createrepo_c = bb.utils.which(os.environ['PATH'], "createrepo_c") |
| 22 | result = create_index("%s --update -q %s" % (createrepo_c, deploy_dir)) |
| 23 | if result: |
| 24 | bb.fatal(result) |
| 25 | |
| 26 | # Sign repomd |
| 27 | if signer: |
| 28 | sig_type = self.d.getVar('PACKAGE_FEED_GPG_SIGNATURE_TYPE') |
| 29 | is_ascii_sig = (sig_type.upper() != "BIN") |
| 30 | signer.detach_sign(os.path.join(deploy_dir, 'repodata', 'repomd.xml'), |
| 31 | self.d.getVar('PACKAGE_FEED_GPG_NAME'), |
| 32 | self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE'), |
| 33 | armor=is_ascii_sig) |
| 34 | |
| 35 | class RpmSubdirIndexer(RpmIndexer): |
| 36 | def write_index(self): |
| 37 | bb.note("Generating package index for %s" %(self.deploy_dir)) |
Andrew Geissler | d1e8949 | 2021-02-12 15:35:20 -0600 | [diff] [blame] | 38 | # Remove the existing repodata to ensure that we re-generate it no matter what |
| 39 | bb.utils.remove(os.path.join(self.deploy_dir, "repodata"), recurse=True) |
| 40 | |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 41 | self.do_write_index(self.deploy_dir) |
| 42 | for entry in os.walk(self.deploy_dir): |
| 43 | if os.path.samefile(self.deploy_dir, entry[0]): |
| 44 | for dir in entry[1]: |
| 45 | if dir != 'repodata': |
| 46 | dir_path = oe.path.join(self.deploy_dir, dir) |
| 47 | bb.note("Generating package index for %s" %(dir_path)) |
| 48 | self.do_write_index(dir_path) |
| 49 | |
| 50 | |
Andrew Geissler | 6ce62a2 | 2020-11-30 19:58:47 -0600 | [diff] [blame] | 51 | class PMPkgsList(PkgsList): |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 52 | def list_pkgs(self): |
| 53 | return RpmPM(self.d, self.rootfs_dir, self.d.getVar('TARGET_VENDOR'), needfeed=False).list_installed() |
| 54 | |
| 55 | class RpmPM(PackageManager): |
| 56 | def __init__(self, |
| 57 | d, |
| 58 | target_rootfs, |
| 59 | target_vendor, |
| 60 | task_name='target', |
| 61 | arch_var=None, |
| 62 | os_var=None, |
| 63 | rpm_repo_workdir="oe-rootfs-repo", |
| 64 | filterbydependencies=True, |
| 65 | needfeed=True): |
| 66 | super(RpmPM, self).__init__(d, target_rootfs) |
| 67 | self.target_vendor = target_vendor |
| 68 | self.task_name = task_name |
| 69 | if arch_var == None: |
| 70 | self.archs = self.d.getVar('ALL_MULTILIB_PACKAGE_ARCHS').replace("-","_") |
| 71 | else: |
| 72 | self.archs = self.d.getVar(arch_var).replace("-","_") |
| 73 | if task_name == "host": |
| 74 | self.primary_arch = self.d.getVar('SDK_ARCH') |
| 75 | else: |
| 76 | self.primary_arch = self.d.getVar('MACHINE_ARCH') |
| 77 | |
| 78 | if needfeed: |
| 79 | self.rpm_repo_dir = oe.path.join(self.d.getVar('WORKDIR'), rpm_repo_workdir) |
| 80 | create_packages_dir(self.d, oe.path.join(self.rpm_repo_dir, "rpm"), d.getVar("DEPLOY_DIR_RPM"), "package_write_rpm", filterbydependencies) |
| 81 | |
| 82 | self.saved_packaging_data = self.d.expand('${T}/saved_packaging_data/%s' % self.task_name) |
| 83 | if not os.path.exists(self.d.expand('${T}/saved_packaging_data')): |
| 84 | bb.utils.mkdirhier(self.d.expand('${T}/saved_packaging_data')) |
| 85 | self.packaging_data_dirs = ['etc/rpm', 'etc/rpmrc', 'etc/dnf', 'var/lib/rpm', 'var/lib/dnf', 'var/cache/dnf'] |
| 86 | self.solution_manifest = self.d.expand('${T}/saved/%s_solution' % |
| 87 | self.task_name) |
| 88 | if not os.path.exists(self.d.expand('${T}/saved')): |
| 89 | bb.utils.mkdirhier(self.d.expand('${T}/saved')) |
| 90 | |
| 91 | def _configure_dnf(self): |
| 92 | # libsolv handles 'noarch' internally, we don't need to specify it explicitly |
| 93 | archs = [i for i in reversed(self.archs.split()) if i not in ["any", "all", "noarch"]] |
| 94 | # This prevents accidental matching against libsolv's built-in policies |
| 95 | if len(archs) <= 1: |
| 96 | archs = archs + ["bogusarch"] |
| 97 | # This architecture needs to be upfront so that packages using it are properly prioritized |
| 98 | archs = ["sdk_provides_dummy_target"] + archs |
| 99 | confdir = "%s/%s" %(self.target_rootfs, "etc/dnf/vars/") |
| 100 | bb.utils.mkdirhier(confdir) |
Patrick Williams | 2390b1b | 2022-11-03 13:47:49 -0500 | [diff] [blame^] | 101 | with open(confdir + "arch", 'w') as f: |
| 102 | f.write(":".join(archs)) |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 103 | |
Patrick Williams | 2390b1b | 2022-11-03 13:47:49 -0500 | [diff] [blame^] | 104 | distro_codename = self.d.getVar('DISTRO_CODENAME') |
| 105 | with open(confdir + "releasever", 'w') as f: |
| 106 | f.write(distro_codename if distro_codename is not None else '') |
| 107 | |
| 108 | with open(oe.path.join(self.target_rootfs, "etc/dnf/dnf.conf"), 'w') as f: |
| 109 | f.write("") |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 110 | |
| 111 | |
| 112 | def _configure_rpm(self): |
| 113 | # We need to configure rpm to use our primary package architecture as the installation architecture, |
| 114 | # and to make it compatible with other package architectures that we use. |
| 115 | # Otherwise it will refuse to proceed with packages installation. |
| 116 | platformconfdir = "%s/%s" %(self.target_rootfs, "etc/rpm/") |
| 117 | rpmrcconfdir = "%s/%s" %(self.target_rootfs, "etc/") |
| 118 | bb.utils.mkdirhier(platformconfdir) |
Patrick Williams | 2390b1b | 2022-11-03 13:47:49 -0500 | [diff] [blame^] | 119 | with open(platformconfdir + "platform", 'w') as f: |
| 120 | f.write("%s-pc-linux" % self.primary_arch) |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 121 | with open(rpmrcconfdir + "rpmrc", 'w') as f: |
| 122 | f.write("arch_compat: %s: %s\n" % (self.primary_arch, self.archs if len(self.archs) > 0 else self.primary_arch)) |
| 123 | f.write("buildarch_compat: %s: noarch\n" % self.primary_arch) |
| 124 | |
Patrick Williams | 2390b1b | 2022-11-03 13:47:49 -0500 | [diff] [blame^] | 125 | with open(platformconfdir + "macros", 'w') as f: |
| 126 | f.write("%_transaction_color 7\n") |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 127 | if self.d.getVar('RPM_PREFER_ELF_ARCH'): |
Patrick Williams | 2390b1b | 2022-11-03 13:47:49 -0500 | [diff] [blame^] | 128 | with open(platformconfdir + "macros", 'a') as f: |
| 129 | f.write("%%_prefer_color %s" % (self.d.getVar('RPM_PREFER_ELF_ARCH'))) |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 130 | |
| 131 | if self.d.getVar('RPM_SIGN_PACKAGES') == '1': |
| 132 | signer = get_signer(self.d, self.d.getVar('RPM_GPG_BACKEND')) |
| 133 | pubkey_path = oe.path.join(self.d.getVar('B'), 'rpm-key') |
| 134 | signer.export_pubkey(pubkey_path, self.d.getVar('RPM_GPG_NAME')) |
| 135 | rpm_bin = bb.utils.which(os.getenv('PATH'), "rpmkeys") |
| 136 | cmd = [rpm_bin, '--root=%s' % self.target_rootfs, '--import', pubkey_path] |
| 137 | try: |
| 138 | subprocess.check_output(cmd, stderr=subprocess.STDOUT) |
| 139 | except subprocess.CalledProcessError as e: |
| 140 | bb.fatal("Importing GPG key failed. Command '%s' " |
| 141 | "returned %d:\n%s" % (' '.join(cmd), e.returncode, e.output.decode("utf-8"))) |
| 142 | |
| 143 | def create_configs(self): |
| 144 | self._configure_dnf() |
| 145 | self._configure_rpm() |
| 146 | |
| 147 | def write_index(self): |
| 148 | lockfilename = self.d.getVar('DEPLOY_DIR_RPM') + "/rpm.lock" |
| 149 | lf = bb.utils.lockfile(lockfilename, False) |
| 150 | RpmIndexer(self.d, self.rpm_repo_dir).write_index() |
| 151 | bb.utils.unlockfile(lf) |
| 152 | |
| 153 | def insert_feeds_uris(self, feed_uris, feed_base_paths, feed_archs): |
| 154 | from urllib.parse import urlparse |
| 155 | |
| 156 | if feed_uris == "": |
| 157 | return |
| 158 | |
| 159 | gpg_opts = '' |
| 160 | if self.d.getVar('PACKAGE_FEED_SIGN') == '1': |
| 161 | gpg_opts += 'repo_gpgcheck=1\n' |
| 162 | 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')) |
| 163 | |
| 164 | if self.d.getVar('RPM_SIGN_PACKAGES') != '1': |
| 165 | gpg_opts += 'gpgcheck=0\n' |
| 166 | |
| 167 | bb.utils.mkdirhier(oe.path.join(self.target_rootfs, "etc", "yum.repos.d")) |
| 168 | remote_uris = self.construct_uris(feed_uris.split(), feed_base_paths.split()) |
| 169 | for uri in remote_uris: |
| 170 | repo_base = "oe-remote-repo" + "-".join(urlparse(uri).path.split("/")) |
| 171 | if feed_archs is not None: |
| 172 | for arch in feed_archs.split(): |
| 173 | repo_uri = uri + "/" + arch |
| 174 | repo_id = "oe-remote-repo" + "-".join(urlparse(repo_uri).path.split("/")) |
| 175 | repo_name = "OE Remote Repo:" + " ".join(urlparse(repo_uri).path.split("/")) |
Patrick Williams | 2390b1b | 2022-11-03 13:47:49 -0500 | [diff] [blame^] | 176 | with open(oe.path.join(self.target_rootfs, "etc", "yum.repos.d", repo_base + ".repo"), 'a') as f: |
| 177 | f.write("[%s]\nname=%s\nbaseurl=%s\n%s\n" % (repo_id, repo_name, repo_uri, gpg_opts)) |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 178 | else: |
| 179 | repo_name = "OE Remote Repo:" + " ".join(urlparse(uri).path.split("/")) |
| 180 | repo_uri = uri |
Patrick Williams | 2390b1b | 2022-11-03 13:47:49 -0500 | [diff] [blame^] | 181 | with open(oe.path.join(self.target_rootfs, "etc", "yum.repos.d", repo_base + ".repo"), 'w') as f: |
| 182 | f.write("[%s]\nname=%s\nbaseurl=%s\n%s" % (repo_base, repo_name, repo_uri, gpg_opts)) |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 183 | |
| 184 | def _prepare_pkg_transaction(self): |
| 185 | os.environ['D'] = self.target_rootfs |
| 186 | os.environ['OFFLINE_ROOT'] = self.target_rootfs |
| 187 | os.environ['IPKG_OFFLINE_ROOT'] = self.target_rootfs |
| 188 | os.environ['OPKG_OFFLINE_ROOT'] = self.target_rootfs |
| 189 | os.environ['INTERCEPT_DIR'] = self.intercepts_dir |
| 190 | os.environ['NATIVE_ROOT'] = self.d.getVar('STAGING_DIR_NATIVE') |
| 191 | |
| 192 | |
Andrew Geissler | 615f2f1 | 2022-07-15 14:00:58 -0500 | [diff] [blame] | 193 | def install(self, pkgs, attempt_only=False, hard_depends_only=False): |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 194 | if len(pkgs) == 0: |
| 195 | return |
| 196 | self._prepare_pkg_transaction() |
| 197 | |
| 198 | bad_recommendations = self.d.getVar('BAD_RECOMMENDATIONS') |
| 199 | package_exclude = self.d.getVar('PACKAGE_EXCLUDE') |
| 200 | exclude_pkgs = (bad_recommendations.split() if bad_recommendations else []) + (package_exclude.split() if package_exclude else []) |
| 201 | |
| 202 | output = self._invoke_dnf((["--skip-broken"] if attempt_only else []) + |
| 203 | (["-x", ",".join(exclude_pkgs)] if len(exclude_pkgs) > 0 else []) + |
Andrew Geissler | 615f2f1 | 2022-07-15 14:00:58 -0500 | [diff] [blame] | 204 | (["--setopt=install_weak_deps=False"] if (hard_depends_only or self.d.getVar('NO_RECOMMENDATIONS') == "1") else []) + |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 205 | (["--nogpgcheck"] if self.d.getVar('RPM_SIGN_PACKAGES') != '1' else ["--setopt=gpgcheck=True"]) + |
| 206 | ["install"] + |
| 207 | pkgs) |
| 208 | |
| 209 | failed_scriptlets_pkgnames = collections.OrderedDict() |
| 210 | for line in output.splitlines(): |
William A. Kennington III | ac69b48 | 2021-06-02 12:28:27 -0700 | [diff] [blame] | 211 | if line.startswith("Error: Systemctl"): |
| 212 | bb.error(line) |
| 213 | |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 214 | if line.startswith("Error in POSTIN scriptlet in rpm package"): |
| 215 | failed_scriptlets_pkgnames[line.split()[-1]] = True |
| 216 | |
| 217 | if len(failed_scriptlets_pkgnames) > 0: |
| 218 | failed_postinsts_abort(list(failed_scriptlets_pkgnames.keys()), self.d.expand("${T}/log.do_${BB_CURRENTTASK}")) |
| 219 | |
| 220 | def remove(self, pkgs, with_dependencies = True): |
| 221 | if not pkgs: |
| 222 | return |
| 223 | |
| 224 | self._prepare_pkg_transaction() |
| 225 | |
| 226 | if with_dependencies: |
| 227 | self._invoke_dnf(["remove"] + pkgs) |
| 228 | else: |
| 229 | cmd = bb.utils.which(os.getenv('PATH'), "rpm") |
| 230 | args = ["-e", "-v", "--nodeps", "--root=%s" %self.target_rootfs] |
| 231 | |
| 232 | try: |
| 233 | bb.note("Running %s" % ' '.join([cmd] + args + pkgs)) |
| 234 | output = subprocess.check_output([cmd] + args + pkgs, stderr=subprocess.STDOUT).decode("utf-8") |
| 235 | bb.note(output) |
| 236 | except subprocess.CalledProcessError as e: |
| 237 | bb.fatal("Could not invoke rpm. Command " |
| 238 | "'%s' returned %d:\n%s" % (' '.join([cmd] + args + pkgs), e.returncode, e.output.decode("utf-8"))) |
| 239 | |
| 240 | def upgrade(self): |
| 241 | self._prepare_pkg_transaction() |
| 242 | self._invoke_dnf(["upgrade"]) |
| 243 | |
| 244 | def autoremove(self): |
| 245 | self._prepare_pkg_transaction() |
| 246 | self._invoke_dnf(["autoremove"]) |
| 247 | |
| 248 | def remove_packaging_data(self): |
| 249 | self._invoke_dnf(["clean", "all"]) |
| 250 | for dir in self.packaging_data_dirs: |
| 251 | bb.utils.remove(oe.path.join(self.target_rootfs, dir), True) |
| 252 | |
| 253 | def backup_packaging_data(self): |
| 254 | # Save the packaging dirs for increment rpm image generation |
| 255 | if os.path.exists(self.saved_packaging_data): |
| 256 | bb.utils.remove(self.saved_packaging_data, True) |
| 257 | for i in self.packaging_data_dirs: |
| 258 | source_dir = oe.path.join(self.target_rootfs, i) |
| 259 | target_dir = oe.path.join(self.saved_packaging_data, i) |
| 260 | if os.path.isdir(source_dir): |
| 261 | shutil.copytree(source_dir, target_dir, symlinks=True) |
| 262 | elif os.path.isfile(source_dir): |
| 263 | shutil.copy2(source_dir, target_dir) |
| 264 | |
| 265 | def recovery_packaging_data(self): |
| 266 | # Move the rpmlib back |
| 267 | if os.path.exists(self.saved_packaging_data): |
| 268 | for i in self.packaging_data_dirs: |
| 269 | target_dir = oe.path.join(self.target_rootfs, i) |
| 270 | if os.path.exists(target_dir): |
| 271 | bb.utils.remove(target_dir, True) |
| 272 | source_dir = oe.path.join(self.saved_packaging_data, i) |
| 273 | if os.path.isdir(source_dir): |
| 274 | shutil.copytree(source_dir, target_dir, symlinks=True) |
| 275 | elif os.path.isfile(source_dir): |
| 276 | shutil.copy2(source_dir, target_dir) |
| 277 | |
| 278 | def list_installed(self): |
| 279 | output = self._invoke_dnf(["repoquery", "--installed", "--queryformat", "Package: %{name} %{arch} %{version} %{name}-%{version}-%{release}.%{arch}.rpm\nDependencies:\n%{requires}\nRecommendations:\n%{recommends}\nDependenciesEndHere:\n"], |
| 280 | print_output = False) |
| 281 | packages = {} |
| 282 | current_package = None |
| 283 | current_deps = None |
| 284 | current_state = "initial" |
| 285 | for line in output.splitlines(): |
| 286 | if line.startswith("Package:"): |
| 287 | package_info = line.split(" ")[1:] |
| 288 | current_package = package_info[0] |
| 289 | package_arch = package_info[1] |
| 290 | package_version = package_info[2] |
| 291 | package_rpm = package_info[3] |
| 292 | packages[current_package] = {"arch":package_arch, "ver":package_version, "filename":package_rpm} |
| 293 | current_deps = [] |
| 294 | elif line.startswith("Dependencies:"): |
| 295 | current_state = "dependencies" |
| 296 | elif line.startswith("Recommendations"): |
| 297 | current_state = "recommendations" |
| 298 | elif line.startswith("DependenciesEndHere:"): |
| 299 | current_state = "initial" |
| 300 | packages[current_package]["deps"] = current_deps |
| 301 | elif len(line) > 0: |
| 302 | if current_state == "dependencies": |
| 303 | current_deps.append(line) |
| 304 | elif current_state == "recommendations": |
| 305 | current_deps.append("%s [REC]" % line) |
| 306 | |
| 307 | return packages |
| 308 | |
| 309 | def update(self): |
| 310 | self._invoke_dnf(["makecache", "--refresh"]) |
| 311 | |
| 312 | def _invoke_dnf(self, dnf_args, fatal = True, print_output = True ): |
| 313 | os.environ['RPM_ETCCONFIGDIR'] = self.target_rootfs |
| 314 | |
| 315 | dnf_cmd = bb.utils.which(os.getenv('PATH'), "dnf") |
| 316 | standard_dnf_args = ["-v", "--rpmverbosity=info", "-y", |
| 317 | "-c", oe.path.join(self.target_rootfs, "etc/dnf/dnf.conf"), |
| 318 | "--setopt=reposdir=%s" %(oe.path.join(self.target_rootfs, "etc/yum.repos.d")), |
| 319 | "--installroot=%s" % (self.target_rootfs), |
| 320 | "--setopt=logdir=%s" % (self.d.getVar('T')) |
| 321 | ] |
| 322 | if hasattr(self, "rpm_repo_dir"): |
| 323 | standard_dnf_args.append("--repofrompath=oe-repo,%s" % (self.rpm_repo_dir)) |
| 324 | cmd = [dnf_cmd] + standard_dnf_args + dnf_args |
| 325 | bb.note('Running %s' % ' '.join(cmd)) |
| 326 | try: |
| 327 | output = subprocess.check_output(cmd,stderr=subprocess.STDOUT).decode("utf-8") |
| 328 | if print_output: |
| 329 | bb.debug(1, output) |
| 330 | return output |
| 331 | except subprocess.CalledProcessError as e: |
| 332 | if print_output: |
| 333 | (bb.note, bb.fatal)[fatal]("Could not invoke dnf. Command " |
| 334 | "'%s' returned %d:\n%s" % (' '.join(cmd), e.returncode, e.output.decode("utf-8"))) |
| 335 | else: |
| 336 | (bb.note, bb.fatal)[fatal]("Could not invoke dnf. Command " |
| 337 | "'%s' returned %d:" % (' '.join(cmd), e.returncode)) |
| 338 | return e.output.decode("utf-8") |
| 339 | |
| 340 | def dump_install_solution(self, pkgs): |
Patrick Williams | 2390b1b | 2022-11-03 13:47:49 -0500 | [diff] [blame^] | 341 | with open(self.solution_manifest, 'w') as f: |
| 342 | f.write(" ".join(pkgs)) |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 343 | return pkgs |
| 344 | |
| 345 | def load_old_install_solution(self): |
| 346 | if not os.path.exists(self.solution_manifest): |
| 347 | return [] |
| 348 | with open(self.solution_manifest, 'r') as fd: |
| 349 | return fd.read().split() |
| 350 | |
| 351 | def _script_num_prefix(self, path): |
| 352 | files = os.listdir(path) |
| 353 | numbers = set() |
| 354 | numbers.add(99) |
| 355 | for f in files: |
| 356 | numbers.add(int(f.split("-")[0])) |
| 357 | return max(numbers) + 1 |
| 358 | |
| 359 | def save_rpmpostinst(self, pkg): |
| 360 | bb.note("Saving postinstall script of %s" % (pkg)) |
| 361 | cmd = bb.utils.which(os.getenv('PATH'), "rpm") |
| 362 | args = ["-q", "--root=%s" % self.target_rootfs, "--queryformat", "%{postin}", pkg] |
| 363 | |
| 364 | try: |
| 365 | output = subprocess.check_output([cmd] + args,stderr=subprocess.STDOUT).decode("utf-8") |
| 366 | except subprocess.CalledProcessError as e: |
| 367 | bb.fatal("Could not invoke rpm. Command " |
| 368 | "'%s' returned %d:\n%s" % (' '.join([cmd] + args), e.returncode, e.output.decode("utf-8"))) |
| 369 | |
| 370 | # may need to prepend #!/bin/sh to output |
| 371 | |
| 372 | target_path = oe.path.join(self.target_rootfs, self.d.expand('${sysconfdir}/rpm-postinsts/')) |
| 373 | bb.utils.mkdirhier(target_path) |
| 374 | num = self._script_num_prefix(target_path) |
| 375 | saved_script_name = oe.path.join(target_path, "%d-%s" % (num, pkg)) |
Patrick Williams | 2390b1b | 2022-11-03 13:47:49 -0500 | [diff] [blame^] | 376 | with open(saved_script_name, 'w') as f: |
| 377 | f.write(output) |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 378 | os.chmod(saved_script_name, 0o755) |
| 379 | |
| 380 | def _handle_intercept_failure(self, registered_pkgs): |
| 381 | rpm_postinsts_dir = self.target_rootfs + self.d.expand('${sysconfdir}/rpm-postinsts/') |
| 382 | bb.utils.mkdirhier(rpm_postinsts_dir) |
| 383 | |
| 384 | # Save the package postinstalls in /etc/rpm-postinsts |
| 385 | for pkg in registered_pkgs.split(): |
| 386 | self.save_rpmpostinst(pkg) |
| 387 | |
| 388 | def extract(self, pkg): |
| 389 | output = self._invoke_dnf(["repoquery", "--queryformat", "%{location}", pkg]) |
| 390 | pkg_name = output.splitlines()[-1] |
| 391 | if not pkg_name.endswith(".rpm"): |
| 392 | bb.fatal("dnf could not find package %s in repository: %s" %(pkg, output)) |
| 393 | pkg_path = oe.path.join(self.rpm_repo_dir, pkg_name) |
| 394 | |
| 395 | cpio_cmd = bb.utils.which(os.getenv("PATH"), "cpio") |
| 396 | rpm2cpio_cmd = bb.utils.which(os.getenv("PATH"), "rpm2cpio") |
| 397 | |
| 398 | if not os.path.isfile(pkg_path): |
| 399 | bb.fatal("Unable to extract package for '%s'." |
| 400 | "File %s doesn't exists" % (pkg, pkg_path)) |
| 401 | |
| 402 | tmp_dir = tempfile.mkdtemp() |
| 403 | current_dir = os.getcwd() |
| 404 | os.chdir(tmp_dir) |
| 405 | |
| 406 | try: |
| 407 | cmd = "%s %s | %s -idmv" % (rpm2cpio_cmd, pkg_path, cpio_cmd) |
| 408 | output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) |
| 409 | except subprocess.CalledProcessError as e: |
| 410 | bb.utils.remove(tmp_dir, recurse=True) |
| 411 | bb.fatal("Unable to extract %s package. Command '%s' " |
| 412 | "returned %d:\n%s" % (pkg_path, cmd, e.returncode, e.output.decode("utf-8"))) |
| 413 | except OSError as e: |
| 414 | bb.utils.remove(tmp_dir, recurse=True) |
| 415 | bb.fatal("Unable to extract %s package. Command '%s' " |
| 416 | "returned %d:\n%s at %s" % (pkg_path, cmd, e.errno, e.strerror, e.filename)) |
| 417 | |
| 418 | bb.note("Extracted %s to %s" % (pkg_path, tmp_dir)) |
| 419 | os.chdir(current_dir) |
| 420 | |
| 421 | return tmp_dir |