1
2
3
4 """This module defines the PysqlConf class
5 that handles all pysql configuration stuff
6 @author: Sébastien Renard (sebastien.renard@digitalfox.org)
7 @license: GNU GPL V3
8 """
9
10
11 import sys
12 import os
13 from os.path import expandvars, join
14 import cPickle
15 from ConfigParser import ConfigParser
16 import readline
17
18
19 from pysqlexception import PysqlException
20 from pysqlcolor import BOLD, CYAN, GREEN, RED, RESET
21
23 """ Handles configuration stuff"""
24
25
26 configInstance=None
27
29 """Config instance creation. Read the config file"""
30
31 if os.name=="nt":
32
33 basePath=join(expandvars("$APPDATA"), "pysql")
34 else:
35 basePath=join(expandvars("$HOME"), ".pysql")
36
37
38 if not self.__isReadWrite(basePath):
39 os.mkdir(basePath)
40
41
42 self.configParser=None
43
44
45 self.configPath=join(basePath, "pysqlrc")
46
47
48 self.cachePath=join(basePath, "pysqlcache")
49
50
51 self.historyPath=join(basePath, "pysqlhistory")
52
53
54 self.sqlLibPath=join(basePath, "pysqlsqllibrary")
55
56
57 self.changed=False
58
59
60 self.completeLists={}
61
62
63 self.sqlLibrary={}
64
65
66 try:
67 self.completeLists=cPickle.load(file(self.cachePath))
68 except Exception, e:
69
70 pass
71
72
73 try:
74 readline.read_history_file(self.historyPath)
75 except Exception, e:
76
77 pass
78
79
80 try:
81 self.sqlLibrary=cPickle.load(file(self.sqlLibPath))
82 except Exception, e:
83
84 pass
85
86
87 self.default={
88 "case_sensitive" : "no",
89 "completionlistsize" : 100,
90 "fetchsize" : 30,
91 "termwidth" : "auto",
92 "widthmin" : 5,
93 "transpose" : "no",
94 "colsep" : "space",
95 "shrink" : "yes",
96 "echo" : "no",
97 "unit" : "mb",
98 "graph_program" : "auto",
99 "graph_format" : "png",
100 "graph_fontname" : "courier",
101 "graph_fontsize" : "10.0",
102 "graph_fontcolor" : "black",
103 "graph_tablecolor" : "ivory",
104 "graph_linkcolor" : "black",
105 "graph_indexcolor" : "skyblue",
106 "graph_bordercolor" : "black",
107 "graph_linklabel" : "off",
108 "graph_depmaxdepth" : 8,
109 "graph_depmaxnodes" : 100,
110 "graph_viewer" : "auto"
111 }
112
113
114
115 if self.__isReadWrite(self.configPath) and sys.stdin.isatty() and sys.stdout.isatty():
116 print CYAN+_("Using config file %s") % self.configPath + RESET
117
118
119 self.configParser=ConfigParser()
120 try:
121 self.configParser.readfp(open(self.configPath))
122 except Exception, e:
123
124 try:
125 file(self.configPath, "w")
126 except Exception, e:
127 print RED+BOLD+_("Failed to create personnal configuration file")
128 print "%s" % e + RESET
129
130
131 self.codec=None
132
139 getConfig=classmethod(getConfig)
140
141 - def get(self, key):
142 """ Gets the value of the parameter key
143 @param key: parameter name
144 @type key: string
145 @return: str or int (if cast if possible)
146 """
147 key=key.lower()
148 if self.configParser is not None:
149 try:
150 value=self.configParser.get("PYSQL", key)
151 except Exception:
152 value=self.getDefault(key)
153 else:
154 value=self.getDefault(key)
155
156
157 try:
158 value=int(value)
159 except (ValueError, TypeError):
160 try:
161 value=float(value)
162 except (ValueError, TypeError):
163 pass
164 return value
165
167 """Gets all defined parameters
168 @return: list of (key, userValue, defaultValue)
169 """
170 result={}
171
172 if self.configParser is not None:
173 if self.configParser.has_section("PYSQL"):
174 all=self.configParser.items("PYSQL")
175 if all is not None:
176 for (key, value) in all:
177
178 try:
179 value=int(value)
180 except (ValueError, TypeError):
181 pass
182 result[key]=[value, ""]
183
184 for (key, value) in self.default.items():
185 if result.has_key(key):
186 result[key]=[result[key][0], value]
187 else:
188 result[key]=["", value]
189
190
191 result=[[i[0]]+i[1] for i in result.items()]
192
193 result.sort()
194 return result
195
197 """Returns the default value for a parameter. If no default value is defined, return None"""
198 if self.default.has_key(key):
199 return self.default[key]
200 else:
201 print "(DEBUG) Key %s has no default value !" % key
202 return None
203
204 - def verify(self, key, value):
205 """Checks if the key has correct value
206 It does not update the value.
207 @param key: key parameter to be tested
208 @param value: value to be tested
209 @return: True if value is correct, else False"""
210
211 if isinstance(value, str):
212 value=os.path.expandvars(value)
213
214
215 if key=="termwidth" and value=="auto":
216 return True
217 elif key in ("termwidth",
218 "fetchsize",
219 "widthmin",
220 "completionlistsize",
221 "graph_fontsize",
222 "graph_depmaxdepth",
223 "graph_depmaxnodes"):
224 try:
225 value=int(value)
226 except (ValueError, TypeError):
227 return False
228 if value>10000:
229 return False
230 if value>1:
231 return True
232 else:
233 return False
234
235 elif key in ("transpose", "shrink", "echo", "graph_linklabel", "case_sensitive"):
236 if value in ("yes", "no"):
237 return True
238 else:
239 return False
240
241 elif key in ("colsep", "graph_viewer"):
242 if len(value)>0:
243 return True
244 else:
245 return False
246
247 elif key=="unit":
248 if value in ("b", "kb", "mb", "gb", "tb", "pb"):
249 return True
250 else:
251 return False
252 elif key=="graph_program":
253 if value in ("auto", "circo", "dot", "dotty", "fdp", "lefty", "neato", "twopi"):
254 return True
255 else:
256 return False
257 elif key=="graph_format":
258 if value in ("dia", "dot", "gif", "jpg", "jpeg", "mp", "pcl", "pic", \
259 "plain", "png", "ps", "ps2", "svg", "svgz", "wbmp"):
260 return True
261 else:
262 return False
263 elif key=="graph_fontname":
264 if value in ("arial", "courier", "times-roman", "verdana"):
265 return True
266 else:
267 return False
268 elif key in ("graph_bordercolor", "graph_linkcolor", "graph_indexcolor", "graph_tablecolor"):
269 return True
270 else:
271 print "(DEBUG) Key %s does not exist or does not have a verify routine !" % key
272 return False
273
274 - def set(self, key, value):
275 """Sets the parameter « key » to « value »"""
276 key=str(key).lower()
277 value=str(value).lower()
278 if self.configParser is not None:
279 if not self.configParser.has_section("PYSQL"):
280 self.configParser.add_section("PYSQL")
281 print GREEN+_("(Config file created)")+RESET
282 if self.verify(key, value):
283 self.configParser.set("PYSQL", key, value)
284 self.setChanged(True)
285 else:
286 raise PysqlException(_("Sorry, value %s is not valid for parameter %s") % (value, key))
287 else:
288 raise PysqlException(_("Cannot set config, no configParser exist !"))
289
291 """Writes config to disk"""
292 if self.changed:
293 try:
294 configFile=file(self.configPath, "w")
295 self.configParser.write(configFile)
296 configFile.close()
297 self.setChanged(False)
298 print GREEN+_("(config file saved successfully)")+RESET
299 except Exception, e:
300 raise PysqlException(_("fail to write file: %s") % e)
301 else:
302 print CYAN+_("(no need to save)")+RESET
303
305 """Writes completion list cache to disk"""
306 try:
307 cPickle.dump(self.completeLists, file(self.cachePath, "w"))
308 except Exception, e:
309 raise PysqlException(_("Fail to save completion cache to %s. Error was:\n\t%s")
310 % (self.cachePath, e))
311
313 """Writes user sql library to disk"""
314 try:
315 cPickle.dump(self.sqlLibrary, file(self.sqlLibPath, "w"))
316 except Exception, e:
317 raise PysqlException(_("Fail to save user sql library to %s. Error was:\n\t%s")
318 % (self.sqlLibPath, e))
319
320 - def writeHistory(self):
321 """Writes shell history to disk"""
322 try:
323
324 historyFile=file(self.historyPath, "w")
325 historyFile.close()
326 readline.set_history_length(1000)
327 readline.write_history_file(self.historyPath)
328 except Exception, e:
329 raise PysqlException(_("Fail to save history to %s. Error was:\n\t%s")
330 % (self.historyPath, e))
332 """Indicates if config data has changed. This is used
333 to detect if it is necessary to save config file to disk"""
334 self.changed=state
335
337 """@return: change state (boolean)"""
338 return self.changed
339
341 """Sets the host codec used to display on and read from string on terminal
342 @arg codec: codec name
343 @type codec: str"""
344 self.codec=codec
345
347 """@return: host codec used to display on and from string on terminal"""
348 return self.codec
349
351 """Emulates the Unix which to search if command is in the PATH
352 Instead of which, if multiple args are given, consider it as a command line
353 and test only the first one.
354 Returns the full path to command if found or None"""
355 command=command.split()[0]
356 for directory in os.getenv("PATH").split(":"):
357 fullpath=os.path.join(directory,command)
358 if os.access(fullpath, os.X_OK):
359 return fullpath
360 return None
361
363 """Checks if filepath is readable and writable. Returns a boolean
364 @param filepath: the full path to the file
365 @type filepath: str
366 @return: Boolean"""
367 if(os.access(filepath, os.R_OK) and os.access(filepath, os.W_OK)):
368 return True
369 else:
370 return False
371