3939
4040from . import iri as pg_iri
4141from . 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
4350try :
4451 from getpass import getuser , getpass
@@ -51,8 +58,10 @@ def getuser():
5158default_port = 5432
5259
5360pg_service_envvar = 'PGSERVICE'
61+ pg_service_file_envvar = 'PGSERVICEFILE'
5462pg_sysconfdir_envvar = 'PGSYSCONFDIR'
5563pg_service_filename = 'pg_service.conf'
64+ pg_service_user_filename = '.pg_service.conf'
5665
5766# posix
5867pg_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):
421436def 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'.
424441def 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
465506def x_pg_ldap (ldap_url , config ):
466507 raise NotImplementedError ("cannot resolve ldap URLs: " + str (ldap_url ))
0 commit comments