Michal Koutný ccf7f1
# This work is licensed under the GNU GPLv2 or later.
Michal Koutný ccf7f1
# See the COPYING file in the top-level directory.
Michal Koutný ccf7f1
Michal Koutný ccf7f1
import configparser
Michal Koutný ccf7f1
import os
Michal Koutný ccf7f1
from logging import getLogger
Michal Koutný ccf7f1
import urllib.parse
Michal Koutný ccf7f1
Michal Koutný ccf7f1
from ._util import listify
Michal Koutný ccf7f1
Michal Koutný ccf7f1
log = getLogger(__name__)
Michal Koutný ccf7f1
Michal Koutný ccf7f1
Michal Koutný ccf7f1
def _parse_hostname(url):
Michal Koutný ccf7f1
    # If http://example.com is passed, netloc=example.com path=""
Michal Koutný ccf7f1
    # If just example.com is passed, netloc="" path=example.com
Michal Koutný ccf7f1
    parsedbits = urllib.parse.urlparse(url)
Michal Koutný ccf7f1
    return parsedbits.netloc or parsedbits.path
Michal Koutný ccf7f1
Michal Koutný ccf7f1
Michal Koutný ccf7f1
def _makedirs(path):
Michal Koutný ccf7f1
    if os.path.exists(os.path.dirname(path)):
Michal Koutný ccf7f1
        return
Michal Koutný ccf7f1
    os.makedirs(os.path.dirname(path), 0o700)
Michal Koutný ccf7f1
Michal Koutný ccf7f1
Michal Koutný ccf7f1
def _default_cache_location(filename):
Michal Koutný ccf7f1
    """
Michal Koutný ccf7f1
    Determine default location for passed xdg filename.
Michal Koutný ccf7f1
    example: ~/.cache/python-bugzilla/bugzillarc
Michal Koutný ccf7f1
    """
Michal Koutný ccf7f1
    return os.path.expanduser("~/.cache/python-bugzilla/%s" % filename)
Michal Koutný ccf7f1
Michal Koutný ccf7f1
Michal Koutný ccf7f1
class _BugzillaRCFile(object):
Michal Koutný ccf7f1
    """
Michal Koutný ccf7f1
    Helper class for interacting with bugzillarc files
Michal Koutný ccf7f1
    """
Michal Koutný ccf7f1
    @staticmethod
Michal Koutný ccf7f1
    def get_default_configpaths():
Michal Koutný ccf7f1
        paths = [
Michal Koutný ccf7f1
            '/etc/bugzillarc',
Michal Koutný ccf7f1
            '~/.bugzillarc',
Michal Koutný ccf7f1
            '~/.config/python-bugzilla/bugzillarc',
Michal Koutný ccf7f1
        ]
Michal Koutný ccf7f1
        return paths
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def __init__(self):
Michal Koutný ccf7f1
        self._cfg = None
Michal Koutný ccf7f1
        self._configpaths = None
Michal Koutný ccf7f1
        self.set_configpaths(None)
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def set_configpaths(self, configpaths):
Michal Koutný ccf7f1
        configpaths = [os.path.expanduser(p) for p in
Michal Koutný ccf7f1
                       listify(configpaths or [])]
Michal Koutný ccf7f1
Michal Koutný ccf7f1
        cfg = configparser.ConfigParser()
Michal Koutný ccf7f1
        read_files = cfg.read(configpaths)
Michal Koutný ccf7f1
        if read_files:
Michal Koutný ccf7f1
            log.info("Found bugzillarc files: %s", read_files)
Michal Koutný ccf7f1
Michal Koutný ccf7f1
        self._cfg = cfg
Michal Koutný ccf7f1
        self._configpaths = configpaths or []
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def get_configpaths(self):
Michal Koutný ccf7f1
        return self._configpaths[:]
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def get_default_url(self):
Michal Koutný ccf7f1
        """
Michal Koutný ccf7f1
        Grab a default URL from bugzillarc [DEFAULT] url=X
Michal Koutný ccf7f1
        """
Michal Koutný ccf7f1
        cfgurl = self._cfg.defaults().get("url", None)
Michal Koutný ccf7f1
        if cfgurl is not None:
Michal Koutný ccf7f1
            log.debug("bugzillarc: found cli url=%s", cfgurl)
Michal Koutný ccf7f1
            return cfgurl
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def parse(self, url):
Michal Koutný ccf7f1
        """
Michal Koutný ccf7f1
        Find the section for the passed URL domain, and return all the fields
Michal Koutný ccf7f1
        """
Michal Koutný ccf7f1
        section = ""
Michal Koutný ccf7f1
        log.debug("bugzillarc: Searching for config section matching %s", url)
Michal Koutný ccf7f1
Michal Koutný ccf7f1
        urlhost = _parse_hostname(url)
Michal Koutný ccf7f1
        for sectionhost in sorted(self._cfg.sections()):
Michal Koutný ccf7f1
            # If the section is just a hostname, make it match
Michal Koutný ccf7f1
            # If the section has a / in it, do a substring match
Michal Koutný ccf7f1
            if "/" not in sectionhost:
Michal Koutný ccf7f1
                if sectionhost == urlhost:
Michal Koutný ccf7f1
                    section = sectionhost
Michal Koutný ccf7f1
            elif sectionhost in url:
Michal Koutný ccf7f1
                section = sectionhost
Michal Koutný ccf7f1
            if section:
Michal Koutný ccf7f1
                log.debug("bugzillarc: Found matching section: %s", section)
Michal Koutný ccf7f1
                break
Michal Koutný ccf7f1
Michal Koutný ccf7f1
        if not section:
Michal Koutný ccf7f1
            log.debug("bugzillarc: No section found")
Michal Koutný ccf7f1
            return {}
Michal Koutný ccf7f1
        return dict(self._cfg.items(section))
Michal Koutný ccf7f1
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def save_api_key(self, url, api_key):
Michal Koutný ccf7f1
        """
Michal Koutný ccf7f1
        Save the API_KEY in the config file. We use the last file
Michal Koutný ccf7f1
        in the configpaths list, which is the one with the highest
Michal Koutný ccf7f1
        precedence.
Michal Koutný ccf7f1
        """
Michal Koutný ccf7f1
        configpaths = self.get_configpaths()
Michal Koutný ccf7f1
        if not configpaths:
Michal Koutný ccf7f1
            return None
Michal Koutný ccf7f1
Michal Koutný ccf7f1
        config_filename = configpaths[-1]
Michal Koutný ccf7f1
        section = _parse_hostname(url)
Michal Koutný ccf7f1
        cfg = configparser.ConfigParser()
Michal Koutný ccf7f1
        cfg.read(config_filename)
Michal Koutný ccf7f1
Michal Koutný ccf7f1
        if section not in cfg.sections():
Michal Koutný ccf7f1
            cfg.add_section(section)
Michal Koutný ccf7f1
Michal Koutný ccf7f1
        cfg.set(section, 'api_key', api_key.strip())
Michal Koutný ccf7f1
Michal Koutný ccf7f1
        _makedirs(config_filename)
Michal Koutný ccf7f1
        with open(config_filename, 'w') as configfile:
Michal Koutný ccf7f1
            cfg.write(configfile)
Michal Koutný ccf7f1
Michal Koutný ccf7f1
        return config_filename
Michal Koutný ccf7f1
Michal Koutný ccf7f1
Michal Koutný ccf7f1
class _BugzillaTokenCache(object):
Michal Koutný ccf7f1
    """
Michal Koutný ccf7f1
    Class for interacting with a .bugzillatoken cache file
Michal Koutný ccf7f1
    """
Michal Koutný ccf7f1
    @staticmethod
Michal Koutný ccf7f1
    def get_default_path():
Michal Koutný ccf7f1
        return _default_cache_location("bugzillatoken")
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def __init__(self):
Michal Koutný ccf7f1
        self._filename = None
Michal Koutný ccf7f1
        self._cfg = None
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def _get_domain(self, url):
Michal Koutný ccf7f1
        domain = urllib.parse.urlparse(url)[1]
Michal Koutný ccf7f1
        if domain and domain not in self._cfg.sections():
Michal Koutný ccf7f1
            self._cfg.add_section(domain)
Michal Koutný ccf7f1
        return domain
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def get_value(self, url):
Michal Koutný ccf7f1
        domain = self._get_domain(url)
Michal Koutný ccf7f1
        if domain and self._cfg.has_option(domain, 'token'):
Michal Koutný ccf7f1
            return self._cfg.get(domain, 'token')
Michal Koutný ccf7f1
        return None
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def set_value(self, url, value):
Michal Koutný ccf7f1
        if self.get_value(url) == value:
Michal Koutný ccf7f1
            return
Michal Koutný ccf7f1
Michal Koutný ccf7f1
        domain = self._get_domain(url)
Michal Koutný ccf7f1
        if value is None:
Michal Koutný ccf7f1
            self._cfg.remove_option(domain, 'token')
Michal Koutný ccf7f1
        else:
Michal Koutný ccf7f1
            self._cfg.set(domain, 'token', value)
Michal Koutný ccf7f1
Michal Koutný ccf7f1
        if self._filename:
Michal Koutný ccf7f1
            _makedirs(self._filename)
Michal Koutný ccf7f1
            with open(self._filename, 'w') as _cfg:
Michal Koutný ccf7f1
                log.debug("Saving to _cfg")
Michal Koutný ccf7f1
                self._cfg.write(_cfg)
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def get_filename(self):
Michal Koutný ccf7f1
        return self._filename
Michal Koutný ccf7f1
Michal Koutný ccf7f1
    def set_filename(self, filename):
Michal Koutný ccf7f1
        log.debug("Using tokenfile=%s", filename)
Michal Koutný ccf7f1
        cfg = configparser.ConfigParser()
Michal Koutný ccf7f1
        if filename:
Michal Koutný ccf7f1
            cfg.read(filename)
Michal Koutný ccf7f1
        self._filename = filename
Michal Koutný ccf7f1
        self._cfg = cfg