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 | |
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')
-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): |