1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """
25 Collect settings for an external program from a configuration file.
26 """
27
28 import ConfigParser
29 import user, os.path
30
31 from Biskit.Errors import BiskitError
32 from Biskit import EHandler
33
34 import Biskit.tools as T
35
36
38 pass
39
41 """
42 Change ConfigParser so that it doesn't convert option names to lower case.
43 """
45 return optionstr
46
47
49
50 """
51 ExeConfig
52 =========
53
54 Manage the settings that Executor needs for calling an external
55 program.
56
57 ExeConfig is initialised with a program name and expects to find
58 the configuration for this program in
59 C{ ~/.biskit/exe_|name|.dat }. Only if nothing is found there, it looks
60 for C{ external/defaults/exe_|name|.dat } in the biskit installation
61 folder. If neither of the two files are found, an error is raised
62 (strict=1) or the binary is assumed to be |name| and must be
63 accessible in the search path (strict=0).
64
65
66 Example
67 -------
68
69 The configuration file (exe_name.dat) should look like this::
70
71 ---- start example configuration file ----
72 [BINARY]
73
74 comment=the emacs editor
75 bin=emacs
76 cwd=
77 shell=0
78 shellexe=
79 pipes=0
80 ## Use new environment containing only variables given below
81 replaceEnv=0
82
83 [ENVIRONMENT]
84
85 HOME=
86 EMACS_CONFIG=~/.emacs/config.dat
87 ---- end of example file ----
88
89
90 This example config would ask Executor to look for an executable
91 called 'emacs' in the local search path. Before running it,
92 executor should check that a variable $HOME exists in the local
93 shell environment (or raise an error otherwise) and set the
94 variable $EMACS_CONFIG to the given path.
95
96 The other settings specify how the program call is done (see also
97 Python 2.4 subprocess.Popen() ):
98
99 - cwd ... working directory (empty -- current working directory)
100 - shell ... wrap process in separate shell
101 - shellexe ... which shell (empty -- sh)
102 - pipes ... paste input via STDIN, collect output at STDOUT
103
104 Missing options are reset to their default value; See
105 L{ ExeConfig.reset() }. All entries in section BINARY are put into the
106 name space of the ExeConfig object. That means an ExeConfig object x
107 created from the above file can be used as follows:
108
109 >>> x = ExeConfig( 'emacs' )
110 >>> x.cwd == None
111 >>> True
112 >>> print x.comment
113 >>> the emacs editor
114 """
115
116
117 PATH_CONF = user.home + '/.biskit'
118 PATH_CONF_DEFAULT = os.path.join( T.projectRoot(), 'external/defaults' )
119 SECTION_BIN = 'BINARY'
120 SECTION_ENV = 'ENVIRONMENT'
121
123 """
124 @param name: unique name of the program
125 @type name: str
126 @param strict: insist on a config file exe_name.dat
127 and do not tolerate missing environment variables
128 (default: 1)
129 @type strict: 0|1
130
131 @raise ExeConfigError: if strict==1 and config file incomplete/missing
132 """
133 self.name = name
134
135 self.dat = os.path.join( self.PATH_CONF, 'exe_%s.dat' % name )
136
137 if not os.path.exists( self.dat ):
138 self.dat = os.path.join( self.PATH_CONF_DEFAULT,'exe_%s.dat'%name )
139
140
141 self.dat_found = os.path.exists( self.dat )
142
143 self.strict = strict
144
145 self.env_checked = 0
146
147 if strict and not self.dat_found:
148
149 raise ExeConfigError,\
150 'Could not find configuration file %s for program %s.'\
151 % (self.dat, self.name)
152
153 self.conf = CaseSensitiveConfigParser()
154 self.conf.read( self.dat )
155
156 self.reset()
157 self.update()
158
159
161 """
162 Reset all required parameters. Called at creation
163 """
164
165 self.comment = 'no comment or missing configuration file'
166 self.bin = self.name
167 self.shell = 0
168 self.shellexe = None
169 self.pipes = 0
170 self.cwd = None
171
172 self.replaceEnv = 0
173 self.env = None
174
175
177 """
178 Load settings from associated configuration file (if available).
179 Is automatically called at creation.
180
181 @raise ExeConfigError: if section [BINARY] was not found in the file
182 """
183
184 try:
185 dconf = self.conf.items( self.SECTION_BIN )
186
187 for key, value in dconf:
188
189
190 t = type( self.__dict__.get( key, '' ) )
191
192
193 if value is not '':
194 self.__dict__[ key ] = t( value )
195
196 except ConfigParser.NoSectionError:
197 if self.strict:
198 raise ExeConfigError,\
199 'Could not find BINARY section in %s.' % self.dat
200
201 try:
202 self.env = self.conf.items( self.SECTION_ENV )
203 except:
204 pass
205
206
208 """
209 Validate the path to the binary.
210
211 @raise ExeConfigError: if environment is not fit for running
212 the program
213 """
214 try:
215 self.bin = T.absbinary( self.bin )
216
217 missing = self.update_environment()
218 report = '%s is missing environment variables: %r'\
219 % (self.name, missing )
220
221 if missing and self.strict:
222 raise ExeConfigError, report
223
224 if missing:
225 EHandler.warning( report )
226
227 except IOError, why:
228 raise ExeConfigError, str(why) + ' Check %s!' % self.dat
229
230
232 """
233 Get needed environment variables.
234
235 @return: dictionary with environment for subprocess.Popen
236 OR None, if no environment was specified
237 @rtype: {str:str} OR None
238
239 @raise ExeConfigError: if env was not yet checked by update_environment
240 """
241 if not self.env_checked:
242 raise ExeConfigError, 'Environment not yet checked, validate()!'
243
244 if self.env is None:
245 return None
246
247 r = {}
248 for key,value in self.env:
249 r[ key ] = value
250
251 return r
252
253
255 """
256 Check for missing environment settings.
257
258 @return: names of required but missing environment variables
259 @rtype: [str]
260 """
261 missing = []
262
263 if self.env:
264
265 for i in range( len( self.env) ):
266
267 key, value = self.env[ i ]
268
269 if value is '':
270
271 if os.getenv( key ) is None:
272 missing += [ key ]
273 else:
274 self.env[ i ] = (key, os.getenv( key ) )
275
276 self.env_checked = 1
277
278 return missing
279
280
282 s = 'ExeConfig for %s' % self.name
283 for k,v in self.__dict__.items():
284 s += '\n%10s \t%r' % (k,v)
285 return s
286
289
290
291
292
293
294
295 import Biskit.test as BT
296
297 -class Test(BT.BiskitTest):
298 """ExeConfig test"""
299
301 """ExeConfig test (validate xclock)"""
302
303 x = ExeConfig( 'xclock', strict=1 )
304 x.validate()
305
306 if self.local:
307 print x.bin
308
309 self.assertEquals( True, 'xclock' in x.bin )
310
311
312 if __name__ == '__main__':
313
314 BT.localTest()
315