From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mail.openembedded.org (Postfix) with ESMTP id 0E5FD7002B for ; Thu, 12 May 2016 09:31:00 +0000 (UTC) Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga103.jf.intel.com with ESMTP; 12 May 2016 02:31:02 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.24,609,1455004800"; d="scan'208";a="951662134" Received: from jxu11-mobl2.amr.corp.intel.com ([10.255.3.247]) by orsmga001.jf.intel.com with ESMTP; 12 May 2016 02:31:00 -0700 Message-ID: <1463045458.3794.5.camel@linux.intel.com> From: Joshua G Lock To: mariano.lopez@linux.intel.com, openembedded-core@lists.openembedded.org Date: Thu, 12 May 2016 10:30:58 +0100 In-Reply-To: <6f35fcf9021b2b3d07e434bcd5e8ab678537e378.1462969737.git.mariano.lopez@linux.intel.com> References: <6f35fcf9021b2b3d07e434bcd5e8ab678537e378.1462969737.git.mariano.lopez@linux.intel.com> X-Mailer: Evolution 3.18.5.2 (3.18.5.2-1.fc23) Mime-Version: 1.0 Subject: Re: [PATCH 2/3] package_manager.py: Add extract() method for opkg and dpkg X-BeenThere: openembedded-core@lists.openembedded.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Patches and discussions about the oe-core layer List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 12 May 2016 09:31:01 -0000 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit On Wed, 2016-05-11 at 12:31 +0000, mariano.lopez@linux.intel.com wrote: > From: Mariano Lopez > > Sometimes it is needed to have the content of a package outside > the recipe context.  This new method extract the content of an > IPK/DEB file to a tmpdir, without actually installing the package. > > A new OpkgDpkgPM class was added to share the code for opkg and dpkg. > > There were need some changes to opkg_query() in order to use it > with apt-cache output. > > [YOCTO #9569] > > Signed-off-by: Mariano Lopez > --- >  meta/lib/oe/package_manager.py | 134 > +++++++++++++++++++++++++++++++++++++++-- >  1 file changed, 129 insertions(+), 5 deletions(-) > > diff --git a/meta/lib/oe/package_manager.py > b/meta/lib/oe/package_manager.py > index 427518d..0830da9 100644 > --- a/meta/lib/oe/package_manager.py > +++ b/meta/lib/oe/package_manager.py > @@ -38,6 +38,7 @@ def opkg_query(cmd_output): >      filename = "" >      dep = [] >      pkg = "" > +    pkgarch = "" Hard to tell from the context here but it looks like arch and ver don't have default values? Potential UnboundLocalError? >      for line in cmd_output.splitlines(): >          line = line.rstrip() >          if ':' in line: > @@ -47,8 +48,10 @@ def opkg_query(cmd_output): >                  arch = line.split(": ")[1] >              elif line.startswith("Version: "): >                  ver = line.split(": ")[1] > -            elif line.startswith("File: "): > +            elif line.startswith("File: ") or > line.startswith("Filename:"): >                  filename = line.split(": ")[1] > +                if "/" in filename: > +                    filename = os.path.basename(filename) >              elif line.startswith("Depends: "): >                  depends = verregex.sub('', line.split(": ")[1]) >                  for depend in depends.split(", "): > @@ -57,15 +60,20 @@ def opkg_query(cmd_output): >                  recommends = verregex.sub('', line.split(": ")[1]) >                  for recommend in recommends.split(", "): >                      dep.append("%s [REC]" % recommend) > -        else: > +            elif line.startswith("PackageArch: "): > +                pkgarch = line.split(": ")[1] > + > +        # When there is a blank line save the package information > +        elif not line: >              # IPK doesn't include the filename >              if not filename: >                  filename = "%s_%s_%s.ipk" % (pkg, ver, arch) >              if pkg: >                  output[pkg] = {"arch":arch, "ver":ver, > -                        "filename":filename, "deps": dep } > +                        "filename":filename, "deps": dep, > "pkgarch":pkgarch } >              pkg = "" >              filename = "" > +            pkgarch = "" >              dep = [] >   >      if pkg: > @@ -1397,7 +1405,70 @@ class RpmPM(PackageManager): >              bb.utils.remove(f, True) >   >   > -class OpkgPM(PackageManager): > +class OpkgDpkgPM(PackageManager): > +    """ > +    This is an abstract class. Do not instantiate this directly. > +    """ > +    def __init__(self, d): > +        super(OpkgDpkgPM, self).__init__(d) > + > +    """ > +    Returns a dictionary with the package info. > + > +    This method extracts the common parts for Opkg and Dpkg > +    """ > +    def package_info(self, pkg, cmd): > + > +        try: > +            output = subprocess.check_output(cmd, > stderr=subprocess.STDOUT, shell=True) > +        except subprocess.CalledProcessError as e: > +            bb.fatal("Unable to list available packages. Command > '%s' " > +                     "returned %d:\n%s" % (cmd, e.returncode, > e.output)) > +        return opkg_query(output) > + > +    """ > +    Returns the path to a tmpdir where resides the contents of a > package. > + > +    Deleting the tmpdir is responsability of the caller. > + > +    This method extracts the common parts for Opkg and Dpkg > +    """ > +    def extract(self, pkg, pkg_path): > + > +        ar_cmd = bb.utils.which(os.getenv("PATH"), "ar") > +        tar_cmd = bb.utils.which(os.getenv("PATH"), "tar") > + > +        if not os.path.isfile(pkg_path): > +            bb.fatal("Unable to extract package for '%s'." > +                     "File %s doesn't exists" % (pkg, pkg_path)) > + > +        tmp_dir = tempfile.mkdtemp() > +        current_dir = os.getcwd() > +        os.chdir(tmp_dir) > + > +        try: > +            cmd = "%s x %s" % (ar_cmd, pkg_path) > +            output = subprocess.check_output(cmd, > stderr=subprocess.STDOUT, shell=True) > +            cmd = "%s xf data.tar.*" % tar_cmd > +            output = subprocess.check_output(cmd, > stderr=subprocess.STDOUT, shell=True) > +        except subprocess.CalledProcessError as e: > +            bb.utils.remove(tmp_dir, recurse=True) > +            bb.fatal("Unable to extract %s package. Command '%s' " > +                     "returned %d:\n%s" % (pkg_path, cmd, > e.returncode, e.output)) > +        except OSError as e: > +            bb.utils.remove(tmp_dir, recurse=True) > +            bb.fatal("Unable to extract %s package. Command '%s' " > +                     "returned %d:\n%s at %s" % (pkg_path, cmd, > e.errno, e.strerror, e.filename)) > + > +        bb.note("Extracted %s to %s" % (pkg_path, tmp_dir)) > +        bb.utils.remove(os.path.join(tmp_dir, "debian-binary")) > +        bb.utils.remove(os.path.join(tmp_dir, "control.tar.gz")) > +        os.chdir(current_dir) > + > +        return tmp_dir > + > + > +class OpkgPM(OpkgDpkgPM): >      def __init__(self, d, target_rootfs, config_file, archs, > task_name='target'): >          super(OpkgPM, self).__init__(d) >   > @@ -1732,8 +1803,34 @@ class OpkgPM(PackageManager): >                              self.opkg_dir, >                              symlinks=True) >   > +    """ > +    Returns a dictionary with the package info. > +    """ > +    def package_info(self, pkg): > +        cmd = "%s %s info %s" % (self.opkg_cmd, self.opkg_args, pkg) > +        return super(OpkgPM, self).package_info(pkg, cmd) > + > +    """ > +    Returns the path to a tmpdir where resides the contents of a > package. > + > +    Deleting the tmpdir is responsability of the caller. > +    """ > +    def extract(self, pkg): > +        pkg_info = self.package_info(pkg) > +        if not pkg_info: > +            bb.fatal("Unable to get information for package '%s' > while " > +                     "trying to extract the package."  % pkg) >   > -class DpkgPM(PackageManager): > +        pkg_arch = pkg_info[pkg]["arch"] > +        pkg_filename = pkg_info[pkg]["filename"] > +        pkg_path = os.path.join(self.deploy_dir, pkg_arch, > pkg_filename) > + > +        tmp_dir = super(OpkgPM, self).extract(pkg, pkg_path) > +        bb.utils.remove(os.path.join(tmp_dir, "data.tar.gz")) > + > +        return tmp_dir > + > +class DpkgPM(OpkgDpkgPM): >      def __init__(self, d, target_rootfs, archs, base_archs, > apt_conf_dir=None): >          super(DpkgPM, self).__init__(d) >          self.target_rootfs = target_rootfs > @@ -1744,6 +1841,7 @@ class DpkgPM(PackageManager): >              self.apt_conf_dir = apt_conf_dir >          self.apt_conf_file = os.path.join(self.apt_conf_dir, > "apt.conf") >          self.apt_get_cmd = bb.utils.which(os.getenv('PATH'), "apt- > get") > +        self.apt_cache_cmd = bb.utils.which(os.getenv('PATH'), "apt- > cache") >   >          self.apt_args = d.getVar("APT_ARGS", True) >   > @@ -2027,6 +2125,32 @@ class DpkgPM(PackageManager): >      def list_installed(self): >          return DpkgPkgsList(self.d, self.target_rootfs).list_pkgs() >   > +    """ > +    Returns a dictionary with the package info. > +    """ > +    def package_info(self, pkg): > +        cmd = "%s show %s" % (self.apt_cache_cmd, pkg) > +        return super(DpkgPM, self).package_info(pkg, cmd) > + > +    """ > +    Returns the path to a tmpdir where resides the contents of a > package. > + > +    Deleting the tmpdir is responsability of the caller. > +    """ > +    def extract(self, pkg): > +        pkg_info = self.package_info(pkg) > +        if not pkg_info: > +            bb.fatal("Unable to get information for package '%s' > while " > +                     "trying to extract the package."  % pkg) > + > +        pkg_arch = pkg_info[pkg]["pkgarch"] > +        pkg_filename = pkg_info[pkg]["filename"] > +        pkg_path = os.path.join(self.deploy_dir, pkg_arch, > pkg_filename) > + > +        tmp_dir = super(DpkgPM, self).extract(pkg, pkg_path) > +        bb.utils.remove(os.path.join(tmp_dir, "data.tar.xz")) > + > +        return tmp_dir >   >  def generate_index_files(d): >      classes = d.getVar('PACKAGE_CLASSES', True).replace("package_", > "").split() > --  > 2.6.6 >