|
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
|