diff options
author | Mariano Lopez <mariano.lopez@linux.intel.com> | 2016-05-12 11:28:13 +0000 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-05-14 23:05:11 +0100 |
commit | b372a828182b924a8118c6cf4c7b45a7a093704b (patch) | |
tree | a80234d0a6264eb60abae8f89461f739aa8def83 /meta/lib/oe/package_manager.py | |
parent | c5aa5246e0177e2a7c08891c690479d94cf04c0d (diff) | |
download | poky-b372a828182b924a8118c6cf4c7b45a7a093704b.tar.gz |
package_manager.py: Add extract() method for opkg and dpkg
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. Also set default values to avoid UnboundLocalError
[YOCTO #9569]
(From OE-Core rev: 7d214b34e11dc57316ed5c1c7747c4601286f6d2)
Signed-off-by: Mariano Lopez <mariano.lopez@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib/oe/package_manager.py')
-rw-r--r-- | meta/lib/oe/package_manager.py | 140 |
1 files changed, 134 insertions, 6 deletions
diff --git a/meta/lib/oe/package_manager.py b/meta/lib/oe/package_manager.py index 427518da68..f5517a4aae 100644 --- a/meta/lib/oe/package_manager.py +++ b/meta/lib/oe/package_manager.py | |||
@@ -35,9 +35,12 @@ when the packages are in deb or ipk format. | |||
35 | def opkg_query(cmd_output): | 35 | def opkg_query(cmd_output): |
36 | verregex = re.compile(' \([=<>]* [^ )]*\)') | 36 | verregex = re.compile(' \([=<>]* [^ )]*\)') |
37 | output = dict() | 37 | output = dict() |
38 | pkg = "" | ||
39 | arch = "" | ||
40 | ver = "" | ||
38 | filename = "" | 41 | filename = "" |
39 | dep = [] | 42 | dep = [] |
40 | pkg = "" | 43 | pkgarch = "" |
41 | for line in cmd_output.splitlines(): | 44 | for line in cmd_output.splitlines(): |
42 | line = line.rstrip() | 45 | line = line.rstrip() |
43 | if ':' in line: | 46 | if ':' in line: |
@@ -47,8 +50,10 @@ def opkg_query(cmd_output): | |||
47 | arch = line.split(": ")[1] | 50 | arch = line.split(": ")[1] |
48 | elif line.startswith("Version: "): | 51 | elif line.startswith("Version: "): |
49 | ver = line.split(": ")[1] | 52 | ver = line.split(": ")[1] |
50 | elif line.startswith("File: "): | 53 | elif line.startswith("File: ") or line.startswith("Filename:"): |
51 | filename = line.split(": ")[1] | 54 | filename = line.split(": ")[1] |
55 | if "/" in filename: | ||
56 | filename = os.path.basename(filename) | ||
52 | elif line.startswith("Depends: "): | 57 | elif line.startswith("Depends: "): |
53 | depends = verregex.sub('', line.split(": ")[1]) | 58 | depends = verregex.sub('', line.split(": ")[1]) |
54 | for depend in depends.split(", "): | 59 | for depend in depends.split(", "): |
@@ -57,16 +62,23 @@ def opkg_query(cmd_output): | |||
57 | recommends = verregex.sub('', line.split(": ")[1]) | 62 | recommends = verregex.sub('', line.split(": ")[1]) |
58 | for recommend in recommends.split(", "): | 63 | for recommend in recommends.split(", "): |
59 | dep.append("%s [REC]" % recommend) | 64 | dep.append("%s [REC]" % recommend) |
60 | else: | 65 | elif line.startswith("PackageArch: "): |
66 | pkgarch = line.split(": ")[1] | ||
67 | |||
68 | # When there is a blank line save the package information | ||
69 | elif not line: | ||
61 | # IPK doesn't include the filename | 70 | # IPK doesn't include the filename |
62 | if not filename: | 71 | if not filename: |
63 | filename = "%s_%s_%s.ipk" % (pkg, ver, arch) | 72 | filename = "%s_%s_%s.ipk" % (pkg, ver, arch) |
64 | if pkg: | 73 | if pkg: |
65 | output[pkg] = {"arch":arch, "ver":ver, | 74 | output[pkg] = {"arch":arch, "ver":ver, |
66 | "filename":filename, "deps": dep } | 75 | "filename":filename, "deps": dep, "pkgarch":pkgarch } |
67 | pkg = "" | 76 | pkg = "" |
77 | arch = "" | ||
78 | ver = "" | ||
68 | filename = "" | 79 | filename = "" |
69 | dep = [] | 80 | dep = [] |
81 | pkgarch = "" | ||
70 | 82 | ||
71 | if pkg: | 83 | if pkg: |
72 | if not filename: | 84 | if not filename: |
@@ -1397,7 +1409,70 @@ class RpmPM(PackageManager): | |||
1397 | bb.utils.remove(f, True) | 1409 | bb.utils.remove(f, True) |
1398 | 1410 | ||
1399 | 1411 | ||
1400 | class OpkgPM(PackageManager): | 1412 | class OpkgDpkgPM(PackageManager): |
1413 | """ | ||
1414 | This is an abstract class. Do not instantiate this directly. | ||
1415 | """ | ||
1416 | def __init__(self, d): | ||
1417 | super(OpkgDpkgPM, self).__init__(d) | ||
1418 | |||
1419 | """ | ||
1420 | Returns a dictionary with the package info. | ||
1421 | |||
1422 | This method extracts the common parts for Opkg and Dpkg | ||
1423 | """ | ||
1424 | def package_info(self, pkg, cmd): | ||
1425 | |||
1426 | try: | ||
1427 | output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) | ||
1428 | except subprocess.CalledProcessError as e: | ||
1429 | bb.fatal("Unable to list available packages. Command '%s' " | ||
1430 | "returned %d:\n%s" % (cmd, e.returncode, e.output)) | ||
1431 | return opkg_query(output) | ||
1432 | |||
1433 | """ | ||
1434 | Returns the path to a tmpdir where resides the contents of a package. | ||
1435 | |||
1436 | Deleting the tmpdir is responsability of the caller. | ||
1437 | |||
1438 | This method extracts the common parts for Opkg and Dpkg | ||
1439 | """ | ||
1440 | def extract(self, pkg, pkg_path): | ||
1441 | |||
1442 | ar_cmd = bb.utils.which(os.getenv("PATH"), "ar") | ||
1443 | tar_cmd = bb.utils.which(os.getenv("PATH"), "tar") | ||
1444 | |||
1445 | if not os.path.isfile(pkg_path): | ||
1446 | bb.fatal("Unable to extract package for '%s'." | ||
1447 | "File %s doesn't exists" % (pkg, pkg_path)) | ||
1448 | |||
1449 | tmp_dir = tempfile.mkdtemp() | ||
1450 | current_dir = os.getcwd() | ||
1451 | os.chdir(tmp_dir) | ||
1452 | |||
1453 | try: | ||
1454 | cmd = "%s x %s" % (ar_cmd, pkg_path) | ||
1455 | output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) | ||
1456 | cmd = "%s xf data.tar.*" % tar_cmd | ||
1457 | output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) | ||
1458 | except subprocess.CalledProcessError as e: | ||
1459 | bb.utils.remove(tmp_dir, recurse=True) | ||
1460 | bb.fatal("Unable to extract %s package. Command '%s' " | ||
1461 | "returned %d:\n%s" % (pkg_path, cmd, e.returncode, e.output)) | ||
1462 | except OSError as e: | ||
1463 | bb.utils.remove(tmp_dir, recurse=True) | ||
1464 | bb.fatal("Unable to extract %s package. Command '%s' " | ||
1465 | "returned %d:\n%s at %s" % (pkg_path, cmd, e.errno, e.strerror, e.filename)) | ||
1466 | |||
1467 | bb.note("Extracted %s to %s" % (pkg_path, tmp_dir)) | ||
1468 | bb.utils.remove(os.path.join(tmp_dir, "debian-binary")) | ||
1469 | bb.utils.remove(os.path.join(tmp_dir, "control.tar.gz")) | ||
1470 | os.chdir(current_dir) | ||
1471 | |||
1472 | return tmp_dir | ||
1473 | |||
1474 | |||
1475 | class OpkgPM(OpkgDpkgPM): | ||
1401 | def __init__(self, d, target_rootfs, config_file, archs, task_name='target'): | 1476 | def __init__(self, d, target_rootfs, config_file, archs, task_name='target'): |
1402 | super(OpkgPM, self).__init__(d) | 1477 | super(OpkgPM, self).__init__(d) |
1403 | 1478 | ||
@@ -1732,8 +1807,34 @@ class OpkgPM(PackageManager): | |||
1732 | self.opkg_dir, | 1807 | self.opkg_dir, |
1733 | symlinks=True) | 1808 | symlinks=True) |
1734 | 1809 | ||
1810 | """ | ||
1811 | Returns a dictionary with the package info. | ||
1812 | """ | ||
1813 | def package_info(self, pkg): | ||
1814 | cmd = "%s %s info %s" % (self.opkg_cmd, self.opkg_args, pkg) | ||
1815 | return super(OpkgPM, self).package_info(pkg, cmd) | ||
1816 | |||
1817 | """ | ||
1818 | Returns the path to a tmpdir where resides the contents of a package. | ||
1819 | |||
1820 | Deleting the tmpdir is responsability of the caller. | ||
1821 | """ | ||
1822 | def extract(self, pkg): | ||
1823 | pkg_info = self.package_info(pkg) | ||
1824 | if not pkg_info: | ||
1825 | bb.fatal("Unable to get information for package '%s' while " | ||
1826 | "trying to extract the package." % pkg) | ||
1827 | |||
1828 | pkg_arch = pkg_info[pkg]["arch"] | ||
1829 | pkg_filename = pkg_info[pkg]["filename"] | ||
1830 | pkg_path = os.path.join(self.deploy_dir, pkg_arch, pkg_filename) | ||
1831 | |||
1832 | tmp_dir = super(OpkgPM, self).extract(pkg, pkg_path) | ||
1833 | bb.utils.remove(os.path.join(tmp_dir, "data.tar.gz")) | ||
1834 | |||
1835 | return tmp_dir | ||
1735 | 1836 | ||
1736 | class DpkgPM(PackageManager): | 1837 | class DpkgPM(OpkgDpkgPM): |
1737 | def __init__(self, d, target_rootfs, archs, base_archs, apt_conf_dir=None): | 1838 | def __init__(self, d, target_rootfs, archs, base_archs, apt_conf_dir=None): |
1738 | super(DpkgPM, self).__init__(d) | 1839 | super(DpkgPM, self).__init__(d) |
1739 | self.target_rootfs = target_rootfs | 1840 | self.target_rootfs = target_rootfs |
@@ -1744,6 +1845,7 @@ class DpkgPM(PackageManager): | |||
1744 | self.apt_conf_dir = apt_conf_dir | 1845 | self.apt_conf_dir = apt_conf_dir |
1745 | self.apt_conf_file = os.path.join(self.apt_conf_dir, "apt.conf") | 1846 | self.apt_conf_file = os.path.join(self.apt_conf_dir, "apt.conf") |
1746 | self.apt_get_cmd = bb.utils.which(os.getenv('PATH'), "apt-get") | 1847 | self.apt_get_cmd = bb.utils.which(os.getenv('PATH'), "apt-get") |
1848 | self.apt_cache_cmd = bb.utils.which(os.getenv('PATH'), "apt-cache") | ||
1747 | 1849 | ||
1748 | self.apt_args = d.getVar("APT_ARGS", True) | 1850 | self.apt_args = d.getVar("APT_ARGS", True) |
1749 | 1851 | ||
@@ -2027,6 +2129,32 @@ class DpkgPM(PackageManager): | |||
2027 | def list_installed(self): | 2129 | def list_installed(self): |
2028 | return DpkgPkgsList(self.d, self.target_rootfs).list_pkgs() | 2130 | return DpkgPkgsList(self.d, self.target_rootfs).list_pkgs() |
2029 | 2131 | ||
2132 | """ | ||
2133 | Returns a dictionary with the package info. | ||
2134 | """ | ||
2135 | def package_info(self, pkg): | ||
2136 | cmd = "%s show %s" % (self.apt_cache_cmd, pkg) | ||
2137 | return super(DpkgPM, self).package_info(pkg, cmd) | ||
2138 | |||
2139 | """ | ||
2140 | Returns the path to a tmpdir where resides the contents of a package. | ||
2141 | |||
2142 | Deleting the tmpdir is responsability of the caller. | ||
2143 | """ | ||
2144 | def extract(self, pkg): | ||
2145 | pkg_info = self.package_info(pkg) | ||
2146 | if not pkg_info: | ||
2147 | bb.fatal("Unable to get information for package '%s' while " | ||
2148 | "trying to extract the package." % pkg) | ||
2149 | |||
2150 | pkg_arch = pkg_info[pkg]["pkgarch"] | ||
2151 | pkg_filename = pkg_info[pkg]["filename"] | ||
2152 | pkg_path = os.path.join(self.deploy_dir, pkg_arch, pkg_filename) | ||
2153 | |||
2154 | tmp_dir = super(DpkgPM, self).extract(pkg, pkg_path) | ||
2155 | bb.utils.remove(os.path.join(tmp_dir, "data.tar.xz")) | ||
2156 | |||
2157 | return tmp_dir | ||
2030 | 2158 | ||
2031 | def generate_index_files(d): | 2159 | def generate_index_files(d): |
2032 | classes = d.getVar('PACKAGE_CLASSES', True).replace("package_", "").split() | 2160 | classes = d.getVar('PACKAGE_CLASSES', True).replace("package_", "").split() |