1635e0e46SAndrew Geissler# 292b42cb3SPatrick Williams# Copyright OpenEmbedded Contributors 392b42cb3SPatrick Williams# 4635e0e46SAndrew Geissler# SPDX-License-Identifier: GPL-2.0-only 5635e0e46SAndrew Geissler# 6635e0e46SAndrew Geissler 7635e0e46SAndrew Geisslerimport re 8635e0e46SAndrew Geisslerimport shutil 9635e0e46SAndrew Geisslerimport subprocess 10635e0e46SAndrew Geisslerfrom oe.package_manager import * 11635e0e46SAndrew Geissler 12635e0e46SAndrew Geisslerclass OpkgIndexer(Indexer): 13635e0e46SAndrew Geissler def write_index(self): 14635e0e46SAndrew Geissler arch_vars = ["ALL_MULTILIB_PACKAGE_ARCHS", 15635e0e46SAndrew Geissler "SDK_PACKAGE_ARCHS", 16635e0e46SAndrew Geissler ] 17635e0e46SAndrew Geissler 18635e0e46SAndrew Geissler opkg_index_cmd = bb.utils.which(os.getenv('PATH'), "opkg-make-index") 19*73bd93f1SPatrick Williams opkg_index_cmd_extra_params = self.d.getVar('OPKG_MAKE_INDEX_EXTRA_PARAMS') or "" 20635e0e46SAndrew Geissler if self.d.getVar('PACKAGE_FEED_SIGN') == '1': 21635e0e46SAndrew Geissler signer = get_signer(self.d, self.d.getVar('PACKAGE_FEED_GPG_BACKEND')) 22635e0e46SAndrew Geissler else: 23635e0e46SAndrew Geissler signer = None 24635e0e46SAndrew Geissler 25635e0e46SAndrew Geissler if not os.path.exists(os.path.join(self.deploy_dir, "Packages")): 26635e0e46SAndrew Geissler open(os.path.join(self.deploy_dir, "Packages"), "w").close() 27635e0e46SAndrew Geissler 28635e0e46SAndrew Geissler index_cmds = set() 29635e0e46SAndrew Geissler index_sign_files = set() 30635e0e46SAndrew Geissler for arch_var in arch_vars: 31635e0e46SAndrew Geissler archs = self.d.getVar(arch_var) 32635e0e46SAndrew Geissler if archs is None: 33635e0e46SAndrew Geissler continue 34635e0e46SAndrew Geissler 35635e0e46SAndrew Geissler for arch in archs.split(): 36635e0e46SAndrew Geissler pkgs_dir = os.path.join(self.deploy_dir, arch) 37635e0e46SAndrew Geissler pkgs_file = os.path.join(pkgs_dir, "Packages") 38635e0e46SAndrew Geissler 39635e0e46SAndrew Geissler if not os.path.isdir(pkgs_dir): 40635e0e46SAndrew Geissler continue 41635e0e46SAndrew Geissler 42635e0e46SAndrew Geissler if not os.path.exists(pkgs_file): 43635e0e46SAndrew Geissler open(pkgs_file, "w").close() 44635e0e46SAndrew Geissler 45*73bd93f1SPatrick Williams index_cmds.add('%s --checksum md5 --checksum sha256 -r %s -p %s -m %s %s' % 46*73bd93f1SPatrick Williams (opkg_index_cmd, pkgs_file, pkgs_file, pkgs_dir, opkg_index_cmd_extra_params)) 47635e0e46SAndrew Geissler 48635e0e46SAndrew Geissler index_sign_files.add(pkgs_file) 49635e0e46SAndrew Geissler 50635e0e46SAndrew Geissler if len(index_cmds) == 0: 51635e0e46SAndrew Geissler bb.note("There are no packages in %s!" % self.deploy_dir) 52635e0e46SAndrew Geissler return 53635e0e46SAndrew Geissler 54635e0e46SAndrew Geissler oe.utils.multiprocess_launch(create_index, index_cmds, self.d) 55635e0e46SAndrew Geissler 56635e0e46SAndrew Geissler if signer: 57635e0e46SAndrew Geissler feed_sig_type = self.d.getVar('PACKAGE_FEED_GPG_SIGNATURE_TYPE') 58635e0e46SAndrew Geissler is_ascii_sig = (feed_sig_type.upper() != "BIN") 59635e0e46SAndrew Geissler for f in index_sign_files: 60635e0e46SAndrew Geissler signer.detach_sign(f, 61635e0e46SAndrew Geissler self.d.getVar('PACKAGE_FEED_GPG_NAME'), 62635e0e46SAndrew Geissler self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE'), 63635e0e46SAndrew Geissler armor=is_ascii_sig) 64635e0e46SAndrew Geissler 656ce62a20SAndrew Geisslerclass PMPkgsList(PkgsList): 666ce62a20SAndrew Geissler def __init__(self, d, rootfs_dir): 676ce62a20SAndrew Geissler super(PMPkgsList, self).__init__(d, rootfs_dir) 686ce62a20SAndrew Geissler config_file = d.getVar("IPKGCONF_TARGET") 69635e0e46SAndrew Geissler 70635e0e46SAndrew Geissler self.opkg_cmd = bb.utils.which(os.getenv('PATH'), "opkg") 71635e0e46SAndrew Geissler self.opkg_args = "-f %s -o %s " % (config_file, rootfs_dir) 72635e0e46SAndrew Geissler self.opkg_args += self.d.getVar("OPKG_ARGS") 73635e0e46SAndrew Geissler 74635e0e46SAndrew Geissler def list_pkgs(self, format=None): 75635e0e46SAndrew Geissler cmd = "%s %s status" % (self.opkg_cmd, self.opkg_args) 76635e0e46SAndrew Geissler 77635e0e46SAndrew Geissler # opkg returns success even when it printed some 78635e0e46SAndrew Geissler # "Collected errors:" report to stderr. Mixing stderr into 79635e0e46SAndrew Geissler # stdout then leads to random failures later on when 80635e0e46SAndrew Geissler # parsing the output. To avoid this we need to collect both 81635e0e46SAndrew Geissler # output streams separately and check for empty stderr. 82635e0e46SAndrew Geissler p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 83635e0e46SAndrew Geissler cmd_output, cmd_stderr = p.communicate() 84635e0e46SAndrew Geissler cmd_output = cmd_output.decode("utf-8") 85635e0e46SAndrew Geissler cmd_stderr = cmd_stderr.decode("utf-8") 86635e0e46SAndrew Geissler if p.returncode or cmd_stderr: 87635e0e46SAndrew Geissler bb.fatal("Cannot get the installed packages list. Command '%s' " 88635e0e46SAndrew Geissler "returned %d and stderr:\n%s" % (cmd, p.returncode, cmd_stderr)) 89635e0e46SAndrew Geissler 90635e0e46SAndrew Geissler return opkg_query(cmd_output) 91635e0e46SAndrew Geissler 92635e0e46SAndrew Geissler 93635e0e46SAndrew Geissler 94635e0e46SAndrew Geisslerclass OpkgDpkgPM(PackageManager): 95635e0e46SAndrew Geissler def __init__(self, d, target_rootfs): 96635e0e46SAndrew Geissler """ 97635e0e46SAndrew Geissler This is an abstract class. Do not instantiate this directly. 98635e0e46SAndrew Geissler """ 99635e0e46SAndrew Geissler super(OpkgDpkgPM, self).__init__(d, target_rootfs) 100635e0e46SAndrew Geissler 101635e0e46SAndrew Geissler def package_info(self, pkg, cmd): 102635e0e46SAndrew Geissler """ 103635e0e46SAndrew Geissler Returns a dictionary with the package info. 104635e0e46SAndrew Geissler 105635e0e46SAndrew Geissler This method extracts the common parts for Opkg and Dpkg 106635e0e46SAndrew Geissler """ 107635e0e46SAndrew Geissler 108db4c27eeSPatrick Williams proc = subprocess.run(cmd, capture_output=True, encoding="utf-8", shell=True) 109db4c27eeSPatrick Williams if proc.returncode: 110635e0e46SAndrew Geissler bb.fatal("Unable to list available packages. Command '%s' " 111db4c27eeSPatrick Williams "returned %d:\n%s" % (cmd, proc.returncode, proc.stderr)) 112db4c27eeSPatrick Williams elif proc.stderr: 113db4c27eeSPatrick Williams bb.note("Command '%s' returned stderr: %s" % (cmd, proc.stderr)) 114db4c27eeSPatrick Williams 115db4c27eeSPatrick Williams return opkg_query(proc.stdout) 116635e0e46SAndrew Geissler 117635e0e46SAndrew Geissler def extract(self, pkg, pkg_info): 118635e0e46SAndrew Geissler """ 119635e0e46SAndrew Geissler Returns the path to a tmpdir where resides the contents of a package. 120635e0e46SAndrew Geissler 121635e0e46SAndrew Geissler Deleting the tmpdir is responsability of the caller. 122635e0e46SAndrew Geissler 123635e0e46SAndrew Geissler This method extracts the common parts for Opkg and Dpkg 124635e0e46SAndrew Geissler """ 125635e0e46SAndrew Geissler 126635e0e46SAndrew Geissler ar_cmd = bb.utils.which(os.getenv("PATH"), "ar") 127635e0e46SAndrew Geissler tar_cmd = bb.utils.which(os.getenv("PATH"), "tar") 128635e0e46SAndrew Geissler pkg_path = pkg_info[pkg]["filepath"] 129635e0e46SAndrew Geissler 130635e0e46SAndrew Geissler if not os.path.isfile(pkg_path): 131635e0e46SAndrew Geissler bb.fatal("Unable to extract package for '%s'." 132635e0e46SAndrew Geissler "File %s doesn't exists" % (pkg, pkg_path)) 133635e0e46SAndrew Geissler 134635e0e46SAndrew Geissler tmp_dir = tempfile.mkdtemp() 135635e0e46SAndrew Geissler current_dir = os.getcwd() 136635e0e46SAndrew Geissler os.chdir(tmp_dir) 137169d7bccSPatrick Williams data_tar = 'data.tar.zst' 138635e0e46SAndrew Geissler 139635e0e46SAndrew Geissler try: 140635e0e46SAndrew Geissler cmd = [ar_cmd, 'x', pkg_path] 141635e0e46SAndrew Geissler output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) 142635e0e46SAndrew Geissler cmd = [tar_cmd, 'xf', data_tar] 143635e0e46SAndrew Geissler output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) 144635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 145635e0e46SAndrew Geissler bb.utils.remove(tmp_dir, recurse=True) 146635e0e46SAndrew Geissler bb.fatal("Unable to extract %s package. Command '%s' " 147635e0e46SAndrew Geissler "returned %d:\n%s" % (pkg_path, ' '.join(cmd), e.returncode, e.output.decode("utf-8"))) 148635e0e46SAndrew Geissler except OSError as e: 149635e0e46SAndrew Geissler bb.utils.remove(tmp_dir, recurse=True) 150635e0e46SAndrew Geissler bb.fatal("Unable to extract %s package. Command '%s' " 151635e0e46SAndrew Geissler "returned %d:\n%s at %s" % (pkg_path, ' '.join(cmd), e.errno, e.strerror, e.filename)) 152635e0e46SAndrew Geissler 153635e0e46SAndrew Geissler bb.note("Extracted %s to %s" % (pkg_path, tmp_dir)) 154635e0e46SAndrew Geissler bb.utils.remove(os.path.join(tmp_dir, "debian-binary")) 155635e0e46SAndrew Geissler bb.utils.remove(os.path.join(tmp_dir, "control.tar.gz")) 156635e0e46SAndrew Geissler os.chdir(current_dir) 157635e0e46SAndrew Geissler 158635e0e46SAndrew Geissler return tmp_dir 159635e0e46SAndrew Geissler 160635e0e46SAndrew Geissler def _handle_intercept_failure(self, registered_pkgs): 161635e0e46SAndrew Geissler self.mark_packages("unpacked", registered_pkgs.split()) 162635e0e46SAndrew Geissler 163635e0e46SAndrew Geisslerclass OpkgPM(OpkgDpkgPM): 164635e0e46SAndrew Geissler def __init__(self, d, target_rootfs, config_file, archs, task_name='target', ipk_repo_workdir="oe-rootfs-repo", filterbydependencies=True, prepare_index=True): 165635e0e46SAndrew Geissler super(OpkgPM, self).__init__(d, target_rootfs) 166635e0e46SAndrew Geissler 167635e0e46SAndrew Geissler self.config_file = config_file 168635e0e46SAndrew Geissler self.pkg_archs = archs 169635e0e46SAndrew Geissler self.task_name = task_name 170635e0e46SAndrew Geissler 171635e0e46SAndrew Geissler self.deploy_dir = oe.path.join(self.d.getVar('WORKDIR'), ipk_repo_workdir) 172635e0e46SAndrew Geissler self.deploy_lock_file = os.path.join(self.deploy_dir, "deploy.lock") 173635e0e46SAndrew Geissler self.opkg_cmd = bb.utils.which(os.getenv('PATH'), "opkg") 174635e0e46SAndrew Geissler self.opkg_args = "--volatile-cache -f %s -t %s -o %s " % (self.config_file, self.d.expand('${T}/ipktemp/') ,target_rootfs) 175635e0e46SAndrew Geissler self.opkg_args += self.d.getVar("OPKG_ARGS") 176635e0e46SAndrew Geissler 177635e0e46SAndrew Geissler if prepare_index: 178635e0e46SAndrew Geissler create_packages_dir(self.d, self.deploy_dir, d.getVar("DEPLOY_DIR_IPK"), "package_write_ipk", filterbydependencies) 179635e0e46SAndrew Geissler 18009209eecSAndrew Geissler self.opkg_dir = oe.path.join(target_rootfs, self.d.getVar('OPKGLIBDIR'), "opkg") 181635e0e46SAndrew Geissler bb.utils.mkdirhier(self.opkg_dir) 182635e0e46SAndrew Geissler 183635e0e46SAndrew Geissler self.saved_opkg_dir = self.d.expand('${T}/saved/%s' % self.task_name) 184635e0e46SAndrew Geissler if not os.path.exists(self.d.expand('${T}/saved')): 185635e0e46SAndrew Geissler bb.utils.mkdirhier(self.d.expand('${T}/saved')) 186635e0e46SAndrew Geissler 187635e0e46SAndrew Geissler self.from_feeds = (self.d.getVar('BUILD_IMAGES_FROM_FEEDS') or "") == "1" 188635e0e46SAndrew Geissler if self.from_feeds: 189635e0e46SAndrew Geissler self._create_custom_config() 190635e0e46SAndrew Geissler else: 191635e0e46SAndrew Geissler self._create_config() 192635e0e46SAndrew Geissler 193635e0e46SAndrew Geissler self.indexer = OpkgIndexer(self.d, self.deploy_dir) 194635e0e46SAndrew Geissler 195635e0e46SAndrew Geissler def mark_packages(self, status_tag, packages=None): 196635e0e46SAndrew Geissler """ 197635e0e46SAndrew Geissler This function will change a package's status in /var/lib/opkg/status file. 198635e0e46SAndrew Geissler If 'packages' is None then the new_status will be applied to all 199635e0e46SAndrew Geissler packages 200635e0e46SAndrew Geissler """ 201635e0e46SAndrew Geissler status_file = os.path.join(self.opkg_dir, "status") 202635e0e46SAndrew Geissler 203635e0e46SAndrew Geissler with open(status_file, "r") as sf: 204635e0e46SAndrew Geissler with open(status_file + ".tmp", "w+") as tmp_sf: 205635e0e46SAndrew Geissler if packages is None: 206635e0e46SAndrew Geissler tmp_sf.write(re.sub(r"Package: (.*?)\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)", 207635e0e46SAndrew Geissler r"Package: \1\n\2Status: \3%s" % status_tag, 208635e0e46SAndrew Geissler sf.read())) 209635e0e46SAndrew Geissler else: 210635e0e46SAndrew Geissler if type(packages).__name__ != "list": 211635e0e46SAndrew Geissler raise TypeError("'packages' should be a list object") 212635e0e46SAndrew Geissler 213635e0e46SAndrew Geissler status = sf.read() 214635e0e46SAndrew Geissler for pkg in packages: 215635e0e46SAndrew Geissler status = re.sub(r"Package: %s\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)" % pkg, 216635e0e46SAndrew Geissler r"Package: %s\n\1Status: \2%s" % (pkg, status_tag), 217635e0e46SAndrew Geissler status) 218635e0e46SAndrew Geissler 219635e0e46SAndrew Geissler tmp_sf.write(status) 220635e0e46SAndrew Geissler 221c926e17cSAndrew Geissler bb.utils.rename(status_file + ".tmp", status_file) 222635e0e46SAndrew Geissler 223635e0e46SAndrew Geissler def _create_custom_config(self): 224635e0e46SAndrew Geissler bb.note("Building from feeds activated!") 225635e0e46SAndrew Geissler 226635e0e46SAndrew Geissler with open(self.config_file, "w+") as config_file: 227635e0e46SAndrew Geissler priority = 1 228635e0e46SAndrew Geissler for arch in self.pkg_archs.split(): 229635e0e46SAndrew Geissler config_file.write("arch %s %d\n" % (arch, priority)) 230635e0e46SAndrew Geissler priority += 5 231635e0e46SAndrew Geissler 232635e0e46SAndrew Geissler for line in (self.d.getVar('IPK_FEED_URIS') or "").split(): 233635e0e46SAndrew Geissler feed_match = re.match(r"^[ \t]*(.*)##([^ \t]*)[ \t]*$", line) 234635e0e46SAndrew Geissler 235635e0e46SAndrew Geissler if feed_match is not None: 236635e0e46SAndrew Geissler feed_name = feed_match.group(1) 237635e0e46SAndrew Geissler feed_uri = feed_match.group(2) 238635e0e46SAndrew Geissler 239635e0e46SAndrew Geissler bb.note("Add %s feed with URL %s" % (feed_name, feed_uri)) 240635e0e46SAndrew Geissler 241635e0e46SAndrew Geissler config_file.write("src/gz %s %s\n" % (feed_name, feed_uri)) 242635e0e46SAndrew Geissler 243635e0e46SAndrew Geissler """ 244635e0e46SAndrew Geissler Allow to use package deploy directory contents as quick devel-testing 245635e0e46SAndrew Geissler feed. This creates individual feed configs for each arch subdir of those 246635e0e46SAndrew Geissler specified as compatible for the current machine. 247635e0e46SAndrew Geissler NOTE: Development-helper feature, NOT a full-fledged feed. 248635e0e46SAndrew Geissler """ 249635e0e46SAndrew Geissler if (self.d.getVar('FEED_DEPLOYDIR_BASE_URI') or "") != "": 250635e0e46SAndrew Geissler for arch in self.pkg_archs.split(): 251028142bdSAndrew Geissler cfg_file_name = oe.path.join(self.target_rootfs, 252635e0e46SAndrew Geissler self.d.getVar("sysconfdir"), 253635e0e46SAndrew Geissler "opkg", 254635e0e46SAndrew Geissler "local-%s-feed.conf" % arch) 255635e0e46SAndrew Geissler 256635e0e46SAndrew Geissler with open(cfg_file_name, "w+") as cfg_file: 257635e0e46SAndrew Geissler cfg_file.write("src/gz local-%s %s/%s" % 258635e0e46SAndrew Geissler (arch, 259635e0e46SAndrew Geissler self.d.getVar('FEED_DEPLOYDIR_BASE_URI'), 260635e0e46SAndrew Geissler arch)) 261635e0e46SAndrew Geissler 262635e0e46SAndrew Geissler if self.d.getVar('OPKGLIBDIR') != '/var/lib': 263635e0e46SAndrew Geissler # There is no command line option for this anymore, we need to add 264635e0e46SAndrew Geissler # info_dir and status_file to config file, if OPKGLIBDIR doesn't have 265635e0e46SAndrew Geissler # the default value of "/var/lib" as defined in opkg: 266635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_LISTS_DIR VARDIR "/lib/opkg/lists" 267635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_INFO_DIR VARDIR "/lib/opkg/info" 268635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_STATUS_FILE VARDIR "/lib/opkg/status" 269635e0e46SAndrew Geissler cfg_file.write("option info_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'info')) 270635e0e46SAndrew Geissler cfg_file.write("option lists_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'lists')) 271635e0e46SAndrew Geissler cfg_file.write("option status_file %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'status')) 272635e0e46SAndrew Geissler 273635e0e46SAndrew Geissler 274635e0e46SAndrew Geissler def _create_config(self): 275635e0e46SAndrew Geissler with open(self.config_file, "w+") as config_file: 276635e0e46SAndrew Geissler priority = 1 277635e0e46SAndrew Geissler for arch in self.pkg_archs.split(): 278635e0e46SAndrew Geissler config_file.write("arch %s %d\n" % (arch, priority)) 279635e0e46SAndrew Geissler priority += 5 280635e0e46SAndrew Geissler 281635e0e46SAndrew Geissler config_file.write("src oe file:%s\n" % self.deploy_dir) 282635e0e46SAndrew Geissler 283635e0e46SAndrew Geissler for arch in self.pkg_archs.split(): 284635e0e46SAndrew Geissler pkgs_dir = os.path.join(self.deploy_dir, arch) 285635e0e46SAndrew Geissler if os.path.isdir(pkgs_dir): 286635e0e46SAndrew Geissler config_file.write("src oe-%s file:%s\n" % 287635e0e46SAndrew Geissler (arch, pkgs_dir)) 288635e0e46SAndrew Geissler 289635e0e46SAndrew Geissler if self.d.getVar('OPKGLIBDIR') != '/var/lib': 290635e0e46SAndrew Geissler # There is no command line option for this anymore, we need to add 291635e0e46SAndrew Geissler # info_dir and status_file to config file, if OPKGLIBDIR doesn't have 292635e0e46SAndrew Geissler # the default value of "/var/lib" as defined in opkg: 293635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_LISTS_DIR VARDIR "/lib/opkg/lists" 294635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_INFO_DIR VARDIR "/lib/opkg/info" 295635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_STATUS_FILE VARDIR "/lib/opkg/status" 296635e0e46SAndrew Geissler config_file.write("option info_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'info')) 297635e0e46SAndrew Geissler config_file.write("option lists_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'lists')) 298635e0e46SAndrew Geissler config_file.write("option status_file %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'status')) 299635e0e46SAndrew Geissler 300635e0e46SAndrew Geissler def insert_feeds_uris(self, feed_uris, feed_base_paths, feed_archs): 301635e0e46SAndrew Geissler if feed_uris == "": 302635e0e46SAndrew Geissler return 303635e0e46SAndrew Geissler 304635e0e46SAndrew Geissler rootfs_config = os.path.join('%s/etc/opkg/base-feeds.conf' 305635e0e46SAndrew Geissler % self.target_rootfs) 306635e0e46SAndrew Geissler 307635e0e46SAndrew Geissler os.makedirs('%s/etc/opkg' % self.target_rootfs, exist_ok=True) 308635e0e46SAndrew Geissler 309635e0e46SAndrew Geissler feed_uris = self.construct_uris(feed_uris.split(), feed_base_paths.split()) 310635e0e46SAndrew Geissler archs = self.pkg_archs.split() if feed_archs is None else feed_archs.split() 311635e0e46SAndrew Geissler 312635e0e46SAndrew Geissler with open(rootfs_config, "w+") as config_file: 313635e0e46SAndrew Geissler uri_iterator = 0 314635e0e46SAndrew Geissler for uri in feed_uris: 315635e0e46SAndrew Geissler if archs: 316635e0e46SAndrew Geissler for arch in archs: 317635e0e46SAndrew Geissler if (feed_archs is None) and (not os.path.exists(oe.path.join(self.deploy_dir, arch))): 318635e0e46SAndrew Geissler continue 319635e0e46SAndrew Geissler bb.note('Adding opkg feed url-%s-%d (%s)' % 320635e0e46SAndrew Geissler (arch, uri_iterator, uri)) 321635e0e46SAndrew Geissler config_file.write("src/gz uri-%s-%d %s/%s\n" % 322635e0e46SAndrew Geissler (arch, uri_iterator, uri, arch)) 323635e0e46SAndrew Geissler else: 324635e0e46SAndrew Geissler bb.note('Adding opkg feed url-%d (%s)' % 325635e0e46SAndrew Geissler (uri_iterator, uri)) 326635e0e46SAndrew Geissler config_file.write("src/gz uri-%d %s\n" % 327635e0e46SAndrew Geissler (uri_iterator, uri)) 328635e0e46SAndrew Geissler 329635e0e46SAndrew Geissler uri_iterator += 1 330635e0e46SAndrew Geissler 331635e0e46SAndrew Geissler def update(self): 332635e0e46SAndrew Geissler self.deploy_dir_lock() 333635e0e46SAndrew Geissler 334635e0e46SAndrew Geissler cmd = "%s %s update" % (self.opkg_cmd, self.opkg_args) 335635e0e46SAndrew Geissler 336635e0e46SAndrew Geissler try: 337635e0e46SAndrew Geissler subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) 338635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 339635e0e46SAndrew Geissler self.deploy_dir_unlock() 340635e0e46SAndrew Geissler bb.fatal("Unable to update the package index files. Command '%s' " 341635e0e46SAndrew Geissler "returned %d:\n%s" % (cmd, e.returncode, e.output.decode("utf-8"))) 342635e0e46SAndrew Geissler 343635e0e46SAndrew Geissler self.deploy_dir_unlock() 344635e0e46SAndrew Geissler 345615f2f11SAndrew Geissler def install(self, pkgs, attempt_only=False, hard_depends_only=False): 346635e0e46SAndrew Geissler if not pkgs: 347635e0e46SAndrew Geissler return 348635e0e46SAndrew Geissler 349635e0e46SAndrew Geissler cmd = "%s %s" % (self.opkg_cmd, self.opkg_args) 350635e0e46SAndrew Geissler for exclude in (self.d.getVar("PACKAGE_EXCLUDE") or "").split(): 351635e0e46SAndrew Geissler cmd += " --add-exclude %s" % exclude 352635e0e46SAndrew Geissler for bad_recommendation in (self.d.getVar("BAD_RECOMMENDATIONS") or "").split(): 353635e0e46SAndrew Geissler cmd += " --add-ignore-recommends %s" % bad_recommendation 354615f2f11SAndrew Geissler if hard_depends_only: 355615f2f11SAndrew Geissler cmd += " --no-install-recommends" 356635e0e46SAndrew Geissler cmd += " install " 357635e0e46SAndrew Geissler cmd += " ".join(pkgs) 358635e0e46SAndrew Geissler 359635e0e46SAndrew Geissler os.environ['D'] = self.target_rootfs 360635e0e46SAndrew Geissler os.environ['OFFLINE_ROOT'] = self.target_rootfs 361635e0e46SAndrew Geissler os.environ['IPKG_OFFLINE_ROOT'] = self.target_rootfs 362635e0e46SAndrew Geissler os.environ['OPKG_OFFLINE_ROOT'] = self.target_rootfs 363635e0e46SAndrew Geissler os.environ['INTERCEPT_DIR'] = self.intercepts_dir 364635e0e46SAndrew Geissler os.environ['NATIVE_ROOT'] = self.d.getVar('STAGING_DIR_NATIVE') 365635e0e46SAndrew Geissler 366635e0e46SAndrew Geissler try: 367635e0e46SAndrew Geissler bb.note("Installing the following packages: %s" % ' '.join(pkgs)) 368635e0e46SAndrew Geissler bb.note(cmd) 369635e0e46SAndrew Geissler output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT).decode("utf-8") 370635e0e46SAndrew Geissler bb.note(output) 371635e0e46SAndrew Geissler failed_pkgs = [] 372635e0e46SAndrew Geissler for line in output.split('\n'): 373635e0e46SAndrew Geissler if line.endswith("configuration required on target."): 374635e0e46SAndrew Geissler bb.warn(line) 375635e0e46SAndrew Geissler failed_pkgs.append(line.split(".")[0]) 376635e0e46SAndrew Geissler if failed_pkgs: 377635e0e46SAndrew Geissler failed_postinsts_abort(failed_pkgs, self.d.expand("${T}/log.do_${BB_CURRENTTASK}")) 378635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 379635e0e46SAndrew Geissler (bb.fatal, bb.warn)[attempt_only]("Unable to install packages. " 380635e0e46SAndrew Geissler "Command '%s' returned %d:\n%s" % 381635e0e46SAndrew Geissler (cmd, e.returncode, e.output.decode("utf-8"))) 382635e0e46SAndrew Geissler 383635e0e46SAndrew Geissler def remove(self, pkgs, with_dependencies=True): 384635e0e46SAndrew Geissler if not pkgs: 385635e0e46SAndrew Geissler return 386635e0e46SAndrew Geissler 387635e0e46SAndrew Geissler if with_dependencies: 388635e0e46SAndrew Geissler cmd = "%s %s --force-remove --force-removal-of-dependent-packages remove %s" % \ 389635e0e46SAndrew Geissler (self.opkg_cmd, self.opkg_args, ' '.join(pkgs)) 390635e0e46SAndrew Geissler else: 391635e0e46SAndrew Geissler cmd = "%s %s --force-depends remove %s" % \ 392635e0e46SAndrew Geissler (self.opkg_cmd, self.opkg_args, ' '.join(pkgs)) 393635e0e46SAndrew Geissler 394635e0e46SAndrew Geissler try: 395635e0e46SAndrew Geissler bb.note(cmd) 396635e0e46SAndrew Geissler output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT).decode("utf-8") 397635e0e46SAndrew Geissler bb.note(output) 398635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 399635e0e46SAndrew Geissler bb.fatal("Unable to remove packages. Command '%s' " 400635e0e46SAndrew Geissler "returned %d:\n%s" % (e.cmd, e.returncode, e.output.decode("utf-8"))) 401635e0e46SAndrew Geissler 402635e0e46SAndrew Geissler def write_index(self): 403635e0e46SAndrew Geissler self.deploy_dir_lock() 404635e0e46SAndrew Geissler 405635e0e46SAndrew Geissler result = self.indexer.write_index() 406635e0e46SAndrew Geissler 407635e0e46SAndrew Geissler self.deploy_dir_unlock() 408635e0e46SAndrew Geissler 409635e0e46SAndrew Geissler if result is not None: 410635e0e46SAndrew Geissler bb.fatal(result) 411635e0e46SAndrew Geissler 412635e0e46SAndrew Geissler def remove_packaging_data(self): 41309209eecSAndrew Geissler cachedir = oe.path.join(self.target_rootfs, self.d.getVar("localstatedir"), "cache", "opkg") 414635e0e46SAndrew Geissler bb.utils.remove(self.opkg_dir, True) 41509209eecSAndrew Geissler bb.utils.remove(cachedir, True) 416635e0e46SAndrew Geissler 417635e0e46SAndrew Geissler def remove_lists(self): 418635e0e46SAndrew Geissler if not self.from_feeds: 419635e0e46SAndrew Geissler bb.utils.remove(os.path.join(self.opkg_dir, "lists"), True) 420635e0e46SAndrew Geissler 421635e0e46SAndrew Geissler def list_installed(self): 4226ce62a20SAndrew Geissler return PMPkgsList(self.d, self.target_rootfs).list_pkgs() 423635e0e46SAndrew Geissler 424635e0e46SAndrew Geissler def dummy_install(self, pkgs): 425635e0e46SAndrew Geissler """ 426635e0e46SAndrew Geissler The following function dummy installs pkgs and returns the log of output. 427635e0e46SAndrew Geissler """ 428635e0e46SAndrew Geissler if len(pkgs) == 0: 429635e0e46SAndrew Geissler return 430635e0e46SAndrew Geissler 431635e0e46SAndrew Geissler # Create an temp dir as opkg root for dummy installation 432635e0e46SAndrew Geissler temp_rootfs = self.d.expand('${T}/opkg') 433635e0e46SAndrew Geissler opkg_lib_dir = self.d.getVar('OPKGLIBDIR') 434635e0e46SAndrew Geissler if opkg_lib_dir[0] == "/": 435635e0e46SAndrew Geissler opkg_lib_dir = opkg_lib_dir[1:] 436635e0e46SAndrew Geissler temp_opkg_dir = os.path.join(temp_rootfs, opkg_lib_dir, 'opkg') 437635e0e46SAndrew Geissler bb.utils.mkdirhier(temp_opkg_dir) 438635e0e46SAndrew Geissler 439635e0e46SAndrew Geissler opkg_args = "-f %s -o %s " % (self.config_file, temp_rootfs) 440635e0e46SAndrew Geissler opkg_args += self.d.getVar("OPKG_ARGS") 441635e0e46SAndrew Geissler 442635e0e46SAndrew Geissler cmd = "%s %s update" % (self.opkg_cmd, opkg_args) 443635e0e46SAndrew Geissler try: 444635e0e46SAndrew Geissler subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) 445635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 446635e0e46SAndrew Geissler bb.fatal("Unable to update. Command '%s' " 447635e0e46SAndrew Geissler "returned %d:\n%s" % (cmd, e.returncode, e.output.decode("utf-8"))) 448635e0e46SAndrew Geissler 449635e0e46SAndrew Geissler # Dummy installation 450635e0e46SAndrew Geissler cmd = "%s %s --noaction install %s " % (self.opkg_cmd, 451635e0e46SAndrew Geissler opkg_args, 452635e0e46SAndrew Geissler ' '.join(pkgs)) 453db4c27eeSPatrick Williams proc = subprocess.run(cmd, capture_output=True, encoding="utf-8", shell=True) 454db4c27eeSPatrick Williams if proc.returncode: 455635e0e46SAndrew Geissler bb.fatal("Unable to dummy install packages. Command '%s' " 456db4c27eeSPatrick Williams "returned %d:\n%s" % (cmd, proc.returncode, proc.stderr)) 457db4c27eeSPatrick Williams elif proc.stderr: 458db4c27eeSPatrick Williams bb.note("Command '%s' returned stderr: %s" % (cmd, proc.stderr)) 459635e0e46SAndrew Geissler 460635e0e46SAndrew Geissler bb.utils.remove(temp_rootfs, True) 461635e0e46SAndrew Geissler 462db4c27eeSPatrick Williams return proc.stdout 463635e0e46SAndrew Geissler 464635e0e46SAndrew Geissler def backup_packaging_data(self): 465635e0e46SAndrew Geissler # Save the opkglib for increment ipk image generation 466635e0e46SAndrew Geissler if os.path.exists(self.saved_opkg_dir): 467635e0e46SAndrew Geissler bb.utils.remove(self.saved_opkg_dir, True) 468635e0e46SAndrew Geissler shutil.copytree(self.opkg_dir, 469635e0e46SAndrew Geissler self.saved_opkg_dir, 470635e0e46SAndrew Geissler symlinks=True) 471635e0e46SAndrew Geissler 472635e0e46SAndrew Geissler def recover_packaging_data(self): 473635e0e46SAndrew Geissler # Move the opkglib back 474635e0e46SAndrew Geissler if os.path.exists(self.saved_opkg_dir): 475635e0e46SAndrew Geissler if os.path.exists(self.opkg_dir): 476635e0e46SAndrew Geissler bb.utils.remove(self.opkg_dir, True) 477635e0e46SAndrew Geissler 478635e0e46SAndrew Geissler bb.note('Recover packaging data') 479635e0e46SAndrew Geissler shutil.copytree(self.saved_opkg_dir, 480635e0e46SAndrew Geissler self.opkg_dir, 481635e0e46SAndrew Geissler symlinks=True) 482635e0e46SAndrew Geissler 483635e0e46SAndrew Geissler def package_info(self, pkg): 484635e0e46SAndrew Geissler """ 485635e0e46SAndrew Geissler Returns a dictionary with the package info. 486635e0e46SAndrew Geissler """ 487635e0e46SAndrew Geissler cmd = "%s %s info %s" % (self.opkg_cmd, self.opkg_args, pkg) 488635e0e46SAndrew Geissler pkg_info = super(OpkgPM, self).package_info(pkg, cmd) 489635e0e46SAndrew Geissler 490635e0e46SAndrew Geissler pkg_arch = pkg_info[pkg]["arch"] 491635e0e46SAndrew Geissler pkg_filename = pkg_info[pkg]["filename"] 492635e0e46SAndrew Geissler pkg_info[pkg]["filepath"] = \ 493635e0e46SAndrew Geissler os.path.join(self.deploy_dir, pkg_arch, pkg_filename) 494635e0e46SAndrew Geissler 495635e0e46SAndrew Geissler return pkg_info 496635e0e46SAndrew Geissler 497635e0e46SAndrew Geissler def extract(self, pkg): 498635e0e46SAndrew Geissler """ 499635e0e46SAndrew Geissler Returns the path to a tmpdir where resides the contents of a package. 500635e0e46SAndrew Geissler 501635e0e46SAndrew Geissler Deleting the tmpdir is responsability of the caller. 502635e0e46SAndrew Geissler """ 503635e0e46SAndrew Geissler pkg_info = self.package_info(pkg) 504635e0e46SAndrew Geissler if not pkg_info: 505635e0e46SAndrew Geissler bb.fatal("Unable to get information for package '%s' while " 506635e0e46SAndrew Geissler "trying to extract the package." % pkg) 507635e0e46SAndrew Geissler 508635e0e46SAndrew Geissler tmp_dir = super(OpkgPM, self).extract(pkg, pkg_info) 509169d7bccSPatrick Williams bb.utils.remove(os.path.join(tmp_dir, "data.tar.zst")) 510635e0e46SAndrew Geissler 511635e0e46SAndrew Geissler return tmp_dir 512