1
2
3
4 """This module defines some common useful helper functions
5 @author: Sébastien Renard (sebastien.renard@digitalfox.org)
6 @license: GNU GPL V3
7 """
8
9
10 import os
11 import sys
12 import traceback
13 from re import match, sub
14 import datetime
15 from cx_Oracle import LOB
16 from cStringIO import StringIO
17 from time import sleep
18 from threading import Thread, Lock
19
20
21 from pysqlexception import PysqlException, PysqlActionDenied
22 from pysqlcolor import BOLD, CYAN, GREEN, GREY, RED, RESET
23 import pysqlupdate
24
25
27 """If aString does not have any wildcard, add one at the begining and one at the end"""
28 if not aString.count(wildcard):
29 return wildcard + aString + wildcard
30 else:
31 return aString
32
34 """Transforms poorly readable ndiff output into colored diff
35 @arg diff: generator returned by difflib.ndiff() function
36 @return: list of string diffs with color to highlight diff
37 """
38 result = []
39 for item in diff:
40 if item[0] == "?":
41 previous = result[-1]
42 i = 0
43 coloring = False
44 newPrevious = []
45 for character in item:
46 if character == "\n":
47
48 newPrevious.append(previous[i:])
49 else:
50 if character in ("-", "^", "+"):
51 if not coloring:
52 newPrevious.append(RED)
53 coloring = True
54 else:
55 if coloring:
56 newPrevious.append(RESET)
57 coloring = False
58 newPrevious.append(previous[i])
59 i += 1
60 newPrevious.append(RESET)
61 result[-1] = "".join(newPrevious)
62 else:
63 result.append(item)
64 return result
65
66
68 """Converts an number in Bytes into a bigger unit.
69 Beware of any data loss"""
70 unit = unit.lower()
71 if unit == "b":
72 return value
73 elif unit == "kb":
74 return float(value) / 1024
75 elif unit == "mb":
76 return float(value) / 1024 / 1024
77 elif unit == "gb":
78 return float(value) / 1024 / 1024 / 1024
79 elif unit == "tb":
80 return float(value) / 1024 / 1024 / 1024 / 1024
81 elif unit == "pb":
82 return float(value) / 1024 / 1024 / 1024 / 1024 / 1024
83 else:
84 raise PysqlException(_("Unit not handled: %s") % unit)
85
86 -def getProg(availables, given, default):
87 """Checks if 'given' graphviz program is in the 'availables' list
88 Raises an exception if program is not available or return the prog (default if given is 'auto'
89 @arg availables: dict of graphviz availables program as return by find_graphivz()
90 @arg given: program choose by user
91 @arg default: program used if user choose default"""
92 if given == "auto":
93 given = default
94 if not availables.has_key(given):
95 raise PysqlActionDenied(given +
96 _(" is not installed. Get it at http://www.graphviz.org/Download.php"))
97 else:
98 return given
99
101 """Compute length of a result set item"""
102 if item is None:
103 return 0
104 elif isinstance(item, (int, float, long, datetime.datetime)):
105 return len(str(item))
106 elif isinstance(item, LOB):
107 return item.size()
108 else:
109 return len(item)
110
112 """ Generate where clause from pysql syntax to filter Oracle object
113 Pysql syntax : pattern1 or (pattern2 and pattern3). Pattern are all accepted Oracle like pattern
114 @arg filter: pysql where clause syntax as a list of words
115 @arg keyword: the database object name on which filter apply
116 @return: SQL where clause"""
117 result = []
118 endingParenthisis = 0
119 startsWithParenthisis = True
120 lastWordWasOperand = True
121 parenthisisBalance = 0
122 for word in filterClause.split():
123
124 while word.startswith("("):
125 parenthisisBalance += 1
126 startsWithParenthisis = True
127 result.append("(")
128 word = word[1:]
129 while word.endswith(")"):
130 parenthisisBalance -= 1
131 endingParenthisis += 1
132 word = word[:-1]
133
134 if word.lower() in ("and", "or"):
135 if startsWithParenthisis or lastWordWasOperand:
136
137
138 raise PysqlException(_("Operator %s was not expected at word %s") % (word.upper(), len(result) + 1))
139 result.append(word.lower())
140 lastWordWasOperand = True
141 startsWithParenthisis = False
142
143 elif len(word) > 0 and lastWordWasOperand:
144 if word.startswith("!"):
145 if len(word) > 1 and word[1] == "(":
146 raise PysqlException(_("The ! is not supported before parenthisis"))
147 operand = "not like"
148 word = word[1:]
149 else:
150 operand = "like"
151 lastWordWasOperand = False
152 startsWithParenthisis = False
153 result.append("%s %s '%s'" % (keyword, operand, word))
154 elif len(word) > 0 and not lastWordWasOperand:
155
156 raise PysqlException(_("Operator (AND/OR) expected at word %s") % (len(result) + 1))
157 while endingParenthisis > 0:
158 endingParenthisis -= 1
159 result.append(")")
160 if parenthisisBalance != 0:
161 raise PysqlException(_("Unblanced parenthisis (%s)") % parenthisisBalance)
162 return " ".join(result)
163
197
199 """Mimics the Unix which command
200 @param progName: program name that will be search through PATH
201 @return: full path to program or None if not find in PATH"""
202 for directory in os.getenv("PATH").split(os.pathsep):
203 fullpath = os.path.join(directory, progName)
204 if os.access(fullpath, os.X_OK) and os.path.isfile(fullpath):
205 return fullpath
206 return None
207
209 """Just print a formated warning message on screen if PYSQL_WARNING env var is set (whatever value)
210 @param message: unicode or str message. Conversion will done with print and default encoding
211 """
212 if os.environ.has_key("PYSQL_WARNING"):
213 print "%s==>Warning:%s %s%s" % (RED, BOLD, message, RESET)
214
216 """Print stack trace with debug information"""
217
218 print "------------------8<-------------------------------------"
219 traceback.print_exc()
220 print "------------------8<-------------------------------------"
221 try:
222 pysqlVersion = pysqlupdate.currentVersion()
223 except PysqlException:
224 pysqlVersion = "unknown"
225 try:
226 import cx_Oracle
227 cxVersion = cx_Oracle.version
228 except Exception:
229 cxVersion = "unknown"
230 print "Pysql release: %s" % pysqlVersion
231 print "cx Oracle release: %s" % cxVersion
232 print "Python release: %s" % sys.version.replace("\n", " ")
233 print
234 print RED + BOLD + "Please, send the text above to pysql@digitalfox.org" + RESET
235 print
236
238 """Sets the window title
239 @param title: window title
240 @type title: unicode string
241 @param codec: codec used to encode string"""
242 if os.name == 'posix' and os.environ["TERM"] == 'xterm' and os.getenv("PYDEVDEBUG", "0") == "0":
243 title = "\033]0;%s\007" % title
244 sys.stdout.write(title.encode(codec, "replace"))
245 elif os.name == "nt":
246 os.system("title %s" % title.encode(codec, "replace"))
247
249 """Gets the window title
250 @return: str"""
251 if os.name == "posix":
252
253
254
255
256 title = "%s@%s" % (os.environ.get("USER", "user"), os.popen("hostname").readline().strip())
257 if os.environ.has_key("DISPLAY"):
258
259 xtitle = os.popen("xprop -id $WINDOWID WM_NAME").readline().strip()
260 if not ("WM_NAMEAborted" in title or "WM_NAMEAbandon" in title):
261 try:
262 title = xtitle.split("=")[1].lstrip(' ').strip('"')
263 except IndexError:
264
265 pass
266 elif os.name == "nt":
267
268
269 title = os.environ["ComSpec"]
270 else:
271
272 title = "terminal"
273 return title
274
276 """Gets the terminal width. Works only on Unix system.
277 @return: terminal width or "120" is system not supported"""
278 if os.name == "posix":
279 result = os.popen("tput cols").readline().strip()
280 if result:
281 return int(result)
282 else:
283
284 return 120
285
287 """Used for Oracle owner and name case policy
288 @param aString: input string to parse
289 @return: Upper case string if no quotes are given, else remove quotes and leave string as is"""
290 if aString.startswith("'") or aString.startswith('"'):
291 return aString.strip("'").strip('"')
292 else:
293 return aString.upper()
294
296 """A waiting cursor for long operation that
297 catch output and flush it after waiting"""
299 self.state = "WAIT"
300 self.lock = Lock()
301 Thread.__init__(self)
302
304 """Method executed when the thread object start() method is called"""
305
306 realStdout = sys.stdout
307 tmpStdout = StringIO()
308 sys.stdout = tmpStdout
309 cursorState = ("-", "\\", "|", "/")
310 i = 0
311 self.lock.acquire()
312 while self.state == "WAIT":
313 realStdout.write(cursorState[i % 4])
314 realStdout.flush()
315 sleep(0.1)
316 realStdout.write("\b")
317 i += 1
318
319
320 sys.stdout = realStdout
321 sys.stdout.write(tmpStdout.getvalue())
322 sys.stdout.flush()
323 self.lock.release()
324
326 self.state = "STOP"
327 self.lock.acquire()
328