Skip to content

Commit efdb4f0

Browse files
committed
authfiles: Add a BugzillaRCFile class
Provides a central way to interact with the RC files. Convert a bunch of usage to use explicit APIs for it Signed-off-by: Cole Robinson <[email protected]>
1 parent 2e3717b commit efdb4f0

3 files changed

Lines changed: 131 additions & 103 deletions

File tree

bugzilla/_authfiles.py

Lines changed: 97 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,107 @@
1111

1212
log = getLogger(__name__)
1313

14-
DEFAULT_CONFIGPATHS = [
15-
'/etc/bugzillarc',
16-
'~/.bugzillarc',
17-
'~/.config/python-bugzilla/bugzillarc',
18-
]
1914

15+
def _parse_hostname(url):
16+
# If http://example.com is passed, netloc=example.com path=""
17+
# If just example.com is passed, netloc="" path=example.com
18+
parsedbits = urlparse(url)
19+
return parsedbits.netloc or parsedbits.path
2020

21-
def open_bugzillarc(configpaths=-1):
22-
if configpaths == -1:
23-
configpaths = DEFAULT_CONFIGPATHS[:]
2421

25-
# pylint: disable=protected-access
26-
configpaths = [os.path.expanduser(p) for p in
27-
listify(configpaths)]
28-
# pylint: enable=protected-access
29-
cfg = ConfigParser()
30-
read_files = cfg.read(configpaths)
31-
if not read_files:
32-
return
22+
def _default_location(filename, kind):
23+
"""
24+
Determine default location for filename, like 'bugzillacookies'. If
25+
old style ~/.bugzillacookies exists, we use that, otherwise we
26+
use ~/.cache/python-bugzilla/bugzillacookies.
27+
Same for bugzillatoken and bugzillarc
28+
"""
29+
homepath = os.path.expanduser("~/.%s" % filename)
30+
xdgpath = os.path.expanduser("~/.%s/python-bugzilla/%s" % (kind, filename))
31+
if os.path.exists(xdgpath):
32+
return xdgpath
33+
if os.path.exists(homepath):
34+
return homepath
3335

34-
log.info("Found bugzillarc files: %s", read_files)
35-
return cfg
36+
if not os.path.exists(os.path.dirname(xdgpath)):
37+
os.makedirs(os.path.dirname(xdgpath), 0o700)
38+
return xdgpath
39+
40+
41+
def _default_cache_location(filename):
42+
return _default_location(filename, 'cache')
43+
44+
45+
def _default_config_location(filename):
46+
return _default_location(filename, 'config')
47+
48+
49+
class _BugzillaRCFile(object):
50+
"""
51+
Helper class for interacting with bugzillarc files
52+
"""
53+
@staticmethod
54+
def get_default_configpaths():
55+
paths = [
56+
'/etc/bugzillarc',
57+
'~/.bugzillarc',
58+
'~/.config/python-bugzilla/bugzillarc',
59+
]
60+
return paths
61+
62+
def __init__(self):
63+
self._cfg = None
64+
self._configpaths = None
65+
self.set_configpaths(None)
66+
67+
def set_configpaths(self, configpaths):
68+
configpaths = [os.path.expanduser(p) for p in
69+
listify(configpaths or [])]
70+
71+
cfg = ConfigParser()
72+
read_files = cfg.read(configpaths)
73+
if read_files:
74+
log.info("Found bugzillarc files: %s", read_files)
75+
76+
self._cfg = cfg
77+
self._configpaths = configpaths or []
78+
79+
def get_configpaths(self):
80+
return self._configpaths[:]
81+
82+
def get_default_url(self):
83+
"""
84+
Grab a default URL from bugzillarc [DEFAULT] url=X
85+
"""
86+
cfgurl = self._cfg.defaults().get("url", None)
87+
if cfgurl is not None:
88+
log.debug("bugzillarc: found cli url=%s", cfgurl)
89+
return cfgurl
90+
91+
def parse(self, url):
92+
"""
93+
Find the section for the passed URL domain, and return all the fields
94+
"""
95+
section = ""
96+
log.debug("bugzillarc: Searching for config section matching %s", url)
97+
98+
urlhost = _parse_hostname(url)
99+
for sectionhost in sorted(self._cfg.sections()):
100+
# If the section is just a hostname, make it match
101+
# If the section has a / in it, do a substring match
102+
if "/" not in sectionhost:
103+
if sectionhost == urlhost:
104+
section = sectionhost
105+
elif sectionhost in url:
106+
section = sectionhost
107+
if section:
108+
log.debug("bugzillarc: Found matching section: %s", section)
109+
break
110+
111+
if not section:
112+
log.debug("bugzillarc: No section found")
113+
return {}
114+
return dict(self._cfg.items(section))
36115

37116

38117
class _BugzillaTokenCache(object):
@@ -86,40 +165,6 @@ def set_filename(self, filename):
86165
self._cfg = cfg
87166

88167

89-
def _parse_hostname(url):
90-
# If http://example.com is passed, netloc=example.com path=""
91-
# If just example.com is passed, netloc="" path=example.com
92-
parsedbits = urlparse(url)
93-
return parsedbits.netloc or parsedbits.path
94-
95-
96-
def _default_location(filename, kind):
97-
"""
98-
Determine default location for filename, like 'bugzillacookies'. If
99-
old style ~/.bugzillacookies exists, we use that, otherwise we
100-
use ~/.cache/python-bugzilla/bugzillacookies.
101-
Same for bugzillatoken and bugzillarc
102-
"""
103-
homepath = os.path.expanduser("~/.%s" % filename)
104-
xdgpath = os.path.expanduser("~/.%s/python-bugzilla/%s" % (kind, filename))
105-
if os.path.exists(xdgpath):
106-
return xdgpath
107-
if os.path.exists(homepath):
108-
return homepath
109-
110-
if not os.path.exists(os.path.dirname(xdgpath)):
111-
os.makedirs(os.path.dirname(xdgpath), 0o700)
112-
return xdgpath
113-
114-
115-
def _default_cache_location(filename):
116-
return _default_location(filename, 'cache')
117-
118-
119-
def _default_config_location(filename):
120-
return _default_location(filename, 'config')
121-
122-
123168
def _save_api_key(url, api_key, configpaths):
124169
"""
125170
Save the API_KEY in the config file.

bugzilla/_cli.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,6 @@ def open_without_clobber(name, *args):
6666
return fobj
6767

6868

69-
def get_default_url():
70-
"""
71-
Grab a default URL from bugzillarc [DEFAULT] url=X
72-
"""
73-
from bugzilla._authfiles import open_bugzillarc
74-
cfg = open_bugzillarc()
75-
if cfg:
76-
cfgurl = cfg.defaults().get("url", None)
77-
if cfgurl is not None:
78-
log.debug("bugzillarc: found cli url=%s", cfgurl)
79-
return cfgurl
80-
return DEFAULT_BZ
81-
82-
8369
def setup_logging(debug, verbose):
8470
handler = StreamHandler(sys.stderr)
8571
handler.setFormatter(Formatter(
@@ -106,7 +92,9 @@ def _setup_root_parser():
10692
epilog = 'Try "bugzilla COMMAND --help" for command-specific help.'
10793
p = argparse.ArgumentParser(epilog=epilog)
10894

109-
default_url = get_default_url()
95+
default_url = bugzilla.Bugzilla.get_rcfile_default_url()
96+
if not default_url:
97+
default_url = DEFAULT_BZ
11098

11199
# General bugzilla connection options
112100
p.add_argument('--bugzilla', default=default_url,

bugzilla/base.py

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@
1515

1616
from io import BytesIO
1717

18-
from ._authfiles import (DEFAULT_CONFIGPATHS, open_bugzillarc,
19-
_BugzillaCookieCache, _BugzillaTokenCache,
20-
_parse_hostname, _save_api_key)
18+
from ._authfiles import (_BugzillaRCFile,
19+
_BugzillaCookieCache, _BugzillaTokenCache, _save_api_key)
2120
from .apiversion import __version__
2221
from ._backendxmlrpc import _BackendXMLRPC
2322
from ._compatimports import Mapping, urlparse, urlunparse, parse_qsl
@@ -161,6 +160,18 @@ def fix_url(url):
161160
log.debug("Generated fixed URL: %s", newurl)
162161
return newurl
163162

163+
@staticmethod
164+
def get_rcfile_default_url():
165+
"""
166+
Helper to check all the default bugzillarc file paths for
167+
a [DEFAULT] url=X section, and if found, return it.
168+
"""
169+
configpaths = _BugzillaRCFile.get_default_configpaths()
170+
rcfile = _BugzillaRCFile()
171+
rcfile.set_configpaths(configpaths)
172+
return rcfile.get_default_url()
173+
174+
164175
def __init__(self, url=-1, user=None, password=None, cookiefile=-1,
165176
sslverify=True, tokenfile=-1, use_creds=True, api_key=None,
166177
cert=None, configpaths=-1, basic_auth=False):
@@ -206,12 +217,12 @@ def __init__(self, url=-1, user=None, password=None, cookiefile=-1,
206217

207218
self._backend = None
208219
self._session = None
209-
self._cookiecache = None
210220
self._sslverify = sslverify
211221
self._cache = _BugzillaAPICache()
212222
self._bug_autorefresh = False
213223
self._is_redhat_bugzilla = False
214224

225+
self._rcfile = _BugzillaRCFile()
215226
self._cookiecache = _BugzillaCookieCache()
216227
self._tokencache = _BugzillaTokenCache()
217228

@@ -226,12 +237,12 @@ def __init__(self, url=-1, user=None, password=None, cookiefile=-1,
226237
if tokenfile == -1:
227238
tokenfile = self._tokencache.get_default_path()
228239
if configpaths == -1:
229-
configpaths = DEFAULT_CONFIGPATHS[:]
240+
configpaths = _BugzillaRCFile.get_default_configpaths()
230241

231242
self._setcookiefile(cookiefile)
232243
self._settokenfile(tokenfile)
244+
self._setconfigpath(configpaths)
233245

234-
self.configpath = configpaths
235246
self._basic_auth = basic_auth
236247

237248
if url:
@@ -341,19 +352,16 @@ def _get_api_aliases(self):
341352
for f in self._get_field_aliases() if f.is_api]
342353

343354

344-
###################
355+
#################
345356
# Auth handling #
346-
###################
357+
#################
347358

348359
def _getcookiefile(self):
349360
return self._cookiecache.get_filename()
350-
351361
def _delcookiefile(self):
352362
self._setcookiefile(None)
353-
354363
def _setcookiefile(self, cookiefile):
355364
self._cookiecache.set_filename(cookiefile)
356-
357365
cookiefile = property(_getcookiefile, _setcookiefile, _delcookiefile)
358366

359367
def _gettokenfile(self):
@@ -364,6 +372,14 @@ def _deltokenfile(self):
364372
self._settokenfile(None)
365373
tokenfile = property(_gettokenfile, _settokenfile, _deltokenfile)
366374

375+
def _getconfigpath(self):
376+
return self._rcfile.get_configpaths()
377+
def _setconfigpath(self, configpaths):
378+
return self._rcfile.set_configpaths(configpaths)
379+
def _delconfigpath(self):
380+
return self._rcfile.set_configpaths(None)
381+
configpath = property(_getconfigpath, _setconfigpath, _delconfigpath)
382+
367383

368384
#############################
369385
# Login/connection handling #
@@ -402,32 +418,11 @@ def readconfig(self, configpath=None, overwrite=True):
402418
:param overwrite: If True, bugzillarc will clobber any already
403419
set self.user/password/api_key/cert value.
404420
"""
405-
cfg = open_bugzillarc(configpath or self.configpath)
406-
if not cfg:
407-
return
408-
409-
section = ""
410-
log.debug("bugzillarc: Searching for config section matching %s",
411-
self.url)
412-
413-
urlhost = _parse_hostname(self.url)
414-
for sectionhost in sorted(cfg.sections()):
415-
# If the section is just a hostname, make it match
416-
# If the section has a / in it, do a substring match
417-
if "/" not in sectionhost:
418-
if sectionhost == urlhost:
419-
section = sectionhost
420-
elif sectionhost in self.url:
421-
section = sectionhost
422-
if section:
423-
log.debug("bugzillarc: Found matching section: %s", section)
424-
break
425-
426-
if not section:
427-
log.debug("bugzillarc: No section found")
428-
return
421+
if configpath:
422+
self._setconfigpath(configpath)
423+
data = self._rcfile.parse(self.url)
429424

430-
for key, val in cfg.items(section):
425+
for key, val in data.items():
431426
if key == "api_key" and (overwrite or not self.api_key):
432427
log.debug("bugzillarc: setting api_key")
433428
self.api_key = val

0 commit comments

Comments
 (0)