Openembedded Core Discussions
 help / color / mirror / Atom feed
From: Joshua G Lock <joshua.g.lock@linux.intel.com>
To: mariano.lopez@linux.intel.com, openembedded-core@lists.openembedded.org
Subject: Re: [PATCH 2/3] package_manager.py: Add extract() method for opkg and dpkg
Date: Thu, 12 May 2016 10:30:58 +0100	[thread overview]
Message-ID: <1463045458.3794.5.camel@linux.intel.com> (raw)
In-Reply-To: <6f35fcf9021b2b3d07e434bcd5e8ab678537e378.1462969737.git.mariano.lopez@linux.intel.com>

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


  reply	other threads:[~2016-05-12  9:31 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-11 12:31 [PATCH 0/3] Add extract() method to package manager mariano.lopez
2016-05-11 12:31 ` [PATCH 1/3] package_manager.py: Move opkg_query() outside of Indexer class mariano.lopez
2016-05-12  9:30   ` Joshua G Lock
2016-05-11 12:31 ` [PATCH 2/3] package_manager.py: Add extract() method for opkg and dpkg mariano.lopez
2016-05-12  9:30   ` Joshua G Lock [this message]
2016-05-11 12:31 ` [PATCH 3/3] package_manager.py: Add extract() method for RPM package manager mariano.lopez
2016-05-12  9:31   ` Joshua G Lock
2016-05-12 19:05     ` Mariano Lopez

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1463045458.3794.5.camel@linux.intel.com \
    --to=joshua.g.lock@linux.intel.com \
    --cc=mariano.lopez@linux.intel.com \
    --cc=openembedded-core@lists.openembedded.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox