diff options
| author | Hongxu Jia <hongxu.jia@windriver.com> | 2014-01-26 17:40:55 +0800 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2014-02-11 11:53:41 +0000 |
| commit | c8103fba58c59acbfc541aec6c9c03315613766a (patch) | |
| tree | bf71ea04d8fa4de0651ba742f45ed825126c5c32 /meta/lib/oe | |
| parent | dff8a593afc880a18c2a48d33161cefb45263c8e (diff) | |
| download | poky-c8103fba58c59acbfc541aec6c9c03315613766a.tar.gz | |
lib/oe/package_manager.py: support RpmPM
- Implementation RpmPM class
- Support rpm incremental image generation
(From OE-Core rev: ca5203d6b1bb0cbf7830ea4f46109c6867138efc)
Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
Signed-off-by: Laurentiu Palcu <laurentiu.palcu@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib/oe')
| -rw-r--r-- | meta/lib/oe/package_manager.py | 656 |
1 files changed, 651 insertions, 5 deletions
diff --git a/meta/lib/oe/package_manager.py b/meta/lib/oe/package_manager.py index e802edd492..15e56b550d 100644 --- a/meta/lib/oe/package_manager.py +++ b/meta/lib/oe/package_manager.py | |||
| @@ -1,8 +1,63 @@ | |||
| 1 | from abc import ABCMeta, abstractmethod | 1 | from abc import ABCMeta, abstractmethod |
| 2 | import os | 2 | import os |
| 3 | import glob | ||
| 3 | import subprocess | 4 | import subprocess |
| 5 | import shutil | ||
| 4 | import multiprocessing | 6 | import multiprocessing |
| 5 | import re | 7 | import re |
| 8 | import bb | ||
| 9 | |||
| 10 | DB_CONFIG_CONTENT = '''# ================ Environment | ||
| 11 | set_data_dir . | ||
| 12 | set_create_dir . | ||
| 13 | set_lg_dir ./log | ||
| 14 | set_tmp_dir ./tmp | ||
| 15 | set_flags db_log_autoremove on | ||
| 16 | |||
| 17 | # -- thread_count must be >= 8 | ||
| 18 | set_thread_count 64 | ||
| 19 | |||
| 20 | # ================ Logging | ||
| 21 | |||
| 22 | # ================ Memory Pool | ||
| 23 | set_cachesize 0 1048576 0 | ||
| 24 | set_mp_mmapsize 268435456 | ||
| 25 | |||
| 26 | # ================ Locking | ||
| 27 | set_lk_max_locks 16384 | ||
| 28 | set_lk_max_lockers 16384 | ||
| 29 | set_lk_max_objects 16384 | ||
| 30 | mutex_set_max 163840 | ||
| 31 | |||
| 32 | # ================ Replication | ||
| 33 | ''' | ||
| 34 | |||
| 35 | SCRIPTLET_FORMAT = '''#!/bin/bash | ||
| 36 | |||
| 37 | export PATH=%s | ||
| 38 | export D=%s | ||
| 39 | export OFFLINE_ROOT="$D" | ||
| 40 | export IPKG_OFFLINE_ROOT="$D" | ||
| 41 | export OPKG_OFFLINE_ROOT="$D" | ||
| 42 | export INTERCEPT_DIR=%s | ||
| 43 | export NATIVE_ROOT=%s | ||
| 44 | |||
| 45 | $2 $1/$3 $4 | ||
| 46 | if [ $? -ne 0 ]; then | ||
| 47 | if [ $4 -eq 1 ]; then | ||
| 48 | mkdir -p $1/etc/rpm-postinsts | ||
| 49 | num=100 | ||
| 50 | while [ -e $1/etc/rpm-postinsts/${num}-* ]; do num=$((num + 1)); done | ||
| 51 | name=`head -1 $1/$3 | cut -d\' \' -f 2` | ||
| 52 | echo "#!$2" > $1/etc/rpm-postinsts/${num}-${name} | ||
| 53 | echo "# Arg: $4" >> $1/etc/rpm-postinsts/${num}-${name} | ||
| 54 | cat $1/$3 >> $1/etc/rpm-postinsts/${num}-${name} | ||
| 55 | chmod +x $1/etc/rpm-postinsts/${num}-${name} | ||
| 56 | else | ||
| 57 | echo "Error: pre/post remove scriptlet failed" | ||
| 58 | fi | ||
| 59 | fi | ||
| 60 | ''' | ||
| 6 | 61 | ||
| 7 | 62 | ||
| 8 | # this can be used by all PM backends to create the index files in parallel | 63 | # this can be used by all PM backends to create the index files in parallel |
| @@ -127,13 +182,604 @@ class PackageManager(object): | |||
| 127 | 182 | ||
| 128 | self.deploy_lock = None | 183 | self.deploy_lock = None |
| 129 | 184 | ||
| 185 | |||
| 130 | class RpmPM(PackageManager): | 186 | class RpmPM(PackageManager): |
| 131 | def __init__(self): | 187 | def __init__(self, |
| 132 | super(RpmPM, self).__init__() | 188 | d, |
| 189 | target_rootfs, | ||
| 190 | package_archs, | ||
| 191 | target_os, | ||
| 192 | target_vendor, | ||
| 193 | task_name='target', | ||
| 194 | providename=None): | ||
| 195 | super(RpmPM, self).__init__(d) | ||
| 196 | self.target_rootfs = target_rootfs | ||
| 197 | self.ml_os_list = target_os | ||
| 198 | self.target_vendor = target_vendor | ||
| 199 | self.task_name = task_name | ||
| 200 | self.providename = providename | ||
| 201 | self.fullpkglist = list() | ||
| 202 | self.deploy_dir = self.d.getVar('DEPLOY_DIR_RPM', True) | ||
| 203 | self.etcrpm_dir = os.path.join(self.target_rootfs, "etc/rpm") | ||
| 204 | self.install_dir = os.path.join(self.target_rootfs, "install") | ||
| 205 | self.rpm_cmd = bb.utils.which(os.getenv('PATH'), "rpm") | ||
| 206 | self.smart_cmd = bb.utils.which(os.getenv('PATH'), "smart") | ||
| 207 | self.smart_opt = "--data-dir=" + os.path.join(target_rootfs, | ||
| 208 | 'var/lib/smart') | ||
| 209 | self.scriptlet_wrapper = self.d.expand('${WORKDIR}/scriptlet_wrapper') | ||
| 210 | self.solution_manifest = self.d.expand('${T}/saved/%s_solution' % | ||
| 211 | self.task_name) | ||
| 212 | self.saved_rpmlib = self.d.expand('${T}/saved/%s' % self.task_name) | ||
| 213 | self.image_rpmlib = os.path.join(self.target_rootfs, 'var/lib/rpm') | ||
| 214 | |||
| 215 | if not os.path.exists(self.d.expand('${T}/saved')): | ||
| 216 | bb.utils.mkdirhier(self.d.expand('${T}/saved')) | ||
| 217 | |||
| 218 | # arch order is reversed. This ensures the -best- match is | ||
| 219 | # listed first! | ||
| 220 | self.ml_prefix_list = dict() | ||
| 221 | for mlib in package_archs: | ||
| 222 | if mlib == 'default': | ||
| 223 | self.ml_prefix_list[mlib] = package_archs[mlib] | ||
| 224 | else: | ||
| 225 | self.ml_prefix_list[mlib] = list() | ||
| 226 | for arch in package_archs[mlib]: | ||
| 227 | if arch in ['all', 'noarch', 'any']: | ||
| 228 | self.ml_prefix_list[mlib].append(arch) | ||
| 229 | else: | ||
| 230 | self.ml_prefix_list[mlib].append(mlib + "_" + arch) | ||
| 231 | |||
| 232 | ''' | ||
| 233 | Create configs for rpm and smart, and multilib is supported | ||
| 234 | ''' | ||
| 235 | def create_configs(self): | ||
| 236 | target_arch = self.d.getVar('TARGET_ARCH', True) | ||
| 237 | platform = '%s%s-%s' % (target_arch.replace('-', '_'), | ||
| 238 | self.target_vendor, | ||
| 239 | self.ml_os_list['default']) | ||
| 240 | |||
| 241 | # List must be prefered to least preferred order | ||
| 242 | default_platform_extra = list() | ||
| 243 | platform_extra = list() | ||
| 244 | bbextendvariant = self.d.getVar('BBEXTENDVARIANT', True) or "" | ||
| 245 | for mlib in self.ml_os_list: | ||
| 246 | for arch in self.ml_prefix_list[mlib]: | ||
| 247 | plt = arch.replace('-', '_') + '-.*-' + self.ml_os_list[mlib] | ||
| 248 | if mlib == bbextendvariant: | ||
| 249 | if plt not in default_platform_extra: | ||
| 250 | default_platform_extra.append(plt) | ||
| 251 | else: | ||
| 252 | if plt not in platform_extra: | ||
| 253 | platform_extra.append(plt) | ||
| 254 | platform_extra = default_platform_extra + platform_extra | ||
| 133 | 255 | ||
| 134 | """ | 256 | self._create_configs(platform, platform_extra) |
| 135 | TBD | 257 | |
| 136 | """ | 258 | def _invoke_smart(self, args): |
| 259 | cmd = "%s %s %s" % (self.smart_cmd, self.smart_opt, args) | ||
| 260 | # bb.note(cmd) | ||
| 261 | try: | ||
| 262 | complementary_pkgs = subprocess.check_output(cmd, shell=True) | ||
| 263 | # bb.note(complementary_pkgs) | ||
| 264 | return complementary_pkgs | ||
| 265 | except subprocess.CalledProcessError as e: | ||
| 266 | bb.fatal("Could not invoke smart. Command " | ||
| 267 | "%s returned %d!" % (cmd, e.returncode)) | ||
| 268 | |||
| 269 | ''' | ||
| 270 | Translate the RPM/Smart format names to the OE multilib format names | ||
| 271 | ''' | ||
| 272 | def _pkg_translate_smart_to_oe(self, pkg, arch): | ||
| 273 | new_pkg = pkg | ||
| 274 | fixed_arch = arch.replace('_', '-') | ||
| 275 | found = 0 | ||
| 276 | for mlib in self.ml_prefix_list: | ||
| 277 | for cmp_arch in self.ml_prefix_list[mlib]: | ||
| 278 | fixed_cmp_arch = cmp_arch.replace('_', '-') | ||
| 279 | if fixed_arch == fixed_cmp_arch: | ||
| 280 | if mlib == 'default': | ||
| 281 | new_pkg = pkg | ||
| 282 | new_arch = cmp_arch | ||
| 283 | else: | ||
| 284 | new_pkg = mlib + '-' + pkg | ||
| 285 | # We need to strip off the ${mlib}_ prefix on the arch | ||
| 286 | new_arch = cmp_arch.replace(mlib + '_', '') | ||
| 287 | |||
| 288 | # Workaround for bug 3565. Simply look to see if we | ||
| 289 | # know of a package with that name, if not try again! | ||
| 290 | filename = os.path.join(self.d.getVar('PKGDATA_DIR', True), | ||
| 291 | 'runtime-reverse', | ||
| 292 | new_pkg) | ||
| 293 | if os.path.exists(filename): | ||
| 294 | found = 1 | ||
| 295 | break | ||
| 296 | |||
| 297 | if found == 1 and fixed_arch == fixed_cmp_arch: | ||
| 298 | break | ||
| 299 | #bb.note('%s, %s -> %s, %s' % (pkg, arch, new_pkg, new_arch)) | ||
| 300 | return new_pkg, new_arch | ||
| 301 | |||
| 302 | def _search_pkg_name_in_feeds(self, pkg, feed_archs): | ||
| 303 | for arch in feed_archs: | ||
| 304 | arch = arch.replace('-', '_') | ||
| 305 | for p in self.fullpkglist: | ||
| 306 | if pkg in p and '@' + arch in p: | ||
| 307 | # First found is best match | ||
| 308 | # bb.note('%s -> %s' % (pkg, pkg + '@' + arch)) | ||
| 309 | return pkg + '@' + arch | ||
| 310 | |||
| 311 | return "" | ||
| 312 | |||
| 313 | ''' | ||
| 314 | Translate the OE multilib format names to the RPM/Smart format names | ||
| 315 | It searched the RPM/Smart format names in probable multilib feeds first, | ||
| 316 | and then searched the default base feed. | ||
| 317 | ''' | ||
| 318 | def _pkg_translate_oe_to_smart(self, pkgs, attempt_only=False): | ||
| 319 | new_pkgs = list() | ||
| 320 | |||
| 321 | for pkg in pkgs: | ||
| 322 | new_pkg = pkg | ||
| 323 | # Search new_pkg in probable multilibs first | ||
| 324 | for mlib in self.ml_prefix_list: | ||
| 325 | # Jump the default archs | ||
| 326 | if mlib == 'default': | ||
| 327 | continue | ||
| 328 | |||
| 329 | subst = pkg.replace(mlib + '-', '') | ||
| 330 | # if the pkg in this multilib feed | ||
| 331 | if subst != pkg: | ||
| 332 | feed_archs = self.ml_prefix_list[mlib] | ||
| 333 | new_pkg = self._search_pkg_name_in_feeds(subst, feed_archs) | ||
| 334 | if not new_pkg: | ||
| 335 | # Failed to translate, package not found! | ||
| 336 | err_msg = '%s not found in the %s feeds (%s).\n' % \ | ||
| 337 | (pkg, mlib, " ".join(feed_archs)) | ||
| 338 | if not attempt_only: | ||
| 339 | err_msg += " ".join(self.fullpkglist) | ||
| 340 | bb.fatal(err_msg) | ||
| 341 | bb.warn(err_msg) | ||
| 342 | else: | ||
| 343 | new_pkgs.append(new_pkg) | ||
| 344 | |||
| 345 | break | ||
| 346 | |||
| 347 | # Apparently not a multilib package... | ||
| 348 | if pkg == new_pkg: | ||
| 349 | # Search new_pkg in default archs | ||
| 350 | default_archs = self.ml_prefix_list['default'] | ||
| 351 | new_pkg = self._search_pkg_name_in_feeds(pkg, default_archs) | ||
| 352 | if not new_pkg: | ||
| 353 | err_msg = '%s not found in the base feeds (%s).\n' % \ | ||
| 354 | (pkg, ' '.join(default_archs)) | ||
| 355 | if not attempt_only: | ||
| 356 | err_msg += " ".join(self.fullpkglist) | ||
| 357 | bb.fatal(err_msg) | ||
| 358 | bb.warn(err_msg) | ||
| 359 | else: | ||
| 360 | new_pkgs.append(new_pkg) | ||
| 361 | |||
| 362 | return new_pkgs | ||
| 363 | |||
| 364 | def _create_configs(self, platform, platform_extra): | ||
| 365 | # Setup base system configuration | ||
| 366 | bb.note("configuring RPM platform settings") | ||
| 367 | |||
| 368 | # Configure internal RPM environment when using Smart | ||
| 369 | os.environ['RPM_ETCRPM'] = self.etcrpm_dir | ||
| 370 | bb.utils.mkdirhier(self.etcrpm_dir) | ||
| 371 | |||
| 372 | # Setup temporary directory -- install... | ||
| 373 | if os.path.exists(self.install_dir): | ||
| 374 | bb.utils.remove(self.install_dir, True) | ||
| 375 | bb.utils.mkdirhier(os.path.join(self.install_dir, 'tmp')) | ||
| 376 | |||
| 377 | channel_priority = 5 | ||
| 378 | platform_dir = os.path.join(self.etcrpm_dir, "platform") | ||
| 379 | with open(platform_dir, "w+") as platform_fd: | ||
| 380 | platform_fd.write(platform + '\n') | ||
| 381 | for pt in platform_extra: | ||
| 382 | channel_priority += 5 | ||
| 383 | platform_fd.write(pt + '.*\n') | ||
| 384 | |||
| 385 | # Tell RPM that the "/" directory exist and is available | ||
| 386 | bb.note("configuring RPM system provides") | ||
| 387 | sysinfo_dir = os.path.join(self.etcrpm_dir, "sysinfo") | ||
| 388 | bb.utils.mkdirhier(sysinfo_dir) | ||
| 389 | with open(os.path.join(sysinfo_dir, "Dirnames"), "w+") as dirnames: | ||
| 390 | dirnames.write("/\n") | ||
| 391 | |||
| 392 | if self.providename: | ||
| 393 | providename_dir = os.path.join(sysinfo_dir, "Providename") | ||
| 394 | if not os.path.exists(providename_dir): | ||
| 395 | providename_content = '\n'.join(self.providename) | ||
| 396 | providename_content += '\n' | ||
| 397 | open(providename_dir, "w+").write(providename_content) | ||
| 398 | |||
| 399 | # Configure RPM... we enforce these settings! | ||
| 400 | bb.note("configuring RPM DB settings") | ||
| 401 | # After change the __db.* cache size, log file will not be | ||
| 402 | # generated automatically, that will raise some warnings, | ||
| 403 | # so touch a bare log for rpm write into it. | ||
| 404 | rpmlib_log = os.path.join(self.image_rpmlib, 'log', 'log.0000000001') | ||
| 405 | if not os.path.exists(rpmlib_log): | ||
| 406 | bb.utils.mkdirhier(os.path.join(self.image_rpmlib, 'log')) | ||
| 407 | open(rpmlib_log, 'w+').close() | ||
| 408 | db_config_dir = os.path.join(self.image_rpmlib, 'DB_CONFIG') | ||
| 409 | if not os.path.exists(db_config_dir): | ||
| 410 | open(db_config_dir, 'w+').write(DB_CONFIG_CONTENT) | ||
| 411 | |||
| 412 | # Create database so that smart doesn't complain (lazy init) | ||
| 413 | cmd = "%s --root %s --dbpath /var/lib/rpm -qa > /dev/null" % ( | ||
| 414 | self.rpm_cmd, | ||
| 415 | self.target_rootfs) | ||
| 416 | try: | ||
| 417 | subprocess.check_output(cmd, shell=True) | ||
| 418 | except subprocess.CalledProcessError as e: | ||
| 419 | bb.fatal("Create rpm database failed. Command %s " | ||
| 420 | "returned %d" % (cmd, e.returncode)) | ||
| 421 | |||
| 422 | # Configure smart | ||
| 423 | bb.note("configuring Smart settings") | ||
| 424 | bb.utils.remove(os.path.join(self.target_rootfs, 'var/lib/smart'), | ||
| 425 | True) | ||
| 426 | self._invoke_smart('config --set rpm-root=%s' % self.target_rootfs) | ||
| 427 | self._invoke_smart('config --set rpm-dbpath=/var/lib/rpm') | ||
| 428 | self._invoke_smart('config --set rpm-extra-macros._var=%s' % | ||
| 429 | self.d.getVar('localstatedir', True)) | ||
| 430 | cmd = 'config --set rpm-extra-macros._tmppath=/install/tmp' | ||
| 431 | self._invoke_smart(cmd) | ||
| 432 | |||
| 433 | # Write common configuration for host and target usage | ||
| 434 | self._invoke_smart('config --set rpm-nolinktos=1') | ||
| 435 | self._invoke_smart('config --set rpm-noparentdirs=1') | ||
| 436 | for i in self.d.getVar('BAD_RECOMMENDATIONS', True).split(): | ||
| 437 | self._invoke_smart('flag --set ignore-recommends %s' % i) | ||
| 438 | |||
| 439 | # Do the following configurations here, to avoid them being | ||
| 440 | # saved for field upgrade | ||
| 441 | if self.d.getVar('NO_RECOMMENDATIONS', True).strip() == "1": | ||
| 442 | self._invoke_smart('config --set ignore-all-recommends=1') | ||
| 443 | pkg_exclude = self.d.getVar('PACKAGE_EXCLUDE', True) or "" | ||
| 444 | for i in pkg_exclude.split(): | ||
| 445 | self._invoke_smart('flag --set exclude-packages %s' % i) | ||
| 446 | |||
| 447 | # Optional debugging | ||
| 448 | # self._invoke_smart('config --set rpm-log-level=debug') | ||
| 449 | # cmd = 'config --set rpm-log-file=/tmp/smart-debug-logfile' | ||
| 450 | # self._invoke_smart(cmd) | ||
| 451 | |||
| 452 | for canonical_arch in platform_extra: | ||
| 453 | arch = canonical_arch.split('-')[0] | ||
| 454 | arch_channel = os.path.join(self.deploy_dir, arch) | ||
| 455 | if os.path.exists(arch_channel): | ||
| 456 | bb.note('Note: adding Smart channel %s (%s)' % | ||
| 457 | (arch, channel_priority)) | ||
| 458 | self._invoke_smart('channel --add %s type=rpm-md baseurl=%s -y' | ||
| 459 | % (arch, arch_channel)) | ||
| 460 | self._invoke_smart('channel --set %s priority=%d' % | ||
| 461 | (arch, channel_priority)) | ||
| 462 | channel_priority -= 5 | ||
| 463 | |||
| 464 | bb.note('adding Smart RPM DB channel') | ||
| 465 | self._invoke_smart('channel --add rpmsys type=rpm-sys -y') | ||
| 466 | |||
| 467 | # Construct install scriptlet wrapper. | ||
| 468 | # Scripts need to be ordered when executed, this ensures numeric order. | ||
| 469 | # If we ever run into needing more the 899 scripts, we'll have to. | ||
| 470 | # change num to start with 1000. | ||
| 471 | # | ||
| 472 | intercept_dir = self.d.expand('${WORKDIR}/intercept_scripts') | ||
| 473 | native_root = self.d.getVar('STAGING_DIR_NATIVE', True) | ||
| 474 | scriptlet_content = SCRIPTLET_FORMAT % (os.environ['PATH'], | ||
| 475 | self.target_rootfs, | ||
| 476 | intercept_dir, | ||
| 477 | native_root) | ||
| 478 | open(self.scriptlet_wrapper, 'w+').write(scriptlet_content) | ||
| 479 | |||
| 480 | bb.note("Note: configuring RPM cross-install scriptlet_wrapper") | ||
| 481 | os.chmod(self.scriptlet_wrapper, 0755) | ||
| 482 | cmd = 'config --set rpm-extra-macros._cross_scriptlet_wrapper=%s' % \ | ||
| 483 | self.scriptlet_wrapper | ||
| 484 | self._invoke_smart(cmd) | ||
| 485 | |||
| 486 | # Debug to show smart config info | ||
| 487 | # bb.note(self._invoke_smart('config --show')) | ||
| 488 | |||
| 489 | def update(self): | ||
| 490 | self._invoke_smart('update rpmsys') | ||
| 491 | |||
| 492 | ''' | ||
| 493 | Install pkgs with smart, the pkg name is oe format | ||
| 494 | ''' | ||
| 495 | def install(self, pkgs, attempt_only=False): | ||
| 496 | |||
| 497 | bb.note("Installing the following packages: %s" % ' '.join(pkgs)) | ||
| 498 | if len(pkgs) == 0: | ||
| 499 | return | ||
| 500 | pkgs = self._pkg_translate_oe_to_smart(pkgs, attempt_only) | ||
| 501 | |||
| 502 | if not attempt_only: | ||
| 503 | bb.note('to be installed: %s' % ' '.join(pkgs)) | ||
| 504 | cmd = "%s %s install -y %s" % \ | ||
| 505 | (self.smart_cmd, self.smart_opt, ' '.join(pkgs)) | ||
| 506 | bb.note(cmd) | ||
| 507 | else: | ||
| 508 | bb.note('installing attempt only packages...') | ||
| 509 | bb.note('Attempting %s' % ' '.join(pkgs)) | ||
| 510 | cmd = "%s %s install --attempt -y %s" % \ | ||
| 511 | (self.smart_cmd, self.smart_opt, ' '.join(pkgs)) | ||
| 512 | try: | ||
| 513 | output = subprocess.check_output(cmd.split()) | ||
| 514 | bb.note(output) | ||
| 515 | except subprocess.CalledProcessError as e: | ||
| 516 | if not attempt_only: | ||
| 517 | bb.note("Unable to install packages. Command %s " | ||
| 518 | "returned %d" % (cmd, e.returncode)) | ||
| 519 | |||
| 520 | ''' | ||
| 521 | Remove pkgs with smart, the pkg name is smart/rpm format | ||
| 522 | ''' | ||
| 523 | def remove(self, pkgs, with_dependencies=True): | ||
| 524 | bb.note('to be removed: ' + ' '.join(pkgs)) | ||
| 525 | |||
| 526 | if not with_dependencies: | ||
| 527 | cmd = "%s -e --nodeps " % self.rpm_cmd | ||
| 528 | cmd += "--root=%s " % self.target_rootfs | ||
| 529 | cmd += "--dbpath=/var/lib/rpm " | ||
| 530 | cmd += "--define='_cross_scriptlet_wrapper %s' " % \ | ||
| 531 | self.scriptlet_wrapper | ||
| 532 | cmd += "--define='_tmppath /install/tmp' %s" % ' '.join(pkgs) | ||
| 533 | else: | ||
| 534 | # for pkg in pkgs: | ||
| 535 | # bb.note('Debug: What required: %s' % pkg) | ||
| 536 | # bb.note(self._invoke_smart('query %s --show-requiredby' % pkg)) | ||
| 537 | |||
| 538 | cmd = "%s %s remove -y %s" % (self.smart_cmd, | ||
| 539 | self.smart_opt, | ||
| 540 | ' '.join(pkgs)) | ||
| 541 | |||
| 542 | try: | ||
| 543 | bb.note(cmd) | ||
| 544 | output = subprocess.check_output(cmd, shell=True) | ||
| 545 | bb.note(output) | ||
| 546 | except subprocess.CalledProcessError as e: | ||
| 547 | bb.note("Unable to remove packages. Command %s " | ||
| 548 | "returned %d" % (cmd, e.returncode)) | ||
| 549 | |||
| 550 | def upgrade(self): | ||
| 551 | bb.note('smart upgrade') | ||
| 552 | self._invoke_smart('upgrade') | ||
| 553 | |||
| 554 | def write_index(self): | ||
| 555 | arch_list = list() | ||
| 556 | for mlib in self.ml_prefix_list: | ||
| 557 | for arch in self.ml_prefix_list[mlib]: | ||
| 558 | if arch not in arch_list: | ||
| 559 | arch_list.append(arch) | ||
| 560 | |||
| 561 | sdk_pkg_archs = self.d.getVar('SDK_PACKAGE_ARCHS', True) | ||
| 562 | if sdk_pkg_archs is not None: | ||
| 563 | arch_list += [i.replace('-', '_') for i in sdk_pkg_archs.split() | ||
| 564 | if i.replace('-', '_') not in arch_list] | ||
| 565 | |||
| 566 | rpm_createrepo = bb.utils.which(os.getenv('PATH'), "createrepo") | ||
| 567 | index_cmds = [] | ||
| 568 | rpm_dirs_found = False | ||
| 569 | for arch in arch_list: | ||
| 570 | arch_dir = os.path.join(self.deploy_dir, arch) | ||
| 571 | if not os.path.isdir(arch_dir): | ||
| 572 | continue | ||
| 573 | |||
| 574 | index_cmds.append("%s --update -q %s" % (rpm_createrepo, arch_dir)) | ||
| 575 | |||
| 576 | rpm_dirs_found = True | ||
| 577 | |||
| 578 | if not rpm_dirs_found: | ||
| 579 | bb.fatal("There are no packages in %s" % self.deploy_dir) | ||
| 580 | |||
| 581 | nproc = multiprocessing.cpu_count() | ||
| 582 | pool = bb.utils.multiprocessingpool(nproc) | ||
| 583 | results = list(pool.imap(create_index, index_cmds)) | ||
| 584 | pool.close() | ||
| 585 | pool.join() | ||
| 586 | |||
| 587 | for result in results: | ||
| 588 | if result is not None: | ||
| 589 | bb.fatal(result) | ||
| 590 | |||
| 591 | def remove_packaging_data(self): | ||
| 592 | bb.utils.remove(self.image_rpmlib, True) | ||
| 593 | bb.utils.remove(os.path.join(self.target_rootfs, 'var/lib/smart'), | ||
| 594 | True) | ||
| 595 | bb.utils.remove(os.path.join(self.target_rootfs, 'var/lib/opkg'), True) | ||
| 596 | |||
| 597 | # remove temp directory | ||
| 598 | bb.utils.remove(self.d.expand('${IMAGE_ROOTFS}/install'), True) | ||
| 599 | |||
| 600 | def backup_packaging_data(self): | ||
| 601 | # Save the rpmlib for increment rpm image generation | ||
| 602 | if os.path.exists(self.saved_rpmlib): | ||
| 603 | bb.utils.remove(self.saved_rpmlib, True) | ||
| 604 | shutil.copytree(self.image_rpmlib, | ||
| 605 | self.saved_rpmlib, | ||
| 606 | symlinks=True) | ||
| 607 | |||
| 608 | def recovery_packaging_data(self): | ||
| 609 | # Move the rpmlib back | ||
| 610 | if os.path.exists(self.saved_rpmlib): | ||
| 611 | if os.path.exists(self.image_rpmlib): | ||
| 612 | bb.utils.remove(self.image_rpmlib, True) | ||
| 613 | |||
| 614 | bb.note('Recovery packaging data') | ||
| 615 | shutil.copytree(self.saved_rpmlib, | ||
| 616 | self.image_rpmlib, | ||
| 617 | symlinks=True) | ||
| 618 | |||
| 619 | def list_installed(self, format=None): | ||
| 620 | cmd = self.rpm_cmd + ' --root ' + self.target_rootfs | ||
| 621 | cmd += ' -D "_dbpath /var/lib/rpm" -qa' | ||
| 622 | cmd += " --qf '[%{NAME} %{ARCH} %{VERSION} %{PACKAGEORIGIN}\n]'" | ||
| 623 | |||
| 624 | try: | ||
| 625 | # bb.note(cmd) | ||
| 626 | tmp_output = subprocess.check_output(cmd, shell=True).strip() | ||
| 627 | self._unlock_rpm_db() | ||
| 628 | except subprocess.CalledProcessError as e: | ||
| 629 | bb.fatal("Cannot get the installed packages list. Command %s " | ||
| 630 | "returned %d" % (cmd, e.returncode)) | ||
| 631 | |||
| 632 | output = list() | ||
| 633 | for line in tmp_output.split('\n'): | ||
| 634 | if len(line.strip()) == 0: | ||
| 635 | continue | ||
| 636 | pkg = line.split()[0] | ||
| 637 | arch = line.split()[1] | ||
| 638 | ver = line.split()[2] | ||
| 639 | pkgorigin = line.split()[3] | ||
| 640 | new_pkg, new_arch = self._pkg_translate_smart_to_oe(pkg, arch) | ||
| 641 | |||
| 642 | if format == "arch": | ||
| 643 | output.append('%s %s' % (new_pkg, new_arch)) | ||
| 644 | elif format == "file": | ||
| 645 | output.append('%s %s %s' % (new_pkg, pkgorigin, new_arch)) | ||
| 646 | elif format == "ver": | ||
| 647 | output.append('%s %s %s' % (new_pkg, new_arch, ver)) | ||
| 648 | else: | ||
| 649 | output.append('%s' % (new_pkg)) | ||
| 650 | |||
| 651 | output.sort() | ||
| 652 | |||
| 653 | return '\n'.join(output) | ||
| 654 | |||
| 655 | ''' | ||
| 656 | If incremental install, we need to determine what we've got, | ||
| 657 | what we need to add, and what to remove... | ||
| 658 | The dump_install_solution will dump and save the new install | ||
| 659 | solution. | ||
| 660 | ''' | ||
| 661 | def dump_install_solution(self, pkgs): | ||
| 662 | bb.note('creating new install solution for incremental install') | ||
| 663 | if len(pkgs) == 0: | ||
| 664 | return | ||
| 665 | |||
| 666 | pkgs = self._pkg_translate_oe_to_smart(pkgs, False) | ||
| 667 | install_pkgs = list() | ||
| 668 | |||
| 669 | cmd = "%s %s install -y --dump %s 2>%s" % \ | ||
| 670 | (self.smart_cmd, | ||
| 671 | self.smart_opt, | ||
| 672 | ' '.join(pkgs), | ||
| 673 | self.solution_manifest) | ||
| 674 | try: | ||
| 675 | # Disable rpmsys channel for the fake install | ||
| 676 | self._invoke_smart('channel --disable rpmsys') | ||
| 677 | |||
| 678 | subprocess.check_output(cmd, shell=True) | ||
| 679 | with open(self.solution_manifest, 'r') as manifest: | ||
| 680 | for pkg in manifest.read().split('\n'): | ||
| 681 | if '@' in pkg: | ||
| 682 | install_pkgs.append(pkg) | ||
| 683 | except subprocess.CalledProcessError as e: | ||
| 684 | bb.note("Unable to dump install packages. Command %s " | ||
| 685 | "returned %d" % (cmd, e.returncode)) | ||
| 686 | # Recovery rpmsys channel | ||
| 687 | self._invoke_smart('channel --enable rpmsys') | ||
| 688 | return install_pkgs | ||
| 689 | |||
| 690 | ''' | ||
| 691 | If incremental install, we need to determine what we've got, | ||
| 692 | what we need to add, and what to remove... | ||
| 693 | The load_old_install_solution will load the previous install | ||
| 694 | solution | ||
| 695 | ''' | ||
| 696 | def load_old_install_solution(self): | ||
| 697 | bb.note('load old install solution for incremental install') | ||
| 698 | installed_pkgs = list() | ||
| 699 | if not os.path.exists(self.solution_manifest): | ||
| 700 | bb.note('old install solution not exist') | ||
| 701 | return installed_pkgs | ||
| 702 | |||
| 703 | with open(self.solution_manifest, 'r') as manifest: | ||
| 704 | for pkg in manifest.read().split('\n'): | ||
| 705 | if '@' in pkg: | ||
| 706 | installed_pkgs.append(pkg.strip()) | ||
| 707 | |||
| 708 | return installed_pkgs | ||
| 709 | |||
| 710 | ''' | ||
| 711 | Dump all available packages in feeds, it should be invoked after the | ||
| 712 | newest rpm index was created | ||
| 713 | ''' | ||
| 714 | def dump_all_available_pkgs(self): | ||
| 715 | available_manifest = self.d.expand('${T}/saved/available_pkgs.txt') | ||
| 716 | available_pkgs = list() | ||
| 717 | cmd = "%s %s query --output %s" % \ | ||
| 718 | (self.smart_cmd, self.smart_opt, available_manifest) | ||
| 719 | try: | ||
| 720 | subprocess.check_output(cmd, shell=True) | ||
| 721 | with open(available_manifest, 'r') as manifest: | ||
| 722 | for pkg in manifest.read().split('\n'): | ||
| 723 | if '@' in pkg: | ||
| 724 | available_pkgs.append(pkg.strip()) | ||
| 725 | except subprocess.CalledProcessError as e: | ||
| 726 | bb.note("Unable to list all available packages. Command %s " | ||
| 727 | "returned %d" % (cmd, e.returncode)) | ||
| 728 | |||
| 729 | self.fullpkglist = available_pkgs | ||
| 730 | |||
| 731 | return | ||
| 732 | |||
| 733 | def save_rpmpostinist(self, pkg): | ||
| 734 | mlibs = self.d.getVar('MULTILIB_GLOBAL_VARIANTS').split() | ||
| 735 | new_pkg = pkg | ||
| 736 | # Remove any multilib prefix from the package name | ||
| 737 | for mlib in mlibs: | ||
| 738 | if mlib in pkg: | ||
| 739 | new_pkg = pkg.replace(mlib + '-', '') | ||
| 740 | break | ||
| 741 | |||
| 742 | bb.note(' * postponing %s' % new_pkg) | ||
| 743 | saved_dir = self.image_rootfs + self.d.expand('${sysconfdir}/rpm-postinsts/') + new_pkg | ||
| 744 | cmd = self.rpm_cmd + ' -q --scripts --root ' + self.target_rootfs | ||
| 745 | cmd += ' --dbpath=/var/lib/rpm ' + new_pkg | ||
| 746 | cmd += ' | sed -n -e "/^postinstall scriptlet (using .*):$/,/^.* scriptlet (using .*):$/ {/.*/p}"' | ||
| 747 | cmd += ' | sed -e "s/postinstall scriptlet (using \(.*\)):$/#!\1/"' | ||
| 748 | cmd += ' -e "/^.* scriptlet (using .*):$/d" > %s' % saved_dir | ||
| 749 | |||
| 750 | try: | ||
| 751 | bb.note(cmd) | ||
| 752 | output = subprocess.check_output(cmd, shell=True).strip() | ||
| 753 | bb.note(output) | ||
| 754 | os.chmod(saved_dir, 0755) | ||
| 755 | self._unlock_rpm_db() | ||
| 756 | except subprocess.CalledProcessError as e: | ||
| 757 | bb.fatal("Invoke save_rpmpostinist failed. Command %s " | ||
| 758 | "returned %d" % (cmd, e.returncode)) | ||
| 759 | |||
| 760 | '''Write common configuration for target usage''' | ||
| 761 | def rpm_setup_smart_target_config(self): | ||
| 762 | bb.utils.remove(os.path.join(self.target_rootfs, 'var/lib/smart'), | ||
| 763 | True) | ||
| 764 | |||
| 765 | self._invoke_smart('config --set rpm-nolinktos=1') | ||
| 766 | self._invoke_smart('config --set rpm-noparentdirs=1') | ||
| 767 | for i in self.d.getVar('BAD_RECOMMENDATIONS', True).split(): | ||
| 768 | self._invoke_smart('flag --set ignore-recommends %s' % i) | ||
| 769 | self._invoke_smart('channel --add rpmsys type=rpm-sys -y') | ||
| 770 | |||
| 771 | self._unlock_rpm_db() | ||
| 772 | |||
| 773 | ''' | ||
| 774 | The rpm db lock files were produced after invoking rpm to query on | ||
| 775 | build system, and they caused the rpm on target didn't work, so we | ||
| 776 | need to unlock the rpm db by removing the lock files. | ||
| 777 | ''' | ||
| 778 | def _unlock_rpm_db(self): | ||
| 779 | # Remove rpm db lock files | ||
| 780 | rpm_db_locks = glob.glob('%s/var/lib/rpm/__db.*' % self.target_rootfs) | ||
| 781 | for f in rpm_db_locks: | ||
| 782 | bb.utils.remove(f, True) | ||
| 137 | 783 | ||
| 138 | 784 | ||
| 139 | class OpkgPM(PackageManager): | 785 | class OpkgPM(PackageManager): |
