diff options
| author | Richard Purdie <richard.purdie@linuxfoundation.org> | 2025-11-07 13:31:53 +0000 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2025-11-07 13:31:53 +0000 |
| commit | 8c22ff0d8b70d9b12f0487ef696a7e915b9e3173 (patch) | |
| tree | efdc32587159d0050a69009bdf2330a531727d95 /meta/lib/oe/package_manager/deb | |
| parent | d412d2747595c1cc4a5e3ca975e3adc31b2f7891 (diff) | |
| download | poky-8c22ff0d8b70d9b12f0487ef696a7e915b9e3173.tar.gz | |
The poky repository master branch is no longer being updated.
You can either:
a) switch to individual clones of bitbake, openembedded-core, meta-yocto and yocto-docs
b) use the new bitbake-setup
You can find information about either approach in our documentation:
https://docs.yoctoproject.org/
Note that "poky" the distro setting is still available in meta-yocto as
before and we continue to use and maintain that.
Long live Poky!
Some further information on the background of this change can be found
in: https://lists.openembedded.org/g/openembedded-architecture/message/2179
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib/oe/package_manager/deb')
| -rw-r--r-- | meta/lib/oe/package_manager/deb/__init__.py | 451 | ||||
| -rw-r--r-- | meta/lib/oe/package_manager/deb/manifest.py | 28 | ||||
| -rw-r--r-- | meta/lib/oe/package_manager/deb/rootfs.py | 212 | ||||
| -rw-r--r-- | meta/lib/oe/package_manager/deb/sdk.py | 107 |
4 files changed, 0 insertions, 798 deletions
diff --git a/meta/lib/oe/package_manager/deb/__init__.py b/meta/lib/oe/package_manager/deb/__init__.py deleted file mode 100644 index eb48f3f982..0000000000 --- a/meta/lib/oe/package_manager/deb/__init__.py +++ /dev/null | |||
| @@ -1,451 +0,0 @@ | |||
| 1 | # | ||
| 2 | # Copyright OpenEmbedded Contributors | ||
| 3 | # | ||
| 4 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 5 | # | ||
| 6 | |||
| 7 | import re | ||
| 8 | import subprocess | ||
| 9 | from oe.package_manager import * | ||
| 10 | from oe.package_manager.common_deb_ipk import OpkgDpkgPM | ||
| 11 | |||
| 12 | class DpkgIndexer(Indexer): | ||
| 13 | def _create_configs(self): | ||
| 14 | bb.utils.mkdirhier(self.apt_conf_dir) | ||
| 15 | bb.utils.mkdirhier(os.path.join(self.apt_conf_dir, "lists", "partial")) | ||
| 16 | bb.utils.mkdirhier(os.path.join(self.apt_conf_dir, "apt.conf.d")) | ||
| 17 | bb.utils.mkdirhier(os.path.join(self.apt_conf_dir, "preferences.d")) | ||
| 18 | |||
| 19 | with open(os.path.join(self.apt_conf_dir, "preferences"), | ||
| 20 | "w") as prefs_file: | ||
| 21 | pass | ||
| 22 | with open(os.path.join(self.apt_conf_dir, "sources.list"), | ||
| 23 | "w+") as sources_file: | ||
| 24 | pass | ||
| 25 | |||
| 26 | with open(self.apt_conf_file, "w") as apt_conf: | ||
| 27 | with open(os.path.join(self.d.expand("${STAGING_ETCDIR_NATIVE}"), | ||
| 28 | "apt", "apt.conf.sample")) as apt_conf_sample: | ||
| 29 | for line in apt_conf_sample.read().split("\n"): | ||
| 30 | line = re.sub(r"#ROOTFS#", "/dev/null", line) | ||
| 31 | line = re.sub(r"#APTCONF#", self.apt_conf_dir, line) | ||
| 32 | apt_conf.write(line + "\n") | ||
| 33 | |||
| 34 | def write_index(self): | ||
| 35 | self.apt_conf_dir = os.path.join(self.d.expand("${APTCONF_TARGET}"), | ||
| 36 | "apt-ftparchive") | ||
| 37 | self.apt_conf_file = os.path.join(self.apt_conf_dir, "apt.conf") | ||
| 38 | self._create_configs() | ||
| 39 | |||
| 40 | os.environ['APT_CONFIG'] = self.apt_conf_file | ||
| 41 | |||
| 42 | pkg_archs = self.d.getVar('PACKAGE_ARCHS') | ||
| 43 | if pkg_archs is not None: | ||
| 44 | arch_list = pkg_archs.split() | ||
| 45 | sdk_pkg_archs = self.d.getVar('SDK_PACKAGE_ARCHS') | ||
| 46 | if sdk_pkg_archs is not None: | ||
| 47 | for a in sdk_pkg_archs.split(): | ||
| 48 | if a not in pkg_archs: | ||
| 49 | arch_list.append(a) | ||
| 50 | |||
| 51 | all_mlb_pkg_arch_list = (self.d.getVar('ALL_MULTILIB_PACKAGE_ARCHS') or "").split() | ||
| 52 | arch_list.extend(arch for arch in all_mlb_pkg_arch_list if arch not in arch_list) | ||
| 53 | |||
| 54 | apt_ftparchive = bb.utils.which(os.getenv('PATH'), "apt-ftparchive") | ||
| 55 | gzip = bb.utils.which(os.getenv('PATH'), "gzip") | ||
| 56 | |||
| 57 | index_cmds = [] | ||
| 58 | deb_dirs_found = False | ||
| 59 | index_sign_files = set() | ||
| 60 | for arch in arch_list: | ||
| 61 | arch_dir = os.path.join(self.deploy_dir, arch) | ||
| 62 | if not os.path.isdir(arch_dir): | ||
| 63 | continue | ||
| 64 | |||
| 65 | cmd = "cd %s; PSEUDO_UNLOAD=1 %s packages . > Packages;" % (arch_dir, apt_ftparchive) | ||
| 66 | |||
| 67 | cmd += "%s -fcn Packages > Packages.gz;" % gzip | ||
| 68 | |||
| 69 | release_file = os.path.join(arch_dir, "Release") | ||
| 70 | index_sign_files.add(release_file) | ||
| 71 | |||
| 72 | with open(release_file, "w+") as release: | ||
| 73 | release.write("Label: %s\n" % arch) | ||
| 74 | |||
| 75 | cmd += "PSEUDO_UNLOAD=1 %s release . >> Release" % apt_ftparchive | ||
| 76 | |||
| 77 | index_cmds.append(cmd) | ||
| 78 | |||
| 79 | deb_dirs_found = True | ||
| 80 | |||
| 81 | if not deb_dirs_found: | ||
| 82 | bb.note("There are no packages in %s" % self.deploy_dir) | ||
| 83 | return | ||
| 84 | |||
| 85 | oe.utils.multiprocess_launch(create_index, index_cmds, self.d) | ||
| 86 | if self.d.getVar('PACKAGE_FEED_SIGN') == '1': | ||
| 87 | signer = get_signer(self.d, self.d.getVar('PACKAGE_FEED_GPG_BACKEND')) | ||
| 88 | else: | ||
| 89 | signer = None | ||
| 90 | if signer: | ||
| 91 | for f in index_sign_files: | ||
| 92 | signer.detach_sign(f, | ||
| 93 | self.d.getVar('PACKAGE_FEED_GPG_NAME'), | ||
| 94 | self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE'), | ||
| 95 | output_suffix="gpg", | ||
| 96 | use_sha256=True) | ||
| 97 | |||
| 98 | class PMPkgsList(PkgsList): | ||
| 99 | |||
| 100 | def list_pkgs(self): | ||
| 101 | cmd = [bb.utils.which(os.getenv('PATH'), "dpkg-query"), | ||
| 102 | "--admindir=%s/var/lib/dpkg" % self.rootfs_dir, | ||
| 103 | "-W"] | ||
| 104 | |||
| 105 | cmd.append("-f=Package: ${Package}\nArchitecture: ${PackageArch}\nVersion: ${Version}\nFile: ${Package}_${Version}_${Architecture}.deb\nDepends: ${Depends}\nRecommends: ${Recommends}\nProvides: ${Provides}\n\n") | ||
| 106 | |||
| 107 | try: | ||
| 108 | cmd_output = subprocess.check_output(cmd, stderr=subprocess.STDOUT).strip().decode("utf-8") | ||
| 109 | except subprocess.CalledProcessError as e: | ||
| 110 | bb.fatal("Cannot get the installed packages list. Command '%s' " | ||
| 111 | "returned %d:\n%s" % (' '.join(cmd), e.returncode, e.output.decode("utf-8"))) | ||
| 112 | |||
| 113 | return opkg_query(cmd_output) | ||
| 114 | |||
| 115 | |||
| 116 | class DpkgPM(OpkgDpkgPM): | ||
| 117 | def __init__(self, d, target_rootfs, archs, base_archs, apt_conf_dir=None, deb_repo_workdir="oe-rootfs-repo", filterbydependencies=True): | ||
| 118 | super(DpkgPM, self).__init__(d, target_rootfs) | ||
| 119 | self.deploy_dir = oe.path.join(self.d.getVar('WORKDIR'), deb_repo_workdir) | ||
| 120 | |||
| 121 | create_packages_dir(self.d, self.deploy_dir, d.getVar("DEPLOY_DIR_DEB"), "package_write_deb", filterbydependencies) | ||
| 122 | |||
| 123 | if apt_conf_dir is None: | ||
| 124 | self.apt_conf_dir = self.d.expand("${APTCONF_TARGET}/apt") | ||
| 125 | else: | ||
| 126 | self.apt_conf_dir = apt_conf_dir | ||
| 127 | self.apt_conf_file = os.path.join(self.apt_conf_dir, "apt.conf") | ||
| 128 | self.apt_get_cmd = bb.utils.which(os.getenv('PATH'), "apt-get") | ||
| 129 | self.apt_cache_cmd = bb.utils.which(os.getenv('PATH'), "apt-cache") | ||
| 130 | |||
| 131 | self.apt_args = d.getVar("APT_ARGS") | ||
| 132 | |||
| 133 | self.all_arch_list = archs.split() | ||
| 134 | all_mlb_pkg_arch_list = (self.d.getVar('ALL_MULTILIB_PACKAGE_ARCHS') or "").split() | ||
| 135 | self.all_arch_list.extend(arch for arch in all_mlb_pkg_arch_list if arch not in self.all_arch_list) | ||
| 136 | |||
| 137 | self._create_configs(archs, base_archs) | ||
| 138 | |||
| 139 | self.indexer = DpkgIndexer(self.d, self.deploy_dir) | ||
| 140 | |||
| 141 | def mark_packages(self, status_tag, packages=None): | ||
| 142 | """ | ||
| 143 | This function will change a package's status in /var/lib/dpkg/status file. | ||
| 144 | If 'packages' is None then the new_status will be applied to all | ||
| 145 | packages | ||
| 146 | """ | ||
| 147 | status_file = self.target_rootfs + "/var/lib/dpkg/status" | ||
| 148 | |||
| 149 | with open(status_file, "r") as sf: | ||
| 150 | with open(status_file + ".tmp", "w+") as tmp_sf: | ||
| 151 | if packages is None: | ||
| 152 | tmp_sf.write(re.sub(r"Package: (.*?)\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)", | ||
| 153 | r"Package: \1\n\2Status: \3%s" % status_tag, | ||
| 154 | sf.read())) | ||
| 155 | else: | ||
| 156 | if type(packages).__name__ != "list": | ||
| 157 | raise TypeError("'packages' should be a list object") | ||
| 158 | |||
| 159 | status = sf.read() | ||
| 160 | for pkg in packages: | ||
| 161 | status = re.sub(r"Package: %s\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)" % pkg, | ||
| 162 | r"Package: %s\n\1Status: \2%s" % (pkg, status_tag), | ||
| 163 | status) | ||
| 164 | |||
| 165 | tmp_sf.write(status) | ||
| 166 | |||
| 167 | bb.utils.rename(status_file + ".tmp", status_file) | ||
| 168 | |||
| 169 | def run_pre_post_installs(self, package_name=None): | ||
| 170 | """ | ||
| 171 | Run the pre/post installs for package "package_name". If package_name is | ||
| 172 | None, then run all pre/post install scriptlets. | ||
| 173 | """ | ||
| 174 | info_dir = self.target_rootfs + "/var/lib/dpkg/info" | ||
| 175 | ControlScript = collections.namedtuple("ControlScript", ["suffix", "name", "argument"]) | ||
| 176 | control_scripts = [ | ||
| 177 | ControlScript(".preinst", "Preinstall", "install"), | ||
| 178 | ControlScript(".postinst", "Postinstall", "configure")] | ||
| 179 | status_file = self.target_rootfs + "/var/lib/dpkg/status" | ||
| 180 | installed_pkgs = [] | ||
| 181 | |||
| 182 | with open(status_file, "r") as status: | ||
| 183 | for line in status.read().split('\n'): | ||
| 184 | m = re.match(r"^Package: (.*)", line) | ||
| 185 | if m is not None: | ||
| 186 | installed_pkgs.append(m.group(1)) | ||
| 187 | |||
| 188 | if package_name is not None and not package_name in installed_pkgs: | ||
| 189 | return | ||
| 190 | |||
| 191 | os.environ['D'] = self.target_rootfs | ||
| 192 | os.environ['OFFLINE_ROOT'] = self.target_rootfs | ||
| 193 | os.environ['IPKG_OFFLINE_ROOT'] = self.target_rootfs | ||
| 194 | os.environ['OPKG_OFFLINE_ROOT'] = self.target_rootfs | ||
| 195 | os.environ['INTERCEPT_DIR'] = self.intercepts_dir | ||
| 196 | os.environ['NATIVE_ROOT'] = self.d.getVar('STAGING_DIR_NATIVE') | ||
| 197 | |||
| 198 | for pkg_name in installed_pkgs: | ||
| 199 | for control_script in control_scripts: | ||
| 200 | p_full = os.path.join(info_dir, pkg_name + control_script.suffix) | ||
| 201 | if os.path.exists(p_full): | ||
| 202 | try: | ||
| 203 | bb.note("Executing %s for package: %s ..." % | ||
| 204 | (control_script.name.lower(), pkg_name)) | ||
| 205 | output = subprocess.check_output([p_full, control_script.argument], | ||
| 206 | stderr=subprocess.STDOUT).decode("utf-8") | ||
| 207 | bb.note(output) | ||
| 208 | except subprocess.CalledProcessError as e: | ||
| 209 | bb.warn("%s for package %s failed with %d:\n%s" % | ||
| 210 | (control_script.name, pkg_name, e.returncode, | ||
| 211 | e.output.decode("utf-8"))) | ||
| 212 | failed_postinsts_abort([pkg_name], self.d.expand("${T}/log.do_${BB_CURRENTTASK}")) | ||
| 213 | |||
| 214 | def update(self): | ||
| 215 | os.environ['APT_CONFIG'] = self.apt_conf_file | ||
| 216 | |||
| 217 | self.deploy_dir_lock() | ||
| 218 | |||
| 219 | cmd = "%s update" % self.apt_get_cmd | ||
| 220 | |||
| 221 | try: | ||
| 222 | subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) | ||
| 223 | except subprocess.CalledProcessError as e: | ||
| 224 | bb.fatal("Unable to update the package index files. Command '%s' " | ||
| 225 | "returned %d:\n%s" % (e.cmd, e.returncode, e.output.decode("utf-8"))) | ||
| 226 | |||
| 227 | self.deploy_dir_unlock() | ||
| 228 | |||
| 229 | def install(self, pkgs, attempt_only=False, hard_depends_only=False): | ||
| 230 | if attempt_only and len(pkgs) == 0: | ||
| 231 | return | ||
| 232 | |||
| 233 | os.environ['APT_CONFIG'] = self.apt_conf_file | ||
| 234 | |||
| 235 | extra_args = "" | ||
| 236 | if hard_depends_only: | ||
| 237 | extra_args = "--no-install-recommends" | ||
| 238 | |||
| 239 | cmd = "%s %s install --allow-downgrades --allow-remove-essential --allow-change-held-packages --allow-unauthenticated --no-remove %s %s" % \ | ||
| 240 | (self.apt_get_cmd, self.apt_args, extra_args, ' '.join(pkgs)) | ||
| 241 | |||
| 242 | try: | ||
| 243 | bb.note("Installing the following packages: %s" % ' '.join(pkgs)) | ||
| 244 | output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) | ||
| 245 | bb.note(output.decode("utf-8")) | ||
| 246 | except subprocess.CalledProcessError as e: | ||
| 247 | e_output = e.output.decode("utf-8") | ||
| 248 | extra_info = "" | ||
| 249 | for e_line in e_output.split('\n'): | ||
| 250 | if 'has no installation candidate' in e_line or 'Unable to locate package' in e_line: | ||
| 251 | match = re.search(r"E: Package '([a-z0-9+\-\._]+)' has no installation candidate", e_line) | ||
| 252 | if match: | ||
| 253 | pkg = match.group(1) | ||
| 254 | else: | ||
| 255 | pkg = re.search(r"E: Unable to locate package ([a-z0-9+\-\._]+)", e_line).group(1) | ||
| 256 | extra_info += self.get_missing_pkg_reason(pkg) | ||
| 257 | (bb.fatal, bb.warn)[attempt_only]("Unable to install packages. " | ||
| 258 | "Command '%s' returned %d:\n%s%s" % | ||
| 259 | (cmd, e.returncode, e_output, extra_info)) | ||
| 260 | |||
| 261 | # rename *.dpkg-new files/dirs | ||
| 262 | for root, dirs, files in os.walk(self.target_rootfs): | ||
| 263 | for dir in dirs: | ||
| 264 | new_dir = re.sub(r"\.dpkg-new", "", dir) | ||
| 265 | if dir != new_dir: | ||
| 266 | bb.utils.rename(os.path.join(root, dir), | ||
| 267 | os.path.join(root, new_dir)) | ||
| 268 | |||
| 269 | for file in files: | ||
| 270 | new_file = re.sub(r"\.dpkg-new", "", file) | ||
| 271 | if file != new_file: | ||
| 272 | bb.utils.rename(os.path.join(root, file), | ||
| 273 | os.path.join(root, new_file)) | ||
| 274 | |||
| 275 | |||
| 276 | def remove(self, pkgs, with_dependencies=True): | ||
| 277 | if not pkgs: | ||
| 278 | return | ||
| 279 | |||
| 280 | os.environ['D'] = self.target_rootfs | ||
| 281 | os.environ['OFFLINE_ROOT'] = self.target_rootfs | ||
| 282 | os.environ['IPKG_OFFLINE_ROOT'] = self.target_rootfs | ||
| 283 | os.environ['OPKG_OFFLINE_ROOT'] = self.target_rootfs | ||
| 284 | os.environ['INTERCEPT_DIR'] = self.intercepts_dir | ||
| 285 | |||
| 286 | if with_dependencies: | ||
| 287 | os.environ['APT_CONFIG'] = self.apt_conf_file | ||
| 288 | cmd = "%s purge %s" % (self.apt_get_cmd, ' '.join(pkgs)) | ||
| 289 | else: | ||
| 290 | cmd = "%s --admindir=%s/var/lib/dpkg --instdir=%s" \ | ||
| 291 | " -P --force-depends %s" % \ | ||
| 292 | (bb.utils.which(os.getenv('PATH'), "dpkg"), | ||
| 293 | self.target_rootfs, self.target_rootfs, ' '.join(pkgs)) | ||
| 294 | |||
| 295 | try: | ||
| 296 | subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) | ||
| 297 | except subprocess.CalledProcessError as e: | ||
| 298 | bb.fatal("Unable to remove packages. Command '%s' " | ||
| 299 | "returned %d:\n%s" % (e.cmd, e.returncode, e.output.decode("utf-8"))) | ||
| 300 | |||
| 301 | def write_index(self): | ||
| 302 | self.deploy_dir_lock() | ||
| 303 | |||
| 304 | result = self.indexer.write_index() | ||
| 305 | |||
| 306 | self.deploy_dir_unlock() | ||
| 307 | |||
| 308 | if result is not None: | ||
| 309 | bb.fatal(result) | ||
| 310 | |||
| 311 | def insert_feeds_uris(self, feed_uris, feed_base_paths, feed_archs): | ||
| 312 | if feed_uris == "": | ||
| 313 | return | ||
| 314 | |||
| 315 | |||
| 316 | sources_conf = os.path.join("%s/etc/apt/sources.list" | ||
| 317 | % self.target_rootfs) | ||
| 318 | if not os.path.exists(os.path.dirname(sources_conf)): | ||
| 319 | return | ||
| 320 | |||
| 321 | arch_list = [] | ||
| 322 | |||
| 323 | if feed_archs is None: | ||
| 324 | for arch in self.all_arch_list: | ||
| 325 | if not os.path.exists(os.path.join(self.deploy_dir, arch)): | ||
| 326 | continue | ||
| 327 | arch_list.append(arch) | ||
| 328 | else: | ||
| 329 | arch_list = feed_archs.split() | ||
| 330 | |||
| 331 | feed_uris = self.construct_uris(feed_uris.split(), feed_base_paths.split()) | ||
| 332 | |||
| 333 | with open(sources_conf, "w+") as sources_file: | ||
| 334 | for uri in feed_uris: | ||
| 335 | if arch_list: | ||
| 336 | for arch in arch_list: | ||
| 337 | bb.note('Adding dpkg channel at (%s)' % uri) | ||
| 338 | sources_file.write("deb [trusted=yes] %s/%s ./\n" % | ||
| 339 | (uri, arch)) | ||
| 340 | else: | ||
| 341 | bb.note('Adding dpkg channel at (%s)' % uri) | ||
| 342 | sources_file.write("deb [trusted=yes] %s ./\n" % uri) | ||
| 343 | |||
| 344 | def _create_configs(self, archs, base_archs): | ||
| 345 | base_archs = re.sub(r"_", r"-", base_archs) | ||
| 346 | |||
| 347 | if os.path.exists(self.apt_conf_dir): | ||
| 348 | bb.utils.remove(self.apt_conf_dir, True) | ||
| 349 | |||
| 350 | bb.utils.mkdirhier(self.apt_conf_dir) | ||
| 351 | bb.utils.mkdirhier(self.apt_conf_dir + "/lists/partial/") | ||
| 352 | bb.utils.mkdirhier(self.apt_conf_dir + "/apt.conf.d/") | ||
| 353 | bb.utils.mkdirhier(self.apt_conf_dir + "/preferences.d/") | ||
| 354 | |||
| 355 | arch_list = [] | ||
| 356 | for arch in self.all_arch_list: | ||
| 357 | if not os.path.exists(os.path.join(self.deploy_dir, arch)): | ||
| 358 | continue | ||
| 359 | arch_list.append(arch) | ||
| 360 | |||
| 361 | with open(os.path.join(self.apt_conf_dir, "preferences"), "w+") as prefs_file: | ||
| 362 | priority = 801 | ||
| 363 | for arch in arch_list: | ||
| 364 | prefs_file.write( | ||
| 365 | "Package: *\n" | ||
| 366 | "Pin: release l=%s\n" | ||
| 367 | "Pin-Priority: %d\n\n" % (arch, priority)) | ||
| 368 | |||
| 369 | priority += 5 | ||
| 370 | |||
| 371 | pkg_exclude = self.d.getVar('PACKAGE_EXCLUDE') or "" | ||
| 372 | for pkg in pkg_exclude.split(): | ||
| 373 | prefs_file.write( | ||
| 374 | "Package: %s\n" | ||
| 375 | "Pin: release *\n" | ||
| 376 | "Pin-Priority: -1\n\n" % pkg) | ||
| 377 | |||
| 378 | arch_list.reverse() | ||
| 379 | |||
| 380 | with open(os.path.join(self.apt_conf_dir, "sources.list"), "w+") as sources_file: | ||
| 381 | for arch in arch_list: | ||
| 382 | sources_file.write("deb [trusted=yes] file:%s/ ./\n" % | ||
| 383 | os.path.join(self.deploy_dir, arch)) | ||
| 384 | |||
| 385 | base_arch_list = base_archs.split() | ||
| 386 | multilib_variants = self.d.getVar("MULTILIB_VARIANTS"); | ||
| 387 | for variant in multilib_variants.split(): | ||
| 388 | localdata = bb.data.createCopy(self.d) | ||
| 389 | variant_tune = localdata.getVar("DEFAULTTUNE:virtclass-multilib-" + variant, False) | ||
| 390 | orig_arch = localdata.getVar("DPKG_ARCH") | ||
| 391 | localdata.setVar("DEFAULTTUNE", variant_tune) | ||
| 392 | variant_arch = localdata.getVar("DPKG_ARCH") | ||
| 393 | if variant_arch not in base_arch_list: | ||
| 394 | base_arch_list.append(variant_arch) | ||
| 395 | |||
| 396 | with open(self.apt_conf_file, "w+") as apt_conf: | ||
| 397 | with open(self.d.expand("${STAGING_ETCDIR_NATIVE}/apt/apt.conf.sample")) as apt_conf_sample: | ||
| 398 | for line in apt_conf_sample.read().split("\n"): | ||
| 399 | match_arch = re.match(r" Architecture \".*\";$", line) | ||
| 400 | architectures = "" | ||
| 401 | if match_arch: | ||
| 402 | for base_arch in base_arch_list: | ||
| 403 | architectures += "\"%s\";" % base_arch | ||
| 404 | apt_conf.write(" Architectures {%s};\n" % architectures); | ||
| 405 | apt_conf.write(" Architecture \"%s\";\n" % base_archs) | ||
| 406 | else: | ||
| 407 | line = re.sub(r"#ROOTFS#", self.target_rootfs, line) | ||
| 408 | line = re.sub(r"#APTCONF#", self.apt_conf_dir, line) | ||
| 409 | apt_conf.write(line + "\n") | ||
| 410 | |||
| 411 | target_dpkg_dir = "%s/var/lib/dpkg" % self.target_rootfs | ||
| 412 | bb.utils.mkdirhier(os.path.join(target_dpkg_dir, "info")) | ||
| 413 | |||
| 414 | bb.utils.mkdirhier(os.path.join(target_dpkg_dir, "updates")) | ||
| 415 | |||
| 416 | if not os.path.exists(os.path.join(target_dpkg_dir, "status")): | ||
| 417 | open(os.path.join(target_dpkg_dir, "status"), "w+").close() | ||
| 418 | if not os.path.exists(os.path.join(target_dpkg_dir, "available")): | ||
| 419 | open(os.path.join(target_dpkg_dir, "available"), "w+").close() | ||
| 420 | |||
| 421 | def remove_packaging_data(self): | ||
| 422 | bb.utils.remove(self.target_rootfs + self.d.getVar('opkglibdir'), True) | ||
| 423 | bb.utils.remove(self.target_rootfs + "/var/lib/dpkg/", True) | ||
| 424 | |||
| 425 | def fix_broken_dependencies(self): | ||
| 426 | os.environ['APT_CONFIG'] = self.apt_conf_file | ||
| 427 | |||
| 428 | cmd = "%s %s --allow-unauthenticated -f install" % (self.apt_get_cmd, self.apt_args) | ||
| 429 | |||
| 430 | try: | ||
| 431 | subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) | ||
| 432 | except subprocess.CalledProcessError as e: | ||
| 433 | bb.fatal("Cannot fix broken dependencies. Command '%s' " | ||
| 434 | "returned %d:\n%s" % (cmd, e.returncode, e.output.decode("utf-8"))) | ||
| 435 | |||
| 436 | def list_installed(self): | ||
| 437 | return PMPkgsList(self.d, self.target_rootfs).list_pkgs() | ||
| 438 | |||
| 439 | def package_info(self, pkg): | ||
| 440 | """ | ||
| 441 | Returns a dictionary with the package info. | ||
| 442 | """ | ||
| 443 | cmd = "%s show %s" % (self.apt_cache_cmd, pkg) | ||
| 444 | pkg_info = self._common_package_info(cmd) | ||
| 445 | |||
| 446 | pkg_arch = pkg_info[pkg]["pkgarch"] | ||
| 447 | pkg_filename = pkg_info[pkg]["filename"] | ||
| 448 | pkg_info[pkg]["filepath"] = \ | ||
| 449 | os.path.join(self.deploy_dir, pkg_arch, pkg_filename) | ||
| 450 | |||
| 451 | return pkg_info | ||
diff --git a/meta/lib/oe/package_manager/deb/manifest.py b/meta/lib/oe/package_manager/deb/manifest.py deleted file mode 100644 index 72983bae98..0000000000 --- a/meta/lib/oe/package_manager/deb/manifest.py +++ /dev/null | |||
| @@ -1,28 +0,0 @@ | |||
| 1 | # | ||
| 2 | # Copyright OpenEmbedded Contributors | ||
| 3 | # | ||
| 4 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 5 | # | ||
| 6 | |||
| 7 | from oe.manifest import Manifest | ||
| 8 | |||
| 9 | class PkgManifest(Manifest): | ||
| 10 | def create_initial(self): | ||
| 11 | with open(self.initial_manifest, "w+") as manifest: | ||
| 12 | manifest.write(self.initial_manifest_file_header) | ||
| 13 | |||
| 14 | for var in self.var_maps[self.manifest_type]: | ||
| 15 | pkg_list = self.d.getVar(var) | ||
| 16 | |||
| 17 | if pkg_list is None: | ||
| 18 | continue | ||
| 19 | |||
| 20 | for pkg in pkg_list.split(): | ||
| 21 | manifest.write("%s,%s\n" % | ||
| 22 | (self.var_maps[self.manifest_type][var], pkg)) | ||
| 23 | |||
| 24 | def create_final(self): | ||
| 25 | pass | ||
| 26 | |||
| 27 | def create_full(self, pm): | ||
| 28 | pass | ||
diff --git a/meta/lib/oe/package_manager/deb/rootfs.py b/meta/lib/oe/package_manager/deb/rootfs.py deleted file mode 100644 index 1e25b64ed9..0000000000 --- a/meta/lib/oe/package_manager/deb/rootfs.py +++ /dev/null | |||
| @@ -1,212 +0,0 @@ | |||
| 1 | # | ||
| 2 | # Copyright OpenEmbedded Contributors | ||
| 3 | # | ||
| 4 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 5 | # | ||
| 6 | |||
| 7 | import re | ||
| 8 | import shutil | ||
| 9 | from oe.rootfs import Rootfs | ||
| 10 | from oe.manifest import Manifest | ||
| 11 | from oe.utils import execute_pre_post_process | ||
| 12 | from oe.package_manager.deb.manifest import PkgManifest | ||
| 13 | from oe.package_manager.deb import DpkgPM | ||
| 14 | |||
| 15 | class DpkgOpkgRootfs(Rootfs): | ||
| 16 | def __init__(self, d, progress_reporter=None, logcatcher=None): | ||
| 17 | super(DpkgOpkgRootfs, self).__init__(d, progress_reporter, logcatcher) | ||
| 18 | |||
| 19 | def _get_pkgs_postinsts(self, status_file): | ||
| 20 | def _get_pkg_depends_list(pkg_depends): | ||
| 21 | pkg_depends_list = [] | ||
| 22 | # filter version requirements like libc (>= 1.1) | ||
| 23 | for dep in pkg_depends.split(', '): | ||
| 24 | m_dep = re.match(r"^(.*) \(.*\)$", dep) | ||
| 25 | if m_dep: | ||
| 26 | dep = m_dep.group(1) | ||
| 27 | pkg_depends_list.append(dep) | ||
| 28 | |||
| 29 | return pkg_depends_list | ||
| 30 | |||
| 31 | pkgs = {} | ||
| 32 | pkg_name = "" | ||
| 33 | pkg_status_match = False | ||
| 34 | pkg_depends = "" | ||
| 35 | |||
| 36 | with open(status_file) as status: | ||
| 37 | data = status.read() | ||
| 38 | status.close() | ||
| 39 | for line in data.split('\n'): | ||
| 40 | m_pkg = re.match(r"^Package: (.*)", line) | ||
| 41 | m_status = re.match(r"^Status:.*unpacked", line) | ||
| 42 | m_depends = re.match(r"^Depends: (.*)", line) | ||
| 43 | |||
| 44 | #Only one of m_pkg, m_status or m_depends is not None at time | ||
| 45 | #If m_pkg is not None, we started a new package | ||
| 46 | if m_pkg is not None: | ||
| 47 | #Get Package name | ||
| 48 | pkg_name = m_pkg.group(1) | ||
| 49 | #Make sure we reset other variables | ||
| 50 | pkg_status_match = False | ||
| 51 | pkg_depends = "" | ||
| 52 | elif m_status is not None: | ||
| 53 | #New status matched | ||
| 54 | pkg_status_match = True | ||
| 55 | elif m_depends is not None: | ||
| 56 | #New depends macthed | ||
| 57 | pkg_depends = m_depends.group(1) | ||
| 58 | else: | ||
| 59 | pass | ||
| 60 | |||
| 61 | #Now check if we can process package depends and postinst | ||
| 62 | if "" != pkg_name and pkg_status_match: | ||
| 63 | pkgs[pkg_name] = _get_pkg_depends_list(pkg_depends) | ||
| 64 | else: | ||
| 65 | #Not enough information | ||
| 66 | pass | ||
| 67 | |||
| 68 | # remove package dependencies not in postinsts | ||
| 69 | pkg_names = list(pkgs.keys()) | ||
| 70 | for pkg_name in pkg_names: | ||
| 71 | deps = pkgs[pkg_name][:] | ||
| 72 | |||
| 73 | for d in deps: | ||
| 74 | if d not in pkg_names: | ||
| 75 | pkgs[pkg_name].remove(d) | ||
| 76 | |||
| 77 | return pkgs | ||
| 78 | |||
| 79 | def _get_delayed_postinsts_common(self, status_file): | ||
| 80 | def _dep_resolve(graph, node, resolved, seen): | ||
| 81 | seen.append(node) | ||
| 82 | |||
| 83 | for edge in graph[node]: | ||
| 84 | if edge not in resolved: | ||
| 85 | if edge in seen: | ||
| 86 | raise RuntimeError("Packages %s and %s have " \ | ||
| 87 | "a circular dependency in postinsts scripts." \ | ||
| 88 | % (node, edge)) | ||
| 89 | _dep_resolve(graph, edge, resolved, seen) | ||
| 90 | |||
| 91 | resolved.append(node) | ||
| 92 | |||
| 93 | pkg_list = [] | ||
| 94 | |||
| 95 | pkgs = None | ||
| 96 | if not self.d.getVar('PACKAGE_INSTALL').strip(): | ||
| 97 | bb.note("Building empty image") | ||
| 98 | else: | ||
| 99 | pkgs = self._get_pkgs_postinsts(status_file) | ||
| 100 | if pkgs: | ||
| 101 | root = "__packagegroup_postinst__" | ||
| 102 | pkgs[root] = list(pkgs.keys()) | ||
| 103 | _dep_resolve(pkgs, root, pkg_list, []) | ||
| 104 | pkg_list.remove(root) | ||
| 105 | |||
| 106 | if len(pkg_list) == 0: | ||
| 107 | return None | ||
| 108 | |||
| 109 | return pkg_list | ||
| 110 | |||
| 111 | def _save_postinsts_common(self, dst_postinst_dir, src_postinst_dir): | ||
| 112 | if bb.utils.contains("IMAGE_FEATURES", "package-management", | ||
| 113 | True, False, self.d): | ||
| 114 | return | ||
| 115 | num = 0 | ||
| 116 | for p in self._get_delayed_postinsts(): | ||
| 117 | bb.utils.mkdirhier(dst_postinst_dir) | ||
| 118 | |||
| 119 | if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")): | ||
| 120 | shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"), | ||
| 121 | os.path.join(dst_postinst_dir, "%03d-%s" % (num, p))) | ||
| 122 | |||
| 123 | num += 1 | ||
| 124 | |||
| 125 | class PkgRootfs(DpkgOpkgRootfs): | ||
| 126 | def __init__(self, d, manifest_dir, progress_reporter=None, logcatcher=None): | ||
| 127 | super(PkgRootfs, self).__init__(d, progress_reporter, logcatcher) | ||
| 128 | self.log_check_regex = '^E:' | ||
| 129 | self.log_check_expected_regexes = \ | ||
| 130 | [ | ||
| 131 | "^E: Unmet dependencies." | ||
| 132 | ] | ||
| 133 | |||
| 134 | bb.utils.remove(self.image_rootfs, True) | ||
| 135 | bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS'), True) | ||
| 136 | self.manifest = PkgManifest(d, manifest_dir) | ||
| 137 | self.pm = DpkgPM(d, d.getVar('IMAGE_ROOTFS'), | ||
| 138 | d.getVar('PACKAGE_ARCHS'), | ||
| 139 | d.getVar('DPKG_ARCH')) | ||
| 140 | |||
| 141 | |||
| 142 | def _create(self): | ||
| 143 | pkgs_to_install = self.manifest.parse_initial_manifest() | ||
| 144 | deb_pre_process_cmds = self.d.getVar('DEB_PREPROCESS_COMMANDS') | ||
| 145 | deb_post_process_cmds = self.d.getVar('DEB_POSTPROCESS_COMMANDS') | ||
| 146 | |||
| 147 | alt_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/alternatives") | ||
| 148 | bb.utils.mkdirhier(alt_dir) | ||
| 149 | |||
| 150 | # update PM index files | ||
| 151 | self.pm.write_index() | ||
| 152 | |||
| 153 | execute_pre_post_process(self.d, deb_pre_process_cmds) | ||
| 154 | |||
| 155 | if self.progress_reporter: | ||
| 156 | self.progress_reporter.next_stage() | ||
| 157 | # Don't support incremental, so skip that | ||
| 158 | self.progress_reporter.next_stage() | ||
| 159 | |||
| 160 | self.pm.update() | ||
| 161 | |||
| 162 | if self.progress_reporter: | ||
| 163 | self.progress_reporter.next_stage() | ||
| 164 | |||
| 165 | for pkg_type in self.install_order: | ||
| 166 | if pkg_type in pkgs_to_install: | ||
| 167 | self.pm.install(pkgs_to_install[pkg_type], | ||
| 168 | [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY]) | ||
| 169 | self.pm.fix_broken_dependencies() | ||
| 170 | |||
| 171 | if self.progress_reporter: | ||
| 172 | # Don't support attemptonly, so skip that | ||
| 173 | self.progress_reporter.next_stage() | ||
| 174 | self.progress_reporter.next_stage() | ||
| 175 | |||
| 176 | self.pm.install_complementary() | ||
| 177 | |||
| 178 | if self.progress_reporter: | ||
| 179 | self.progress_reporter.next_stage() | ||
| 180 | |||
| 181 | self._setup_dbg_rootfs(['/var/lib/dpkg']) | ||
| 182 | |||
| 183 | self.pm.fix_broken_dependencies() | ||
| 184 | |||
| 185 | self.pm.mark_packages("installed") | ||
| 186 | |||
| 187 | self.pm.run_pre_post_installs() | ||
| 188 | |||
| 189 | execute_pre_post_process(self.d, deb_post_process_cmds) | ||
| 190 | |||
| 191 | if self.progress_reporter: | ||
| 192 | self.progress_reporter.next_stage() | ||
| 193 | |||
| 194 | @staticmethod | ||
| 195 | def _depends_list(): | ||
| 196 | return ['DEPLOY_DIR_DEB', 'DEB_SDK_ARCH', 'APTCONF_TARGET', 'APT_ARGS', 'DPKG_ARCH', 'DEB_PREPROCESS_COMMANDS', 'DEB_POSTPROCESS_COMMANDS'] | ||
| 197 | |||
| 198 | def _get_delayed_postinsts(self): | ||
| 199 | status_file = self.image_rootfs + "/var/lib/dpkg/status" | ||
| 200 | return self._get_delayed_postinsts_common(status_file) | ||
| 201 | |||
| 202 | def _save_postinsts(self): | ||
| 203 | dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/deb-postinsts") | ||
| 204 | src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/info") | ||
| 205 | return self._save_postinsts_common(dst_postinst_dir, src_postinst_dir) | ||
| 206 | |||
| 207 | def _log_check(self): | ||
| 208 | self._log_check_warn() | ||
| 209 | self._log_check_error() | ||
| 210 | |||
| 211 | def _cleanup(self): | ||
| 212 | pass | ||
diff --git a/meta/lib/oe/package_manager/deb/sdk.py b/meta/lib/oe/package_manager/deb/sdk.py deleted file mode 100644 index 6f3005053e..0000000000 --- a/meta/lib/oe/package_manager/deb/sdk.py +++ /dev/null | |||
| @@ -1,107 +0,0 @@ | |||
| 1 | # | ||
| 2 | # Copyright OpenEmbedded Contributors | ||
| 3 | # | ||
| 4 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 5 | # | ||
| 6 | |||
| 7 | import glob | ||
| 8 | import shutil | ||
| 9 | from oe.utils import execute_pre_post_process | ||
| 10 | from oe.sdk import Sdk | ||
| 11 | from oe.manifest import Manifest | ||
| 12 | from oe.package_manager.deb import DpkgPM | ||
| 13 | from oe.package_manager.deb.manifest import PkgManifest | ||
| 14 | |||
| 15 | class PkgSdk(Sdk): | ||
| 16 | def __init__(self, d, manifest_dir=None): | ||
| 17 | super(PkgSdk, self).__init__(d, manifest_dir) | ||
| 18 | |||
| 19 | self.target_conf_dir = os.path.join(self.d.getVar("APTCONF_TARGET"), "apt") | ||
| 20 | self.host_conf_dir = os.path.join(self.d.getVar("APTCONF_TARGET"), "apt-sdk") | ||
| 21 | |||
| 22 | |||
| 23 | self.target_manifest = PkgManifest(d, self.manifest_dir, | ||
| 24 | Manifest.MANIFEST_TYPE_SDK_TARGET) | ||
| 25 | self.host_manifest = PkgManifest(d, self.manifest_dir, | ||
| 26 | Manifest.MANIFEST_TYPE_SDK_HOST) | ||
| 27 | |||
| 28 | deb_repo_workdir = "oe-sdk-repo" | ||
| 29 | if "sdk_ext" in d.getVar("BB_RUNTASK"): | ||
| 30 | deb_repo_workdir = "oe-sdk-ext-repo" | ||
| 31 | |||
| 32 | self.target_pm = DpkgPM(d, self.sdk_target_sysroot, | ||
| 33 | self.d.getVar("PACKAGE_ARCHS"), | ||
| 34 | self.d.getVar("DPKG_ARCH"), | ||
| 35 | self.target_conf_dir, | ||
| 36 | deb_repo_workdir=deb_repo_workdir) | ||
| 37 | |||
| 38 | self.host_pm = DpkgPM(d, self.sdk_host_sysroot, | ||
| 39 | self.d.getVar("SDK_PACKAGE_ARCHS"), | ||
| 40 | self.d.getVar("DEB_SDK_ARCH"), | ||
| 41 | self.host_conf_dir, | ||
| 42 | deb_repo_workdir=deb_repo_workdir) | ||
| 43 | |||
| 44 | def _copy_apt_dir_to(self, dst_dir): | ||
| 45 | staging_etcdir_native = self.d.getVar("STAGING_ETCDIR_NATIVE") | ||
| 46 | |||
| 47 | self.remove(dst_dir, True) | ||
| 48 | |||
| 49 | shutil.copytree(os.path.join(staging_etcdir_native, "apt"), dst_dir) | ||
| 50 | |||
| 51 | def _populate_sysroot(self, pm, manifest): | ||
| 52 | pkgs_to_install = manifest.parse_initial_manifest() | ||
| 53 | |||
| 54 | pm.write_index() | ||
| 55 | pm.update() | ||
| 56 | |||
| 57 | for pkg_type in self.install_order: | ||
| 58 | if pkg_type in pkgs_to_install: | ||
| 59 | pm.install(pkgs_to_install[pkg_type], | ||
| 60 | [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY]) | ||
| 61 | |||
| 62 | def _populate(self): | ||
| 63 | execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_PRE_TARGET_COMMAND")) | ||
| 64 | |||
| 65 | bb.note("Installing TARGET packages") | ||
| 66 | self._populate_sysroot(self.target_pm, self.target_manifest) | ||
| 67 | |||
| 68 | self.target_pm.install_complementary(self.d.getVar('SDKIMAGE_INSTALL_COMPLEMENTARY')) | ||
| 69 | |||
| 70 | self.target_pm.run_pre_post_installs() | ||
| 71 | |||
| 72 | env_bkp = os.environ.copy() | ||
| 73 | os.environ['PATH'] = self.d.expand("${COREBASE}/scripts/nativesdk-intercept") + \ | ||
| 74 | os.pathsep + os.environ["PATH"] | ||
| 75 | |||
| 76 | self.target_pm.run_intercepts(populate_sdk='target') | ||
| 77 | os.environ.update(env_bkp) | ||
| 78 | |||
| 79 | execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_TARGET_COMMAND")) | ||
| 80 | |||
| 81 | self._copy_apt_dir_to(os.path.join(self.sdk_target_sysroot, "etc", "apt")) | ||
| 82 | |||
| 83 | if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d): | ||
| 84 | self.target_pm.remove_packaging_data() | ||
| 85 | |||
| 86 | bb.note("Installing NATIVESDK packages") | ||
| 87 | self._populate_sysroot(self.host_pm, self.host_manifest) | ||
| 88 | self.install_locales(self.host_pm) | ||
| 89 | |||
| 90 | self.host_pm.run_pre_post_installs() | ||
| 91 | |||
| 92 | self.host_pm.run_intercepts(populate_sdk='host') | ||
| 93 | |||
| 94 | execute_pre_post_process(self.d, self.d.getVar("POPULATE_SDK_POST_HOST_COMMAND")) | ||
| 95 | |||
| 96 | self._copy_apt_dir_to(os.path.join(self.sdk_output, self.sdk_native_path, | ||
| 97 | "etc", "apt")) | ||
| 98 | |||
| 99 | if not bb.utils.contains("SDKIMAGE_FEATURES", "package-management", True, False, self.d): | ||
| 100 | self.host_pm.remove_packaging_data() | ||
| 101 | |||
| 102 | native_dpkg_state_dir = os.path.join(self.sdk_output, self.sdk_native_path, | ||
| 103 | "var", "lib", "dpkg") | ||
| 104 | self.mkdirhier(native_dpkg_state_dir) | ||
| 105 | for f in glob.glob(os.path.join(self.sdk_output, "var", "lib", "dpkg", "*")): | ||
| 106 | self.movefile(f, native_dpkg_state_dir) | ||
| 107 | self.remove(os.path.join(self.sdk_output, "var"), True) | ||
