diff options
Diffstat (limited to 'apkkit/base/index.py')
-rw-r--r-- | apkkit/base/index.py | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/apkkit/base/index.py b/apkkit/base/index.py new file mode 100644 index 0000000..ee0af9f --- /dev/null +++ b/apkkit/base/index.py @@ -0,0 +1,147 @@ +"""Contains the Index class and related helper classes and functions.""" + +from io import BytesIO +import logging +import os +import requests +import tarfile + +from apkkit.base.package import Package + + +INDEX_LOGGER = logging.getLogger(__name__) + + +class Index: + """The base index class.""" + + def __init__(self, packages=None, description=None, url=None, **kwargs): + """Initialise an Index object. + + :param list packages: + The packages available in the repository this index represents. + + :param str description: + (Recommended) The description of the repository this index + represents. Typically, something like "system" or "user". + + :param str url: + (Optional) The URL to download the index from. All other + parameters are ignored if this is specified. + """ + + if url is not None: + self._url = url + resp = requests.get(url) + if resp.status_code != 200: + INDEX_LOGGER.error("could not download %s: %d (%r)", url, + resp.status_code, resp.text) + else: + self._fill_from_index_file(BytesIO(resp.content)) + else: + if packages is None: + raise ValueError("Packages are required.") + self._pkgs = packages + self._desc = description + + if len(kwargs) > 0: + INDEX_LOGGER.warning("unknown kwargs in Index: %r", kwargs) + + @property + def description(self): + """The description of this repository.""" + return self._desc + + @property + def packages(self): + """The packages available in this repository.""" + return list(self._pkgs) + + @property + def origins(self): + """The names of all unique origin packages available in this repo.""" + return {pkg.origin for pkg in self._pkgs} + + def __repr__(self): + if self._url is not None: + return 'Index(url="{url}")'.format(url=self._url) + return 'Index(packages=<{num} packages>, description="{desc}")'.format( + num=len(self._pkgs), desc=self._desc) + + def to_raw(self): + """Serialises this repository information into the APKINDEX format. + + :returns str: The APKINDEX for this package. Unicode str, ready to be + written to a file. + """ + raise NotImplemented("Not yet.") + + def _fill_from_index_file(self, buf): + """Fill this `Index` object from the APKINDEX in `buf`.""" + if len(getattr(self, '_pkgs', list())) > 0: + raise Exception("Attempt to fill an already filled Index") + + pkgs = list() + params = {} + param_map = {'P': 'name', 'V': 'version', 'A': 'arch', 'o': 'origin', + 'T': 'description', 'p': 'provides', 'i': 'install_if', + 'D': 'depends', 'U': 'url', 'I': 'size', 'r': 'replaces', + 'L': 'license', 'q': 'replaces_priority', 'c': 'commit', + 'm': 'maintainer', 't': 'builddate'} + list_keys = {'p', 'D', 'i', 'r'} + + tar = None + + # assumption: "P" is the first line of each package. + try: + tar = tarfile.open(fileobj=buf) + real_buf = tar.extractfile('APKINDEX') + except: + real_buf = buf + + for line in real_buf.readlines(): + if not isinstance(line, str): + line = line.decode('utf-8') + + # Skip comments. + if line[0] == '#': + continue + + # separated by blank line + if line == "\n" and params.get('name', None) is not None: + pkgs.append(Package(**params)) + params.clear() + continue + + if line.find(':') == -1: + INDEX_LOGGER.warning('!!! malformed line? "%s" !!!', 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]] = value.split(' ') + else: + params[param_map[key]] = value + else: + INDEX_LOGGER.info('!!! unrecognised APKINDEX key %s !!!', key) + + self._pkgs = pkgs + + @classmethod + def from_raw(cls, buf): + """Create a new :py:class:`Index` object from an existing APKINDEX. + + :param buf: + The buffer to read from (whether file, BytesIO, etc). + + :returns: + A :py:class:`Index` object with the details from the APKINDEX. + """ + idx = cls(packages=list()) + idx._fill_from_index_file(buf) + return idx + |