[OE-core] [PATCH 2/3] package_manager.py: Add extract() method for opkg and dpkg

Joshua G Lock joshua.g.lock at linux.intel.com
Thu May 12 09:30:58 UTC 2016


On Wed, 2016-05-11 at 12:31 +0000, mariano.lopez at linux.intel.com wrote:
> From: Mariano Lopez <mariano.lopez at linux.intel.com>
> 
> 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 <mariano.lopez at linux.intel.com>
> ---
>  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
> 



More information about the Openembedded-core mailing list