chiark / gitweb /
cgi.py: Set the default static URL prefix from user's `SCRIPT_NAME'.
[chopwood] / config.py
1 ### -*-python-*-
2 ###
3 ### Configuration handling
4 ###
5 ### (c) 2013 Mark Wooding
6 ###
7
8 ###----- Licensing notice ---------------------------------------------------
9 ###
10 ### This file is part of Chopwood: a password-changing service.
11 ###
12 ### Chopwood is free software; you can redistribute it and/or modify
13 ### it under the terms of the GNU Affero General Public License as
14 ### published by the Free Software Foundation; either version 3 of the
15 ### License, or (at your option) any later version.
16 ###
17 ### Chopwood is distributed in the hope that it will be useful,
18 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ### GNU Affero General Public License for more details.
21 ###
22 ### You should have received a copy of the GNU Affero General Public
23 ### License along with Chopwood; if not, see
24 ### <http://www.gnu.org/licenses/>.
25
26 from __future__ import with_statement
27
28 import os as OS; ENV = OS.environ
29 import output as O; OUT = O.OUT
30 import sys as SYS
31 import types as TY
32
33 from auto import PACKAGE, VERSION
34
35 ### Configuration is done by interpreting a file of Python code.  We expect
36 ### the code to define a number of variables in its global scope.  We import
37 ### a number of identifiers (named in the `EXPORT' list) to this module, and
38 ### also our entire parent module as `chpwd'.
39
40 ## Names which ought to be exported to the configuration module.
41 _EXPORT = {}
42
43 ## The configuration module.
44 CFG = TY.ModuleType('chpwd_config')
45
46 ## A list of hooks to call once configuration is complete.
47 _HOOKS = []
48 def hook(func):
49   """Decorator for post-configuration hooks."""
50   _HOOKS.append(func)
51   return func
52
53 ## A suitable set of defaults.
54 DEFAULTS = {}
55
56 def export(*names, **kw):
57   """
58   Export the names to the configuration module from the caller's environment.
59   """
60
61   ## Find the caller's global environment.  Please don't try this at home.
62   try: raise Exception
63   except: tb = SYS.exc_info()[2]
64   env = tb.tb_frame.f_back.f_globals
65
66   ## Export things.
67   for name in names:
68     _EXPORT[name] = env[name]
69   _EXPORT.update(kw)
70
71 ## Some things to export for sure.
72 export('PACKAGE', 'VERSION', 'ENV', CONF = SYS.modules[__name__])
73
74 def loadconfig(config):
75   """
76   Load the configuration, populating the `CFG' module with settings.
77   """
78
79   ## Make a new module for the configuration, and import ourselves into it.
80   d = CFG.__dict__
81   d.update(_EXPORT)
82   d.update(DEFAULTS)
83
84   ## And run the configuration code.
85   try:
86     with open(config) as f:
87       exec f in d
88   except IOError, e:
89     OUT.warn("couldn't open configuration file `%s': %s" %
90              (config, e.strerror))
91
92   ## Run the hooks.
93   for func in _HOOKS:
94     func()
95
96 ###----- That's all, folks --------------------------------------------------