summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Wilcox <AWilcox@Wilcox-Tech.com>2015-10-07 21:22:56 -0500
committerAndrew Wilcox <AWilcox@Wilcox-Tech.com>2015-10-07 21:22:56 -0500
commit2230cfbae1d8723330845abf11d40505d904bbec (patch)
tree734022d6a7739707229efc041b11fe94628e8810
parent033db487a62bb2c7660576be2985465d28bc52a5 (diff)
downloadapkkit-2230cfbae1d8723330845abf11d40505d904bbec.tar.gz
apkkit-2230cfbae1d8723330845abf11d40505d904bbec.tar.bz2
apkkit-2230cfbae1d8723330845abf11d40505d904bbec.tar.xz
apkkit-2230cfbae1d8723330845abf11d40505d904bbec.zip
Add initial code for reading in APK files.
-rw-r--r--apkkit/__init__.py0
-rw-r--r--apkkit/base/__init__.py0
-rw-r--r--apkkit/base/package.py158
-rw-r--r--apkkit/io/__init__.py0
-rw-r--r--apkkit/io/apkfile.py10
5 files changed, 168 insertions, 0 deletions
diff --git a/apkkit/__init__.py b/apkkit/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apkkit/__init__.py
diff --git a/apkkit/base/__init__.py b/apkkit/base/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apkkit/base/__init__.py
diff --git a/apkkit/base/package.py b/apkkit/base/package.py
new file mode 100644
index 0000000..87164e3
--- /dev/null
+++ b/apkkit/base/package.py
@@ -0,0 +1,158 @@
+"""Contains the Package class and related helper classes and functions."""
+
+pkginfo_template = """
+# Generated by APK Kit for Adélie Linux
+# {builduser}@{buildhost} {builddate}
+pkgname = {name}
+pkgver = {ver}
+pkgdesc = {desc}
+arch = {arch}
+"""
+
+class Package:
+ """The base package class."""
+
+ def __init__(self, name, version, arch, description=None, url=None, size=0,
+ provides=None, depends=None):
+ """Initialise a package object.
+
+ :param str name:
+ The name of the package.
+
+ :param str version:
+ The version of the package.
+
+ :param str arch:
+ The architecture of the package.
+
+ :param str description:
+ (Recommended) The description of the package. Defaults to the name
+ if not set.
+
+ :param int size:
+ (Recommended) The installed size of the package. You almost always
+ want to set this to something other than 0 if you don't want unhappy
+ users. :)
+
+ :param str url:
+ (Optional) The URL of the homepage for the package.
+
+ :param list provides:
+ (Optional) One or more virtuals that this package provides.
+
+ :param list depends:
+ (Optional) One or more packages that are required to be installed
+ to use this package.
+ """
+
+ self._pkgname = name
+ self._pkgver = version
+ self._pkgdesc = description or name
+ self._url = url
+ self._size = int(size)
+ self._arch = arch
+ self._provides = provides or list()
+ self._depends = depends or list()
+
+ @property
+ def name(self):
+ """The name of the package."""
+ return self._pkgname
+
+ @property
+ def version(self):
+ """The version of the package."""
+ return self._pkgver
+
+ @property
+ def description(self):
+ """The description of the package."""
+ return self._pkgdesc
+
+ @property
+ def url(self):
+ """The URL of the homepage of the package."""
+ return self._url
+
+ @property
+ def size(self):
+ """The installed size of the package in bytes."""
+ return self._size
+
+ @property
+ def arch(self):
+ """The architecture of the package."""
+ return self._arch
+
+ @property
+ def depends(self):
+ """The dependencies of the package."""
+ return self._depends
+
+ def __repr__(self):
+ return 'Package(name="{name}", version="{ver}", arch="{arch}", '\
+ 'description="{desc}", url="{url}", size={size}, '\
+ 'provides={prov}, depends={dep})'.format(
+ name=self._pkgname, ver=self._pkgver, arch=self._arch,
+ desc=self._pkgdesc, prov=self._provides, dep=self._depends,
+ url=self._url, size=self._size)
+
+ def to_pkginfo(self):
+ """Serialises the package's information into the PKGINFO format.
+
+ :returns str: The PKGINFO for this package. Unicode str, ready to be
+ written to a file.
+
+ .. note:: To write a file, see the :py:meth:`.write_pkginfo` helper
+ method.
+ """
+
+ @classmethod
+ def from_pkginfo(cls, buf):
+ """Create a new :py:class:`Package` object from an existing PKGINFO.
+
+ :param buf:
+ The buffer to read from (whether file, StringIO, etc).
+
+ :returns:
+ A :py:class:`Package` object with the details from the PKGINFO.
+
+ :throws ValueError:
+ If a required field is missing from the PKGINFO.
+ """
+
+ params = {}
+ param_map = {'pkgname': 'name', 'pkgver': 'version', 'arch': 'arch',
+ 'pkgdesc': 'description', 'provides': 'provides',
+ 'depend': 'depends', 'url': 'url', 'size': 'size'}
+ list_keys = {'provides', 'depend'}
+
+ params['provides'] = list()
+ params['depends'] = list()
+
+ for line in buf.readlines():
+ # XXX TODO make this better
+ if type(line) != str:
+ line = line.decode('utf-8')
+
+ # Skip comments.
+ if len(line) == 0 or line[0] == '#':
+ continue
+
+ if line.index('=') == -1:
+ print('!!! malformed line? {} !!!'.format(line))
+ continue
+
+ (key, value) = line.split('=', 1)
+ key = key.strip()
+ value = value.strip()
+
+ if key in param_map:
+ if key in list_keys:
+ params[param_map[key]].append(value)
+ else:
+ params[param_map[key]] = value
+ else:
+ print('!!! unrecognised PKGINFO key {} !!!'.format(key))
+
+ return cls(**params)
diff --git a/apkkit/io/__init__.py b/apkkit/io/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/apkkit/io/__init__.py
diff --git a/apkkit/io/apkfile.py b/apkkit/io/apkfile.py
new file mode 100644
index 0000000..327ba08
--- /dev/null
+++ b/apkkit/io/apkfile.py
@@ -0,0 +1,10 @@
+from apkkit.base.package import Package
+import gzip # Not used, but we need to raise ImportError if gzip isn't built.
+import tarfile
+
+class APKFile:
+ """Represents an APK file on disk (or in memory)."""
+
+ def __init__(self, filename, mode='r'):
+ self.tar = tarfile.open(filename, mode)
+ self.package = Package.from_pkginfo(self.tar.extractfile('.PKGINFO'))