diff options
author | Fredrik Gustafsson <fredrik.gustafsson@axis.com> | 2020-07-24 16:42:35 +0200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2020-07-27 19:58:10 +0100 |
commit | 6fd8b177480719f6dec6bdde15d01d19dbfb00c7 (patch) | |
tree | 858cad6d27177e797becc66c7beb8ab45a356ba0 | |
parent | 873aee855f196cba43bed5201e7b30ba74a2b255 (diff) | |
download | poky-6fd8b177480719f6dec6bdde15d01d19dbfb00c7.tar.gz |
deb: Move rootfs to its own dir
This is a part of a refactor that will split the package manager
code so that it's possible to use other package managers in other
layers.
(From OE-Core rev: abadf053371ce863bf21b4a9474eb61761545de1)
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/deb/rootfs.py | 209 | ||||
-rw-r--r-- | meta/lib/oe/rootfs.py | 201 |
2 files changed, 211 insertions, 199 deletions
diff --git a/meta/lib/oe/package_manager/deb/rootfs.py b/meta/lib/oe/package_manager/deb/rootfs.py new file mode 100644 index 0000000000..0661ee7c5b --- /dev/null +++ b/meta/lib/oe/package_manager/deb/rootfs.py | |||
@@ -0,0 +1,209 @@ | |||
1 | # | ||
2 | # SPDX-License-Identifier: GPL-2.0-only | ||
3 | # | ||
4 | |||
5 | from oe.rootfs import Rootfs | ||
6 | from oe.package_manager import DpkgPM | ||
7 | from oe.manifest import Manifest | ||
8 | from oe.utils import execute_pre_post_process | ||
9 | from oe.package_manager.deb.manifest import DpkgManifest | ||
10 | import re | ||
11 | |||
12 | class DpkgOpkgRootfs(Rootfs): | ||
13 | def __init__(self, d, progress_reporter=None, logcatcher=None): | ||
14 | super(DpkgOpkgRootfs, self).__init__(d, progress_reporter, logcatcher) | ||
15 | |||
16 | def _get_pkgs_postinsts(self, status_file): | ||
17 | def _get_pkg_depends_list(pkg_depends): | ||
18 | pkg_depends_list = [] | ||
19 | # filter version requirements like libc (>= 1.1) | ||
20 | for dep in pkg_depends.split(', '): | ||
21 | m_dep = re.match(r"^(.*) \(.*\)$", dep) | ||
22 | if m_dep: | ||
23 | dep = m_dep.group(1) | ||
24 | pkg_depends_list.append(dep) | ||
25 | |||
26 | return pkg_depends_list | ||
27 | |||
28 | pkgs = {} | ||
29 | pkg_name = "" | ||
30 | pkg_status_match = False | ||
31 | pkg_depends = "" | ||
32 | |||
33 | with open(status_file) as status: | ||
34 | data = status.read() | ||
35 | status.close() | ||
36 | for line in data.split('\n'): | ||
37 | m_pkg = re.match(r"^Package: (.*)", line) | ||
38 | m_status = re.match(r"^Status:.*unpacked", line) | ||
39 | m_depends = re.match(r"^Depends: (.*)", line) | ||
40 | |||
41 | #Only one of m_pkg, m_status or m_depends is not None at time | ||
42 | #If m_pkg is not None, we started a new package | ||
43 | if m_pkg is not None: | ||
44 | #Get Package name | ||
45 | pkg_name = m_pkg.group(1) | ||
46 | #Make sure we reset other variables | ||
47 | pkg_status_match = False | ||
48 | pkg_depends = "" | ||
49 | elif m_status is not None: | ||
50 | #New status matched | ||
51 | pkg_status_match = True | ||
52 | elif m_depends is not None: | ||
53 | #New depends macthed | ||
54 | pkg_depends = m_depends.group(1) | ||
55 | else: | ||
56 | pass | ||
57 | |||
58 | #Now check if we can process package depends and postinst | ||
59 | if "" != pkg_name and pkg_status_match: | ||
60 | pkgs[pkg_name] = _get_pkg_depends_list(pkg_depends) | ||
61 | else: | ||
62 | #Not enough information | ||
63 | pass | ||
64 | |||
65 | # remove package dependencies not in postinsts | ||
66 | pkg_names = list(pkgs.keys()) | ||
67 | for pkg_name in pkg_names: | ||
68 | deps = pkgs[pkg_name][:] | ||
69 | |||
70 | for d in deps: | ||
71 | if d not in pkg_names: | ||
72 | pkgs[pkg_name].remove(d) | ||
73 | |||
74 | return pkgs | ||
75 | |||
76 | def _get_delayed_postinsts_common(self, status_file): | ||
77 | def _dep_resolve(graph, node, resolved, seen): | ||
78 | seen.append(node) | ||
79 | |||
80 | for edge in graph[node]: | ||
81 | if edge not in resolved: | ||
82 | if edge in seen: | ||
83 | raise RuntimeError("Packages %s and %s have " \ | ||
84 | "a circular dependency in postinsts scripts." \ | ||
85 | % (node, edge)) | ||
86 | _dep_resolve(graph, edge, resolved, seen) | ||
87 | |||
88 | resolved.append(node) | ||
89 | |||
90 | pkg_list = [] | ||
91 | |||
92 | pkgs = None | ||
93 | if not self.d.getVar('PACKAGE_INSTALL').strip(): | ||
94 | bb.note("Building empty image") | ||
95 | else: | ||
96 | pkgs = self._get_pkgs_postinsts(status_file) | ||
97 | if pkgs: | ||
98 | root = "__packagegroup_postinst__" | ||
99 | pkgs[root] = list(pkgs.keys()) | ||
100 | _dep_resolve(pkgs, root, pkg_list, []) | ||
101 | pkg_list.remove(root) | ||
102 | |||
103 | if len(pkg_list) == 0: | ||
104 | return None | ||
105 | |||
106 | return pkg_list | ||
107 | |||
108 | def _save_postinsts_common(self, dst_postinst_dir, src_postinst_dir): | ||
109 | if bb.utils.contains("IMAGE_FEATURES", "package-management", | ||
110 | True, False, self.d): | ||
111 | return | ||
112 | num = 0 | ||
113 | for p in self._get_delayed_postinsts(): | ||
114 | bb.utils.mkdirhier(dst_postinst_dir) | ||
115 | |||
116 | if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")): | ||
117 | shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"), | ||
118 | os.path.join(dst_postinst_dir, "%03d-%s" % (num, p))) | ||
119 | |||
120 | num += 1 | ||
121 | |||
122 | class DpkgRootfs(DpkgOpkgRootfs): | ||
123 | def __init__(self, d, manifest_dir, progress_reporter=None, logcatcher=None): | ||
124 | super(DpkgRootfs, self).__init__(d, progress_reporter, logcatcher) | ||
125 | self.log_check_regex = '^E:' | ||
126 | self.log_check_expected_regexes = \ | ||
127 | [ | ||
128 | "^E: Unmet dependencies." | ||
129 | ] | ||
130 | |||
131 | bb.utils.remove(self.image_rootfs, True) | ||
132 | bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS'), True) | ||
133 | self.manifest = DpkgManifest(d, manifest_dir) | ||
134 | self.pm = DpkgPM(d, d.getVar('IMAGE_ROOTFS'), | ||
135 | d.getVar('PACKAGE_ARCHS'), | ||
136 | d.getVar('DPKG_ARCH')) | ||
137 | |||
138 | |||
139 | def _create(self): | ||
140 | pkgs_to_install = self.manifest.parse_initial_manifest() | ||
141 | deb_pre_process_cmds = self.d.getVar('DEB_PREPROCESS_COMMANDS') | ||
142 | deb_post_process_cmds = self.d.getVar('DEB_POSTPROCESS_COMMANDS') | ||
143 | |||
144 | alt_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/alternatives") | ||
145 | bb.utils.mkdirhier(alt_dir) | ||
146 | |||
147 | # update PM index files | ||
148 | self.pm.write_index() | ||
149 | |||
150 | execute_pre_post_process(self.d, deb_pre_process_cmds) | ||
151 | |||
152 | if self.progress_reporter: | ||
153 | self.progress_reporter.next_stage() | ||
154 | # Don't support incremental, so skip that | ||
155 | self.progress_reporter.next_stage() | ||
156 | |||
157 | self.pm.update() | ||
158 | |||
159 | if self.progress_reporter: | ||
160 | self.progress_reporter.next_stage() | ||
161 | |||
162 | for pkg_type in self.install_order: | ||
163 | if pkg_type in pkgs_to_install: | ||
164 | self.pm.install(pkgs_to_install[pkg_type], | ||
165 | [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY]) | ||
166 | self.pm.fix_broken_dependencies() | ||
167 | |||
168 | if self.progress_reporter: | ||
169 | # Don't support attemptonly, so skip that | ||
170 | self.progress_reporter.next_stage() | ||
171 | self.progress_reporter.next_stage() | ||
172 | |||
173 | self.pm.install_complementary() | ||
174 | |||
175 | if self.progress_reporter: | ||
176 | self.progress_reporter.next_stage() | ||
177 | |||
178 | self._setup_dbg_rootfs(['/var/lib/dpkg']) | ||
179 | |||
180 | self.pm.fix_broken_dependencies() | ||
181 | |||
182 | self.pm.mark_packages("installed") | ||
183 | |||
184 | self.pm.run_pre_post_installs() | ||
185 | |||
186 | execute_pre_post_process(self.d, deb_post_process_cmds) | ||
187 | |||
188 | if self.progress_reporter: | ||
189 | self.progress_reporter.next_stage() | ||
190 | |||
191 | @staticmethod | ||
192 | def _depends_list(): | ||
193 | return ['DEPLOY_DIR_DEB', 'DEB_SDK_ARCH', 'APTCONF_TARGET', 'APT_ARGS', 'DPKG_ARCH', 'DEB_PREPROCESS_COMMANDS', 'DEB_POSTPROCESS_COMMANDS'] | ||
194 | |||
195 | def _get_delayed_postinsts(self): | ||
196 | status_file = self.image_rootfs + "/var/lib/dpkg/status" | ||
197 | return self._get_delayed_postinsts_common(status_file) | ||
198 | |||
199 | def _save_postinsts(self): | ||
200 | dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/deb-postinsts") | ||
201 | src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/info") | ||
202 | return self._save_postinsts_common(dst_postinst_dir, src_postinst_dir) | ||
203 | |||
204 | def _log_check(self): | ||
205 | self._log_check_warn() | ||
206 | self._log_check_error() | ||
207 | |||
208 | def _cleanup(self): | ||
209 | pass | ||
diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py index 062ea7f335..17ca323588 100644 --- a/meta/lib/oe/rootfs.py +++ b/meta/lib/oe/rootfs.py | |||
@@ -354,208 +354,10 @@ class Rootfs(object, metaclass=ABCMeta): | |||
354 | self.image_rootfs, "-D", devtable]) | 354 | self.image_rootfs, "-D", devtable]) |
355 | 355 | ||
356 | 356 | ||
357 | class DpkgOpkgRootfs(Rootfs): | ||
358 | def __init__(self, d, progress_reporter=None, logcatcher=None): | ||
359 | super(DpkgOpkgRootfs, self).__init__(d, progress_reporter, logcatcher) | ||
360 | |||
361 | def _get_pkgs_postinsts(self, status_file): | ||
362 | def _get_pkg_depends_list(pkg_depends): | ||
363 | pkg_depends_list = [] | ||
364 | # filter version requirements like libc (>= 1.1) | ||
365 | for dep in pkg_depends.split(', '): | ||
366 | m_dep = re.match(r"^(.*) \(.*\)$", dep) | ||
367 | if m_dep: | ||
368 | dep = m_dep.group(1) | ||
369 | pkg_depends_list.append(dep) | ||
370 | |||
371 | return pkg_depends_list | ||
372 | |||
373 | pkgs = {} | ||
374 | pkg_name = "" | ||
375 | pkg_status_match = False | ||
376 | pkg_depends = "" | ||
377 | |||
378 | with open(status_file) as status: | ||
379 | data = status.read() | ||
380 | status.close() | ||
381 | for line in data.split('\n'): | ||
382 | m_pkg = re.match(r"^Package: (.*)", line) | ||
383 | m_status = re.match(r"^Status:.*unpacked", line) | ||
384 | m_depends = re.match(r"^Depends: (.*)", line) | ||
385 | |||
386 | #Only one of m_pkg, m_status or m_depends is not None at time | ||
387 | #If m_pkg is not None, we started a new package | ||
388 | if m_pkg is not None: | ||
389 | #Get Package name | ||
390 | pkg_name = m_pkg.group(1) | ||
391 | #Make sure we reset other variables | ||
392 | pkg_status_match = False | ||
393 | pkg_depends = "" | ||
394 | elif m_status is not None: | ||
395 | #New status matched | ||
396 | pkg_status_match = True | ||
397 | elif m_depends is not None: | ||
398 | #New depends macthed | ||
399 | pkg_depends = m_depends.group(1) | ||
400 | else: | ||
401 | pass | ||
402 | |||
403 | #Now check if we can process package depends and postinst | ||
404 | if "" != pkg_name and pkg_status_match: | ||
405 | pkgs[pkg_name] = _get_pkg_depends_list(pkg_depends) | ||
406 | else: | ||
407 | #Not enough information | ||
408 | pass | ||
409 | |||
410 | # remove package dependencies not in postinsts | ||
411 | pkg_names = list(pkgs.keys()) | ||
412 | for pkg_name in pkg_names: | ||
413 | deps = pkgs[pkg_name][:] | ||
414 | |||
415 | for d in deps: | ||
416 | if d not in pkg_names: | ||
417 | pkgs[pkg_name].remove(d) | ||
418 | |||
419 | return pkgs | ||
420 | |||
421 | def _get_delayed_postinsts_common(self, status_file): | ||
422 | def _dep_resolve(graph, node, resolved, seen): | ||
423 | seen.append(node) | ||
424 | |||
425 | for edge in graph[node]: | ||
426 | if edge not in resolved: | ||
427 | if edge in seen: | ||
428 | raise RuntimeError("Packages %s and %s have " \ | ||
429 | "a circular dependency in postinsts scripts." \ | ||
430 | % (node, edge)) | ||
431 | _dep_resolve(graph, edge, resolved, seen) | ||
432 | |||
433 | resolved.append(node) | ||
434 | |||
435 | pkg_list = [] | ||
436 | |||
437 | pkgs = None | ||
438 | if not self.d.getVar('PACKAGE_INSTALL').strip(): | ||
439 | bb.note("Building empty image") | ||
440 | else: | ||
441 | pkgs = self._get_pkgs_postinsts(status_file) | ||
442 | if pkgs: | ||
443 | root = "__packagegroup_postinst__" | ||
444 | pkgs[root] = list(pkgs.keys()) | ||
445 | _dep_resolve(pkgs, root, pkg_list, []) | ||
446 | pkg_list.remove(root) | ||
447 | |||
448 | if len(pkg_list) == 0: | ||
449 | return None | ||
450 | |||
451 | return pkg_list | ||
452 | |||
453 | def _save_postinsts_common(self, dst_postinst_dir, src_postinst_dir): | ||
454 | if bb.utils.contains("IMAGE_FEATURES", "package-management", | ||
455 | True, False, self.d): | ||
456 | return | ||
457 | num = 0 | ||
458 | for p in self._get_delayed_postinsts(): | ||
459 | bb.utils.mkdirhier(dst_postinst_dir) | ||
460 | |||
461 | if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")): | ||
462 | shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"), | ||
463 | os.path.join(dst_postinst_dir, "%03d-%s" % (num, p))) | ||
464 | |||
465 | num += 1 | ||
466 | |||
467 | class DpkgRootfs(DpkgOpkgRootfs): | ||
468 | def __init__(self, d, manifest_dir, progress_reporter=None, logcatcher=None): | ||
469 | super(DpkgRootfs, self).__init__(d, progress_reporter, logcatcher) | ||
470 | self.log_check_regex = '^E:' | ||
471 | self.log_check_expected_regexes = \ | ||
472 | [ | ||
473 | "^E: Unmet dependencies." | ||
474 | ] | ||
475 | |||
476 | bb.utils.remove(self.image_rootfs, True) | ||
477 | bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS'), True) | ||
478 | self.manifest = DpkgManifest(d, manifest_dir) | ||
479 | self.pm = DpkgPM(d, d.getVar('IMAGE_ROOTFS'), | ||
480 | d.getVar('PACKAGE_ARCHS'), | ||
481 | d.getVar('DPKG_ARCH')) | ||
482 | |||
483 | |||
484 | def _create(self): | ||
485 | pkgs_to_install = self.manifest.parse_initial_manifest() | ||
486 | deb_pre_process_cmds = self.d.getVar('DEB_PREPROCESS_COMMANDS') | ||
487 | deb_post_process_cmds = self.d.getVar('DEB_POSTPROCESS_COMMANDS') | ||
488 | |||
489 | alt_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/alternatives") | ||
490 | bb.utils.mkdirhier(alt_dir) | ||
491 | |||
492 | # update PM index files | ||
493 | self.pm.write_index() | ||
494 | |||
495 | execute_pre_post_process(self.d, deb_pre_process_cmds) | ||
496 | |||
497 | if self.progress_reporter: | ||
498 | self.progress_reporter.next_stage() | ||
499 | # Don't support incremental, so skip that | ||
500 | self.progress_reporter.next_stage() | ||
501 | |||
502 | self.pm.update() | ||
503 | |||
504 | if self.progress_reporter: | ||
505 | self.progress_reporter.next_stage() | ||
506 | |||
507 | for pkg_type in self.install_order: | ||
508 | if pkg_type in pkgs_to_install: | ||
509 | self.pm.install(pkgs_to_install[pkg_type], | ||
510 | [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY]) | ||
511 | self.pm.fix_broken_dependencies() | ||
512 | |||
513 | if self.progress_reporter: | ||
514 | # Don't support attemptonly, so skip that | ||
515 | self.progress_reporter.next_stage() | ||
516 | self.progress_reporter.next_stage() | ||
517 | |||
518 | self.pm.install_complementary() | ||
519 | |||
520 | if self.progress_reporter: | ||
521 | self.progress_reporter.next_stage() | ||
522 | |||
523 | self._setup_dbg_rootfs(['/var/lib/dpkg']) | ||
524 | |||
525 | self.pm.fix_broken_dependencies() | ||
526 | |||
527 | self.pm.mark_packages("installed") | ||
528 | |||
529 | self.pm.run_pre_post_installs() | ||
530 | |||
531 | execute_pre_post_process(self.d, deb_post_process_cmds) | ||
532 | |||
533 | if self.progress_reporter: | ||
534 | self.progress_reporter.next_stage() | ||
535 | |||
536 | @staticmethod | ||
537 | def _depends_list(): | ||
538 | return ['DEPLOY_DIR_DEB', 'DEB_SDK_ARCH', 'APTCONF_TARGET', 'APT_ARGS', 'DPKG_ARCH', 'DEB_PREPROCESS_COMMANDS', 'DEB_POSTPROCESS_COMMANDS'] | ||
539 | |||
540 | def _get_delayed_postinsts(self): | ||
541 | status_file = self.image_rootfs + "/var/lib/dpkg/status" | ||
542 | return self._get_delayed_postinsts_common(status_file) | ||
543 | |||
544 | def _save_postinsts(self): | ||
545 | dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/deb-postinsts") | ||
546 | src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/info") | ||
547 | return self._save_postinsts_common(dst_postinst_dir, src_postinst_dir) | ||
548 | |||
549 | def _log_check(self): | ||
550 | self._log_check_warn() | ||
551 | self._log_check_error() | ||
552 | |||
553 | def _cleanup(self): | ||
554 | pass | ||
555 | |||
556 | def get_class_for_type(imgtype): | 357 | def get_class_for_type(imgtype): |
557 | from oe.package_manager.rpm.rootfs import RpmRootfs | 358 | from oe.package_manager.rpm.rootfs import RpmRootfs |
558 | from oe.package_manager.ipk.rootfs import OpkgRootfs | 359 | from oe.package_manager.ipk.rootfs import OpkgRootfs |
360 | from oe.package_manager.deb.rootfs import DpkgRootfs | ||
559 | return {"rpm": RpmRootfs, | 361 | return {"rpm": RpmRootfs, |
560 | "ipk": OpkgRootfs, | 362 | "ipk": OpkgRootfs, |
561 | "deb": DpkgRootfs}[imgtype] | 363 | "deb": DpkgRootfs}[imgtype] |
@@ -570,6 +372,7 @@ def create_rootfs(d, manifest_dir=None, progress_reporter=None, logcatcher=None) | |||
570 | 372 | ||
571 | from oe.package_manager.rpm.rootfs import RpmRootfs | 373 | from oe.package_manager.rpm.rootfs import RpmRootfs |
572 | from oe.package_manager.ipk.rootfs import OpkgRootfs | 374 | from oe.package_manager.ipk.rootfs import OpkgRootfs |
375 | from oe.package_manager.deb.rootfs import DpkgRootfs | ||
573 | img_type = d.getVar('IMAGE_PKGTYPE') | 376 | img_type = d.getVar('IMAGE_PKGTYPE') |
574 | if img_type == "rpm": | 377 | if img_type == "rpm": |
575 | RpmRootfs(d, manifest_dir, progress_reporter, logcatcher).create() | 378 | RpmRootfs(d, manifest_dir, progress_reporter, logcatcher).create() |