Skip to content

Commit ae90431

Browse files
author
James William Pye
committed
Add support for user service files.
Also, raise an exception when the service could not be found. fixes #40
1 parent 07ef3a0 commit ae90431

1 file changed

Lines changed: 78 additions & 37 deletions

File tree

postgresql/clientparameters.py

Lines changed: 78 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@
3939

4040
from . import iri as pg_iri
4141
from . import pgpassfile as pg_pass
42+
from . exceptions import Error
43+
44+
class ClientParameterError(Error):
45+
code = '-*000'
46+
source = '.clientparameters'
47+
class ServiceDoesNotExistError(ClientParameterError):
48+
code = '-*srv'
4249

4350
try:
4451
from getpass import getuser, getpass
@@ -51,8 +58,10 @@ def getuser():
5158
default_port = 5432
5259

5360
pg_service_envvar = 'PGSERVICE'
61+
pg_service_file_envvar = 'PGSERVICEFILE'
5462
pg_sysconfdir_envvar = 'PGSYSCONFDIR'
5563
pg_service_filename = 'pg_service.conf'
64+
pg_service_user_filename = '.pg_service.conf'
5665

5766
# posix
5867
pg_home_passfile = '.pgpass'
@@ -194,8 +203,14 @@ def envvars(environ = os.environ, modifier : "environment variable key modifier"
194203
settings = [
195204
(('settings', v,), environ[k]) for k, v in envvar_settings_map if k in environ
196205
]
206+
207+
# PGSYSCONFDIR based
197208
if pg_sysconfdir_envvar in environ:
198209
yield ('config-pg_sysconfdir', environ[pg_sysconfdir_envvar])
210+
# PGSERVICEFILE based
211+
if pg_service_file_envvar in environ:
212+
yield ('config-pg_service_file', environ[pg_service_file_envvar])
213+
199214
service = modifier('SERVICE')
200215
if service in environ:
201216
yield ('pg_service', environ[service])
@@ -421,46 +436,72 @@ def denormalize_parameters(p):
421436
def x_pq_iri(iri, config):
422437
return denormalize_parameters(pg_iri.parse(iri))
423438

439+
# Lookup service data using the `service_name`
440+
# Be sure to map 'dbname' to 'database'.
424441
def x_pg_service(service_name, config):
425-
"""
426-
Lookup service data using the `service_name`.
442+
service_files = []
427443

428-
Be sure to map 'dbname' to 'database'.
429-
"""
430-
service_file = config.get('pg_service_file')
431-
if service_file is None:
432-
sysconfdir = config.get('pg_sysconfdir')
433-
if sysconfdir:
434-
service_filename = config.get('pg_service_filename', pg_service_filename)
435-
service_file = os.path.join(sysconfdir, service_filename)
436-
if not service_file or not os.path.exists(service_file):
437-
return
438-
439-
cp = configparser.RawConfigParser()
440-
cp.read(service_file)
441-
try:
442-
s = cp.items(service_name)
443-
except configparser.NoSectionError:
444-
# section, indicate with None.
445-
return
446-
447-
for (k, v) in s:
448-
k = k.lower()
449-
if k == 'ldap':
450-
yield ('pg_ldap', ':'.join((k, v)))
451-
elif k == 'pg_service':
452-
# ignore
453-
pass
454-
elif k == 'hostaddr':
455-
# XXX: should yield ipv as well?
456-
yield (('host',), v)
457-
elif k == 'dbname':
458-
yield (('database',), v)
459-
elif k not in pg_service_driver_parameters:
460-
# it's a GUC.
461-
yield (('settings', k), v)
444+
f = config.get('pg_service_file')
445+
if f is not None:
446+
# service file override
447+
service_files.append(f)
448+
else:
449+
# override is not specified, use the user service file
450+
home = os.path.expanduser('~' + getuser())
451+
service_files.append(os.path.join(home, pg_service_user_filename))
452+
453+
# global service file is checked next.
454+
sysconfdir = config.get('pg_sysconfdir')
455+
if sysconfdir:
456+
sf = config.get('pg_service_filename', pg_service_filename)
457+
f = os.path.join(sysconfdir, sf)
458+
# existence will be checked later.
459+
service_files.append(f)
460+
461+
for sf in service_files:
462+
if not os.path.exists(sf):
463+
continue
464+
465+
cp = configparser.RawConfigParser()
466+
cp.read(sf)
467+
try:
468+
s = cp.items(service_name)
469+
except configparser.NoSectionError:
470+
continue
471+
472+
for (k, v) in s:
473+
k = k.lower()
474+
if k == 'ldap':
475+
yield ('pg_ldap', ':'.join((k, v)))
476+
elif k == 'pg_service':
477+
# ignore
478+
pass
479+
elif k == 'hostaddr':
480+
# XXX: should yield ipv as well?
481+
yield (('host',), v)
482+
elif k == 'dbname':
483+
yield (('database',), v)
484+
elif k not in pg_service_driver_parameters:
485+
# it's a GUC.
486+
yield (('settings', k), v)
487+
else:
488+
yield ((k,), v)
462489
else:
463-
yield ((k,), v)
490+
break
491+
else:
492+
# iterator exhausted; service not found
493+
if sum([os.path.exists(x) for x in service_files]):
494+
details = {
495+
'context': ', '.join(service_files),
496+
}
497+
else:
498+
details = {
499+
'hint': "No service files could be found."
500+
}
501+
raise ServiceDoesNotExistError(
502+
'cannot find service named "{0}"'.format(service_name),
503+
details = details
504+
)
464505

465506
def x_pg_ldap(ldap_url, config):
466507
raise NotImplementedError("cannot resolve ldap URLs: " + str(ldap_url))

0 commit comments

Comments
 (0)