1*635e0e46SAndrew Geissler# 2*635e0e46SAndrew Geissler# SPDX-License-Identifier: GPL-2.0-only 3*635e0e46SAndrew Geissler# 4*635e0e46SAndrew Geissler 5*635e0e46SAndrew Geisslerimport re 6*635e0e46SAndrew Geisslerimport shutil 7*635e0e46SAndrew Geisslerimport subprocess 8*635e0e46SAndrew Geisslerfrom oe.package_manager import * 9*635e0e46SAndrew Geissler 10*635e0e46SAndrew Geisslerclass OpkgIndexer(Indexer): 11*635e0e46SAndrew Geissler def write_index(self): 12*635e0e46SAndrew Geissler arch_vars = ["ALL_MULTILIB_PACKAGE_ARCHS", 13*635e0e46SAndrew Geissler "SDK_PACKAGE_ARCHS", 14*635e0e46SAndrew Geissler ] 15*635e0e46SAndrew Geissler 16*635e0e46SAndrew Geissler opkg_index_cmd = bb.utils.which(os.getenv('PATH'), "opkg-make-index") 17*635e0e46SAndrew Geissler if self.d.getVar('PACKAGE_FEED_SIGN') == '1': 18*635e0e46SAndrew Geissler signer = get_signer(self.d, self.d.getVar('PACKAGE_FEED_GPG_BACKEND')) 19*635e0e46SAndrew Geissler else: 20*635e0e46SAndrew Geissler signer = None 21*635e0e46SAndrew Geissler 22*635e0e46SAndrew Geissler if not os.path.exists(os.path.join(self.deploy_dir, "Packages")): 23*635e0e46SAndrew Geissler open(os.path.join(self.deploy_dir, "Packages"), "w").close() 24*635e0e46SAndrew Geissler 25*635e0e46SAndrew Geissler index_cmds = set() 26*635e0e46SAndrew Geissler index_sign_files = set() 27*635e0e46SAndrew Geissler for arch_var in arch_vars: 28*635e0e46SAndrew Geissler archs = self.d.getVar(arch_var) 29*635e0e46SAndrew Geissler if archs is None: 30*635e0e46SAndrew Geissler continue 31*635e0e46SAndrew Geissler 32*635e0e46SAndrew Geissler for arch in archs.split(): 33*635e0e46SAndrew Geissler pkgs_dir = os.path.join(self.deploy_dir, arch) 34*635e0e46SAndrew Geissler pkgs_file = os.path.join(pkgs_dir, "Packages") 35*635e0e46SAndrew Geissler 36*635e0e46SAndrew Geissler if not os.path.isdir(pkgs_dir): 37*635e0e46SAndrew Geissler continue 38*635e0e46SAndrew Geissler 39*635e0e46SAndrew Geissler if not os.path.exists(pkgs_file): 40*635e0e46SAndrew Geissler open(pkgs_file, "w").close() 41*635e0e46SAndrew Geissler 42*635e0e46SAndrew Geissler index_cmds.add('%s --checksum md5 --checksum sha256 -r %s -p %s -m %s' % 43*635e0e46SAndrew Geissler (opkg_index_cmd, pkgs_file, pkgs_file, pkgs_dir)) 44*635e0e46SAndrew Geissler 45*635e0e46SAndrew Geissler index_sign_files.add(pkgs_file) 46*635e0e46SAndrew Geissler 47*635e0e46SAndrew Geissler if len(index_cmds) == 0: 48*635e0e46SAndrew Geissler bb.note("There are no packages in %s!" % self.deploy_dir) 49*635e0e46SAndrew Geissler return 50*635e0e46SAndrew Geissler 51*635e0e46SAndrew Geissler oe.utils.multiprocess_launch(create_index, index_cmds, self.d) 52*635e0e46SAndrew Geissler 53*635e0e46SAndrew Geissler if signer: 54*635e0e46SAndrew Geissler feed_sig_type = self.d.getVar('PACKAGE_FEED_GPG_SIGNATURE_TYPE') 55*635e0e46SAndrew Geissler is_ascii_sig = (feed_sig_type.upper() != "BIN") 56*635e0e46SAndrew Geissler for f in index_sign_files: 57*635e0e46SAndrew Geissler signer.detach_sign(f, 58*635e0e46SAndrew Geissler self.d.getVar('PACKAGE_FEED_GPG_NAME'), 59*635e0e46SAndrew Geissler self.d.getVar('PACKAGE_FEED_GPG_PASSPHRASE_FILE'), 60*635e0e46SAndrew Geissler armor=is_ascii_sig) 61*635e0e46SAndrew Geissler 62*635e0e46SAndrew Geisslerclass OpkgPkgsList(PkgsList): 63*635e0e46SAndrew Geissler def __init__(self, d, rootfs_dir, config_file): 64*635e0e46SAndrew Geissler super(OpkgPkgsList, self).__init__(d, rootfs_dir) 65*635e0e46SAndrew Geissler 66*635e0e46SAndrew Geissler self.opkg_cmd = bb.utils.which(os.getenv('PATH'), "opkg") 67*635e0e46SAndrew Geissler self.opkg_args = "-f %s -o %s " % (config_file, rootfs_dir) 68*635e0e46SAndrew Geissler self.opkg_args += self.d.getVar("OPKG_ARGS") 69*635e0e46SAndrew Geissler 70*635e0e46SAndrew Geissler def list_pkgs(self, format=None): 71*635e0e46SAndrew Geissler cmd = "%s %s status" % (self.opkg_cmd, self.opkg_args) 72*635e0e46SAndrew Geissler 73*635e0e46SAndrew Geissler # opkg returns success even when it printed some 74*635e0e46SAndrew Geissler # "Collected errors:" report to stderr. Mixing stderr into 75*635e0e46SAndrew Geissler # stdout then leads to random failures later on when 76*635e0e46SAndrew Geissler # parsing the output. To avoid this we need to collect both 77*635e0e46SAndrew Geissler # output streams separately and check for empty stderr. 78*635e0e46SAndrew Geissler p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 79*635e0e46SAndrew Geissler cmd_output, cmd_stderr = p.communicate() 80*635e0e46SAndrew Geissler cmd_output = cmd_output.decode("utf-8") 81*635e0e46SAndrew Geissler cmd_stderr = cmd_stderr.decode("utf-8") 82*635e0e46SAndrew Geissler if p.returncode or cmd_stderr: 83*635e0e46SAndrew Geissler bb.fatal("Cannot get the installed packages list. Command '%s' " 84*635e0e46SAndrew Geissler "returned %d and stderr:\n%s" % (cmd, p.returncode, cmd_stderr)) 85*635e0e46SAndrew Geissler 86*635e0e46SAndrew Geissler return opkg_query(cmd_output) 87*635e0e46SAndrew Geissler 88*635e0e46SAndrew Geissler 89*635e0e46SAndrew Geissler 90*635e0e46SAndrew Geisslerclass OpkgDpkgPM(PackageManager): 91*635e0e46SAndrew Geissler def __init__(self, d, target_rootfs): 92*635e0e46SAndrew Geissler """ 93*635e0e46SAndrew Geissler This is an abstract class. Do not instantiate this directly. 94*635e0e46SAndrew Geissler """ 95*635e0e46SAndrew Geissler super(OpkgDpkgPM, self).__init__(d, target_rootfs) 96*635e0e46SAndrew Geissler 97*635e0e46SAndrew Geissler def package_info(self, pkg, cmd): 98*635e0e46SAndrew Geissler """ 99*635e0e46SAndrew Geissler Returns a dictionary with the package info. 100*635e0e46SAndrew Geissler 101*635e0e46SAndrew Geissler This method extracts the common parts for Opkg and Dpkg 102*635e0e46SAndrew Geissler """ 103*635e0e46SAndrew Geissler 104*635e0e46SAndrew Geissler try: 105*635e0e46SAndrew Geissler output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True).decode("utf-8") 106*635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 107*635e0e46SAndrew Geissler bb.fatal("Unable to list available packages. Command '%s' " 108*635e0e46SAndrew Geissler "returned %d:\n%s" % (cmd, e.returncode, e.output.decode("utf-8"))) 109*635e0e46SAndrew Geissler return opkg_query(output) 110*635e0e46SAndrew Geissler 111*635e0e46SAndrew Geissler def extract(self, pkg, pkg_info): 112*635e0e46SAndrew Geissler """ 113*635e0e46SAndrew Geissler Returns the path to a tmpdir where resides the contents of a package. 114*635e0e46SAndrew Geissler 115*635e0e46SAndrew Geissler Deleting the tmpdir is responsability of the caller. 116*635e0e46SAndrew Geissler 117*635e0e46SAndrew Geissler This method extracts the common parts for Opkg and Dpkg 118*635e0e46SAndrew Geissler """ 119*635e0e46SAndrew Geissler 120*635e0e46SAndrew Geissler ar_cmd = bb.utils.which(os.getenv("PATH"), "ar") 121*635e0e46SAndrew Geissler tar_cmd = bb.utils.which(os.getenv("PATH"), "tar") 122*635e0e46SAndrew Geissler pkg_path = pkg_info[pkg]["filepath"] 123*635e0e46SAndrew Geissler 124*635e0e46SAndrew Geissler if not os.path.isfile(pkg_path): 125*635e0e46SAndrew Geissler bb.fatal("Unable to extract package for '%s'." 126*635e0e46SAndrew Geissler "File %s doesn't exists" % (pkg, pkg_path)) 127*635e0e46SAndrew Geissler 128*635e0e46SAndrew Geissler tmp_dir = tempfile.mkdtemp() 129*635e0e46SAndrew Geissler current_dir = os.getcwd() 130*635e0e46SAndrew Geissler os.chdir(tmp_dir) 131*635e0e46SAndrew Geissler data_tar = 'data.tar.xz' 132*635e0e46SAndrew Geissler 133*635e0e46SAndrew Geissler try: 134*635e0e46SAndrew Geissler cmd = [ar_cmd, 'x', pkg_path] 135*635e0e46SAndrew Geissler output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) 136*635e0e46SAndrew Geissler cmd = [tar_cmd, 'xf', data_tar] 137*635e0e46SAndrew Geissler output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) 138*635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 139*635e0e46SAndrew Geissler bb.utils.remove(tmp_dir, recurse=True) 140*635e0e46SAndrew Geissler bb.fatal("Unable to extract %s package. Command '%s' " 141*635e0e46SAndrew Geissler "returned %d:\n%s" % (pkg_path, ' '.join(cmd), e.returncode, e.output.decode("utf-8"))) 142*635e0e46SAndrew Geissler except OSError as e: 143*635e0e46SAndrew Geissler bb.utils.remove(tmp_dir, recurse=True) 144*635e0e46SAndrew Geissler bb.fatal("Unable to extract %s package. Command '%s' " 145*635e0e46SAndrew Geissler "returned %d:\n%s at %s" % (pkg_path, ' '.join(cmd), e.errno, e.strerror, e.filename)) 146*635e0e46SAndrew Geissler 147*635e0e46SAndrew Geissler bb.note("Extracted %s to %s" % (pkg_path, tmp_dir)) 148*635e0e46SAndrew Geissler bb.utils.remove(os.path.join(tmp_dir, "debian-binary")) 149*635e0e46SAndrew Geissler bb.utils.remove(os.path.join(tmp_dir, "control.tar.gz")) 150*635e0e46SAndrew Geissler os.chdir(current_dir) 151*635e0e46SAndrew Geissler 152*635e0e46SAndrew Geissler return tmp_dir 153*635e0e46SAndrew Geissler 154*635e0e46SAndrew Geissler def _handle_intercept_failure(self, registered_pkgs): 155*635e0e46SAndrew Geissler self.mark_packages("unpacked", registered_pkgs.split()) 156*635e0e46SAndrew Geissler 157*635e0e46SAndrew Geisslerclass OpkgPM(OpkgDpkgPM): 158*635e0e46SAndrew Geissler def __init__(self, d, target_rootfs, config_file, archs, task_name='target', ipk_repo_workdir="oe-rootfs-repo", filterbydependencies=True, prepare_index=True): 159*635e0e46SAndrew Geissler super(OpkgPM, self).__init__(d, target_rootfs) 160*635e0e46SAndrew Geissler 161*635e0e46SAndrew Geissler self.config_file = config_file 162*635e0e46SAndrew Geissler self.pkg_archs = archs 163*635e0e46SAndrew Geissler self.task_name = task_name 164*635e0e46SAndrew Geissler 165*635e0e46SAndrew Geissler self.deploy_dir = oe.path.join(self.d.getVar('WORKDIR'), ipk_repo_workdir) 166*635e0e46SAndrew Geissler self.deploy_lock_file = os.path.join(self.deploy_dir, "deploy.lock") 167*635e0e46SAndrew Geissler self.opkg_cmd = bb.utils.which(os.getenv('PATH'), "opkg") 168*635e0e46SAndrew Geissler self.opkg_args = "--volatile-cache -f %s -t %s -o %s " % (self.config_file, self.d.expand('${T}/ipktemp/') ,target_rootfs) 169*635e0e46SAndrew Geissler self.opkg_args += self.d.getVar("OPKG_ARGS") 170*635e0e46SAndrew Geissler 171*635e0e46SAndrew Geissler if prepare_index: 172*635e0e46SAndrew Geissler create_packages_dir(self.d, self.deploy_dir, d.getVar("DEPLOY_DIR_IPK"), "package_write_ipk", filterbydependencies) 173*635e0e46SAndrew Geissler 174*635e0e46SAndrew Geissler opkg_lib_dir = self.d.getVar('OPKGLIBDIR') 175*635e0e46SAndrew Geissler if opkg_lib_dir[0] == "/": 176*635e0e46SAndrew Geissler opkg_lib_dir = opkg_lib_dir[1:] 177*635e0e46SAndrew Geissler 178*635e0e46SAndrew Geissler self.opkg_dir = os.path.join(target_rootfs, opkg_lib_dir, "opkg") 179*635e0e46SAndrew Geissler 180*635e0e46SAndrew Geissler bb.utils.mkdirhier(self.opkg_dir) 181*635e0e46SAndrew Geissler 182*635e0e46SAndrew Geissler self.saved_opkg_dir = self.d.expand('${T}/saved/%s' % self.task_name) 183*635e0e46SAndrew Geissler if not os.path.exists(self.d.expand('${T}/saved')): 184*635e0e46SAndrew Geissler bb.utils.mkdirhier(self.d.expand('${T}/saved')) 185*635e0e46SAndrew Geissler 186*635e0e46SAndrew Geissler self.from_feeds = (self.d.getVar('BUILD_IMAGES_FROM_FEEDS') or "") == "1" 187*635e0e46SAndrew Geissler if self.from_feeds: 188*635e0e46SAndrew Geissler self._create_custom_config() 189*635e0e46SAndrew Geissler else: 190*635e0e46SAndrew Geissler self._create_config() 191*635e0e46SAndrew Geissler 192*635e0e46SAndrew Geissler self.indexer = OpkgIndexer(self.d, self.deploy_dir) 193*635e0e46SAndrew Geissler 194*635e0e46SAndrew Geissler def mark_packages(self, status_tag, packages=None): 195*635e0e46SAndrew Geissler """ 196*635e0e46SAndrew Geissler This function will change a package's status in /var/lib/opkg/status file. 197*635e0e46SAndrew Geissler If 'packages' is None then the new_status will be applied to all 198*635e0e46SAndrew Geissler packages 199*635e0e46SAndrew Geissler """ 200*635e0e46SAndrew Geissler status_file = os.path.join(self.opkg_dir, "status") 201*635e0e46SAndrew Geissler 202*635e0e46SAndrew Geissler with open(status_file, "r") as sf: 203*635e0e46SAndrew Geissler with open(status_file + ".tmp", "w+") as tmp_sf: 204*635e0e46SAndrew Geissler if packages is None: 205*635e0e46SAndrew Geissler tmp_sf.write(re.sub(r"Package: (.*?)\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)", 206*635e0e46SAndrew Geissler r"Package: \1\n\2Status: \3%s" % status_tag, 207*635e0e46SAndrew Geissler sf.read())) 208*635e0e46SAndrew Geissler else: 209*635e0e46SAndrew Geissler if type(packages).__name__ != "list": 210*635e0e46SAndrew Geissler raise TypeError("'packages' should be a list object") 211*635e0e46SAndrew Geissler 212*635e0e46SAndrew Geissler status = sf.read() 213*635e0e46SAndrew Geissler for pkg in packages: 214*635e0e46SAndrew Geissler status = re.sub(r"Package: %s\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)" % pkg, 215*635e0e46SAndrew Geissler r"Package: %s\n\1Status: \2%s" % (pkg, status_tag), 216*635e0e46SAndrew Geissler status) 217*635e0e46SAndrew Geissler 218*635e0e46SAndrew Geissler tmp_sf.write(status) 219*635e0e46SAndrew Geissler 220*635e0e46SAndrew Geissler os.rename(status_file + ".tmp", status_file) 221*635e0e46SAndrew Geissler 222*635e0e46SAndrew Geissler def _create_custom_config(self): 223*635e0e46SAndrew Geissler bb.note("Building from feeds activated!") 224*635e0e46SAndrew Geissler 225*635e0e46SAndrew Geissler with open(self.config_file, "w+") as config_file: 226*635e0e46SAndrew Geissler priority = 1 227*635e0e46SAndrew Geissler for arch in self.pkg_archs.split(): 228*635e0e46SAndrew Geissler config_file.write("arch %s %d\n" % (arch, priority)) 229*635e0e46SAndrew Geissler priority += 5 230*635e0e46SAndrew Geissler 231*635e0e46SAndrew Geissler for line in (self.d.getVar('IPK_FEED_URIS') or "").split(): 232*635e0e46SAndrew Geissler feed_match = re.match(r"^[ \t]*(.*)##([^ \t]*)[ \t]*$", line) 233*635e0e46SAndrew Geissler 234*635e0e46SAndrew Geissler if feed_match is not None: 235*635e0e46SAndrew Geissler feed_name = feed_match.group(1) 236*635e0e46SAndrew Geissler feed_uri = feed_match.group(2) 237*635e0e46SAndrew Geissler 238*635e0e46SAndrew Geissler bb.note("Add %s feed with URL %s" % (feed_name, feed_uri)) 239*635e0e46SAndrew Geissler 240*635e0e46SAndrew Geissler config_file.write("src/gz %s %s\n" % (feed_name, feed_uri)) 241*635e0e46SAndrew Geissler 242*635e0e46SAndrew Geissler """ 243*635e0e46SAndrew Geissler Allow to use package deploy directory contents as quick devel-testing 244*635e0e46SAndrew Geissler feed. This creates individual feed configs for each arch subdir of those 245*635e0e46SAndrew Geissler specified as compatible for the current machine. 246*635e0e46SAndrew Geissler NOTE: Development-helper feature, NOT a full-fledged feed. 247*635e0e46SAndrew Geissler """ 248*635e0e46SAndrew Geissler if (self.d.getVar('FEED_DEPLOYDIR_BASE_URI') or "") != "": 249*635e0e46SAndrew Geissler for arch in self.pkg_archs.split(): 250*635e0e46SAndrew Geissler cfg_file_name = os.path.join(self.target_rootfs, 251*635e0e46SAndrew Geissler self.d.getVar("sysconfdir"), 252*635e0e46SAndrew Geissler "opkg", 253*635e0e46SAndrew Geissler "local-%s-feed.conf" % arch) 254*635e0e46SAndrew Geissler 255*635e0e46SAndrew Geissler with open(cfg_file_name, "w+") as cfg_file: 256*635e0e46SAndrew Geissler cfg_file.write("src/gz local-%s %s/%s" % 257*635e0e46SAndrew Geissler (arch, 258*635e0e46SAndrew Geissler self.d.getVar('FEED_DEPLOYDIR_BASE_URI'), 259*635e0e46SAndrew Geissler arch)) 260*635e0e46SAndrew Geissler 261*635e0e46SAndrew Geissler if self.d.getVar('OPKGLIBDIR') != '/var/lib': 262*635e0e46SAndrew Geissler # There is no command line option for this anymore, we need to add 263*635e0e46SAndrew Geissler # info_dir and status_file to config file, if OPKGLIBDIR doesn't have 264*635e0e46SAndrew Geissler # the default value of "/var/lib" as defined in opkg: 265*635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_LISTS_DIR VARDIR "/lib/opkg/lists" 266*635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_INFO_DIR VARDIR "/lib/opkg/info" 267*635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_STATUS_FILE VARDIR "/lib/opkg/status" 268*635e0e46SAndrew Geissler cfg_file.write("option info_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'info')) 269*635e0e46SAndrew Geissler cfg_file.write("option lists_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'lists')) 270*635e0e46SAndrew Geissler cfg_file.write("option status_file %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'status')) 271*635e0e46SAndrew Geissler 272*635e0e46SAndrew Geissler 273*635e0e46SAndrew Geissler def _create_config(self): 274*635e0e46SAndrew Geissler with open(self.config_file, "w+") as config_file: 275*635e0e46SAndrew Geissler priority = 1 276*635e0e46SAndrew Geissler for arch in self.pkg_archs.split(): 277*635e0e46SAndrew Geissler config_file.write("arch %s %d\n" % (arch, priority)) 278*635e0e46SAndrew Geissler priority += 5 279*635e0e46SAndrew Geissler 280*635e0e46SAndrew Geissler config_file.write("src oe file:%s\n" % self.deploy_dir) 281*635e0e46SAndrew Geissler 282*635e0e46SAndrew Geissler for arch in self.pkg_archs.split(): 283*635e0e46SAndrew Geissler pkgs_dir = os.path.join(self.deploy_dir, arch) 284*635e0e46SAndrew Geissler if os.path.isdir(pkgs_dir): 285*635e0e46SAndrew Geissler config_file.write("src oe-%s file:%s\n" % 286*635e0e46SAndrew Geissler (arch, pkgs_dir)) 287*635e0e46SAndrew Geissler 288*635e0e46SAndrew Geissler if self.d.getVar('OPKGLIBDIR') != '/var/lib': 289*635e0e46SAndrew Geissler # There is no command line option for this anymore, we need to add 290*635e0e46SAndrew Geissler # info_dir and status_file to config file, if OPKGLIBDIR doesn't have 291*635e0e46SAndrew Geissler # the default value of "/var/lib" as defined in opkg: 292*635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_LISTS_DIR VARDIR "/lib/opkg/lists" 293*635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_INFO_DIR VARDIR "/lib/opkg/info" 294*635e0e46SAndrew Geissler # libopkg/opkg_conf.h:#define OPKG_CONF_DEFAULT_STATUS_FILE VARDIR "/lib/opkg/status" 295*635e0e46SAndrew Geissler config_file.write("option info_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'info')) 296*635e0e46SAndrew Geissler config_file.write("option lists_dir %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'lists')) 297*635e0e46SAndrew Geissler config_file.write("option status_file %s\n" % os.path.join(self.d.getVar('OPKGLIBDIR'), 'opkg', 'status')) 298*635e0e46SAndrew Geissler 299*635e0e46SAndrew Geissler def insert_feeds_uris(self, feed_uris, feed_base_paths, feed_archs): 300*635e0e46SAndrew Geissler if feed_uris == "": 301*635e0e46SAndrew Geissler return 302*635e0e46SAndrew Geissler 303*635e0e46SAndrew Geissler rootfs_config = os.path.join('%s/etc/opkg/base-feeds.conf' 304*635e0e46SAndrew Geissler % self.target_rootfs) 305*635e0e46SAndrew Geissler 306*635e0e46SAndrew Geissler os.makedirs('%s/etc/opkg' % self.target_rootfs, exist_ok=True) 307*635e0e46SAndrew Geissler 308*635e0e46SAndrew Geissler feed_uris = self.construct_uris(feed_uris.split(), feed_base_paths.split()) 309*635e0e46SAndrew Geissler archs = self.pkg_archs.split() if feed_archs is None else feed_archs.split() 310*635e0e46SAndrew Geissler 311*635e0e46SAndrew Geissler with open(rootfs_config, "w+") as config_file: 312*635e0e46SAndrew Geissler uri_iterator = 0 313*635e0e46SAndrew Geissler for uri in feed_uris: 314*635e0e46SAndrew Geissler if archs: 315*635e0e46SAndrew Geissler for arch in archs: 316*635e0e46SAndrew Geissler if (feed_archs is None) and (not os.path.exists(oe.path.join(self.deploy_dir, arch))): 317*635e0e46SAndrew Geissler continue 318*635e0e46SAndrew Geissler bb.note('Adding opkg feed url-%s-%d (%s)' % 319*635e0e46SAndrew Geissler (arch, uri_iterator, uri)) 320*635e0e46SAndrew Geissler config_file.write("src/gz uri-%s-%d %s/%s\n" % 321*635e0e46SAndrew Geissler (arch, uri_iterator, uri, arch)) 322*635e0e46SAndrew Geissler else: 323*635e0e46SAndrew Geissler bb.note('Adding opkg feed url-%d (%s)' % 324*635e0e46SAndrew Geissler (uri_iterator, uri)) 325*635e0e46SAndrew Geissler config_file.write("src/gz uri-%d %s\n" % 326*635e0e46SAndrew Geissler (uri_iterator, uri)) 327*635e0e46SAndrew Geissler 328*635e0e46SAndrew Geissler uri_iterator += 1 329*635e0e46SAndrew Geissler 330*635e0e46SAndrew Geissler def update(self): 331*635e0e46SAndrew Geissler self.deploy_dir_lock() 332*635e0e46SAndrew Geissler 333*635e0e46SAndrew Geissler cmd = "%s %s update" % (self.opkg_cmd, self.opkg_args) 334*635e0e46SAndrew Geissler 335*635e0e46SAndrew Geissler try: 336*635e0e46SAndrew Geissler subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) 337*635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 338*635e0e46SAndrew Geissler self.deploy_dir_unlock() 339*635e0e46SAndrew Geissler bb.fatal("Unable to update the package index files. Command '%s' " 340*635e0e46SAndrew Geissler "returned %d:\n%s" % (cmd, e.returncode, e.output.decode("utf-8"))) 341*635e0e46SAndrew Geissler 342*635e0e46SAndrew Geissler self.deploy_dir_unlock() 343*635e0e46SAndrew Geissler 344*635e0e46SAndrew Geissler def install(self, pkgs, attempt_only=False): 345*635e0e46SAndrew Geissler if not pkgs: 346*635e0e46SAndrew Geissler return 347*635e0e46SAndrew Geissler 348*635e0e46SAndrew Geissler cmd = "%s %s" % (self.opkg_cmd, self.opkg_args) 349*635e0e46SAndrew Geissler for exclude in (self.d.getVar("PACKAGE_EXCLUDE") or "").split(): 350*635e0e46SAndrew Geissler cmd += " --add-exclude %s" % exclude 351*635e0e46SAndrew Geissler for bad_recommendation in (self.d.getVar("BAD_RECOMMENDATIONS") or "").split(): 352*635e0e46SAndrew Geissler cmd += " --add-ignore-recommends %s" % bad_recommendation 353*635e0e46SAndrew Geissler cmd += " install " 354*635e0e46SAndrew Geissler cmd += " ".join(pkgs) 355*635e0e46SAndrew Geissler 356*635e0e46SAndrew Geissler os.environ['D'] = self.target_rootfs 357*635e0e46SAndrew Geissler os.environ['OFFLINE_ROOT'] = self.target_rootfs 358*635e0e46SAndrew Geissler os.environ['IPKG_OFFLINE_ROOT'] = self.target_rootfs 359*635e0e46SAndrew Geissler os.environ['OPKG_OFFLINE_ROOT'] = self.target_rootfs 360*635e0e46SAndrew Geissler os.environ['INTERCEPT_DIR'] = self.intercepts_dir 361*635e0e46SAndrew Geissler os.environ['NATIVE_ROOT'] = self.d.getVar('STAGING_DIR_NATIVE') 362*635e0e46SAndrew Geissler 363*635e0e46SAndrew Geissler try: 364*635e0e46SAndrew Geissler bb.note("Installing the following packages: %s" % ' '.join(pkgs)) 365*635e0e46SAndrew Geissler bb.note(cmd) 366*635e0e46SAndrew Geissler output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT).decode("utf-8") 367*635e0e46SAndrew Geissler bb.note(output) 368*635e0e46SAndrew Geissler failed_pkgs = [] 369*635e0e46SAndrew Geissler for line in output.split('\n'): 370*635e0e46SAndrew Geissler if line.endswith("configuration required on target."): 371*635e0e46SAndrew Geissler bb.warn(line) 372*635e0e46SAndrew Geissler failed_pkgs.append(line.split(".")[0]) 373*635e0e46SAndrew Geissler if failed_pkgs: 374*635e0e46SAndrew Geissler failed_postinsts_abort(failed_pkgs, self.d.expand("${T}/log.do_${BB_CURRENTTASK}")) 375*635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 376*635e0e46SAndrew Geissler (bb.fatal, bb.warn)[attempt_only]("Unable to install packages. " 377*635e0e46SAndrew Geissler "Command '%s' returned %d:\n%s" % 378*635e0e46SAndrew Geissler (cmd, e.returncode, e.output.decode("utf-8"))) 379*635e0e46SAndrew Geissler 380*635e0e46SAndrew Geissler def remove(self, pkgs, with_dependencies=True): 381*635e0e46SAndrew Geissler if not pkgs: 382*635e0e46SAndrew Geissler return 383*635e0e46SAndrew Geissler 384*635e0e46SAndrew Geissler if with_dependencies: 385*635e0e46SAndrew Geissler cmd = "%s %s --force-remove --force-removal-of-dependent-packages remove %s" % \ 386*635e0e46SAndrew Geissler (self.opkg_cmd, self.opkg_args, ' '.join(pkgs)) 387*635e0e46SAndrew Geissler else: 388*635e0e46SAndrew Geissler cmd = "%s %s --force-depends remove %s" % \ 389*635e0e46SAndrew Geissler (self.opkg_cmd, self.opkg_args, ' '.join(pkgs)) 390*635e0e46SAndrew Geissler 391*635e0e46SAndrew Geissler try: 392*635e0e46SAndrew Geissler bb.note(cmd) 393*635e0e46SAndrew Geissler output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT).decode("utf-8") 394*635e0e46SAndrew Geissler bb.note(output) 395*635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 396*635e0e46SAndrew Geissler bb.fatal("Unable to remove packages. Command '%s' " 397*635e0e46SAndrew Geissler "returned %d:\n%s" % (e.cmd, e.returncode, e.output.decode("utf-8"))) 398*635e0e46SAndrew Geissler 399*635e0e46SAndrew Geissler def write_index(self): 400*635e0e46SAndrew Geissler self.deploy_dir_lock() 401*635e0e46SAndrew Geissler 402*635e0e46SAndrew Geissler result = self.indexer.write_index() 403*635e0e46SAndrew Geissler 404*635e0e46SAndrew Geissler self.deploy_dir_unlock() 405*635e0e46SAndrew Geissler 406*635e0e46SAndrew Geissler if result is not None: 407*635e0e46SAndrew Geissler bb.fatal(result) 408*635e0e46SAndrew Geissler 409*635e0e46SAndrew Geissler def remove_packaging_data(self): 410*635e0e46SAndrew Geissler bb.utils.remove(self.opkg_dir, True) 411*635e0e46SAndrew Geissler # create the directory back, it's needed by PM lock 412*635e0e46SAndrew Geissler bb.utils.mkdirhier(self.opkg_dir) 413*635e0e46SAndrew Geissler 414*635e0e46SAndrew Geissler def remove_lists(self): 415*635e0e46SAndrew Geissler if not self.from_feeds: 416*635e0e46SAndrew Geissler bb.utils.remove(os.path.join(self.opkg_dir, "lists"), True) 417*635e0e46SAndrew Geissler 418*635e0e46SAndrew Geissler def list_installed(self): 419*635e0e46SAndrew Geissler return OpkgPkgsList(self.d, self.target_rootfs, self.config_file).list_pkgs() 420*635e0e46SAndrew Geissler 421*635e0e46SAndrew Geissler def dummy_install(self, pkgs): 422*635e0e46SAndrew Geissler """ 423*635e0e46SAndrew Geissler The following function dummy installs pkgs and returns the log of output. 424*635e0e46SAndrew Geissler """ 425*635e0e46SAndrew Geissler if len(pkgs) == 0: 426*635e0e46SAndrew Geissler return 427*635e0e46SAndrew Geissler 428*635e0e46SAndrew Geissler # Create an temp dir as opkg root for dummy installation 429*635e0e46SAndrew Geissler temp_rootfs = self.d.expand('${T}/opkg') 430*635e0e46SAndrew Geissler opkg_lib_dir = self.d.getVar('OPKGLIBDIR') 431*635e0e46SAndrew Geissler if opkg_lib_dir[0] == "/": 432*635e0e46SAndrew Geissler opkg_lib_dir = opkg_lib_dir[1:] 433*635e0e46SAndrew Geissler temp_opkg_dir = os.path.join(temp_rootfs, opkg_lib_dir, 'opkg') 434*635e0e46SAndrew Geissler bb.utils.mkdirhier(temp_opkg_dir) 435*635e0e46SAndrew Geissler 436*635e0e46SAndrew Geissler opkg_args = "-f %s -o %s " % (self.config_file, temp_rootfs) 437*635e0e46SAndrew Geissler opkg_args += self.d.getVar("OPKG_ARGS") 438*635e0e46SAndrew Geissler 439*635e0e46SAndrew Geissler cmd = "%s %s update" % (self.opkg_cmd, opkg_args) 440*635e0e46SAndrew Geissler try: 441*635e0e46SAndrew Geissler subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) 442*635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 443*635e0e46SAndrew Geissler bb.fatal("Unable to update. Command '%s' " 444*635e0e46SAndrew Geissler "returned %d:\n%s" % (cmd, e.returncode, e.output.decode("utf-8"))) 445*635e0e46SAndrew Geissler 446*635e0e46SAndrew Geissler # Dummy installation 447*635e0e46SAndrew Geissler cmd = "%s %s --noaction install %s " % (self.opkg_cmd, 448*635e0e46SAndrew Geissler opkg_args, 449*635e0e46SAndrew Geissler ' '.join(pkgs)) 450*635e0e46SAndrew Geissler try: 451*635e0e46SAndrew Geissler output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) 452*635e0e46SAndrew Geissler except subprocess.CalledProcessError as e: 453*635e0e46SAndrew Geissler bb.fatal("Unable to dummy install packages. Command '%s' " 454*635e0e46SAndrew Geissler "returned %d:\n%s" % (cmd, e.returncode, e.output.decode("utf-8"))) 455*635e0e46SAndrew Geissler 456*635e0e46SAndrew Geissler bb.utils.remove(temp_rootfs, True) 457*635e0e46SAndrew Geissler 458*635e0e46SAndrew Geissler return output 459*635e0e46SAndrew Geissler 460*635e0e46SAndrew Geissler def backup_packaging_data(self): 461*635e0e46SAndrew Geissler # Save the opkglib for increment ipk image generation 462*635e0e46SAndrew Geissler if os.path.exists(self.saved_opkg_dir): 463*635e0e46SAndrew Geissler bb.utils.remove(self.saved_opkg_dir, True) 464*635e0e46SAndrew Geissler shutil.copytree(self.opkg_dir, 465*635e0e46SAndrew Geissler self.saved_opkg_dir, 466*635e0e46SAndrew Geissler symlinks=True) 467*635e0e46SAndrew Geissler 468*635e0e46SAndrew Geissler def recover_packaging_data(self): 469*635e0e46SAndrew Geissler # Move the opkglib back 470*635e0e46SAndrew Geissler if os.path.exists(self.saved_opkg_dir): 471*635e0e46SAndrew Geissler if os.path.exists(self.opkg_dir): 472*635e0e46SAndrew Geissler bb.utils.remove(self.opkg_dir, True) 473*635e0e46SAndrew Geissler 474*635e0e46SAndrew Geissler bb.note('Recover packaging data') 475*635e0e46SAndrew Geissler shutil.copytree(self.saved_opkg_dir, 476*635e0e46SAndrew Geissler self.opkg_dir, 477*635e0e46SAndrew Geissler symlinks=True) 478*635e0e46SAndrew Geissler 479*635e0e46SAndrew Geissler def package_info(self, pkg): 480*635e0e46SAndrew Geissler """ 481*635e0e46SAndrew Geissler Returns a dictionary with the package info. 482*635e0e46SAndrew Geissler """ 483*635e0e46SAndrew Geissler cmd = "%s %s info %s" % (self.opkg_cmd, self.opkg_args, pkg) 484*635e0e46SAndrew Geissler pkg_info = super(OpkgPM, self).package_info(pkg, cmd) 485*635e0e46SAndrew Geissler 486*635e0e46SAndrew Geissler pkg_arch = pkg_info[pkg]["arch"] 487*635e0e46SAndrew Geissler pkg_filename = pkg_info[pkg]["filename"] 488*635e0e46SAndrew Geissler pkg_info[pkg]["filepath"] = \ 489*635e0e46SAndrew Geissler os.path.join(self.deploy_dir, pkg_arch, pkg_filename) 490*635e0e46SAndrew Geissler 491*635e0e46SAndrew Geissler return pkg_info 492*635e0e46SAndrew Geissler 493*635e0e46SAndrew Geissler def extract(self, pkg): 494*635e0e46SAndrew Geissler """ 495*635e0e46SAndrew Geissler Returns the path to a tmpdir where resides the contents of a package. 496*635e0e46SAndrew Geissler 497*635e0e46SAndrew Geissler Deleting the tmpdir is responsability of the caller. 498*635e0e46SAndrew Geissler """ 499*635e0e46SAndrew Geissler pkg_info = self.package_info(pkg) 500*635e0e46SAndrew Geissler if not pkg_info: 501*635e0e46SAndrew Geissler bb.fatal("Unable to get information for package '%s' while " 502*635e0e46SAndrew Geissler "trying to extract the package." % pkg) 503*635e0e46SAndrew Geissler 504*635e0e46SAndrew Geissler tmp_dir = super(OpkgPM, self).extract(pkg, pkg_info) 505*635e0e46SAndrew Geissler bb.utils.remove(os.path.join(tmp_dir, "data.tar.xz")) 506*635e0e46SAndrew Geissler 507*635e0e46SAndrew Geissler return tmp_dir 508