1
2
3
4
5
6
7
8 __version__ = "$Revision: 1.10 $"
9 __author__ = "Ian Haywood"
10 __license__ = "GPL (details at http://www.gnu.org)"
11
12
13 import sys, os, string, re, urllib2, logging
14
15
16 _log = logging.getLogger('gm.bootstrapper')
17 _log.info(__version__)
18
20 """
21 runs the shell command and returns a string
22 """
23 stdin, stdout = os.popen4 (cmd.group (1))
24 r = stdout.read ()
25 stdout.close()
26 stdin.close()
27 return r
28
30 """
31 performs backtick shell extension in a string
32 """
33 return re.sub (r"`(.*)`", shellrun, str)
34
36
38 """
39 db : the interpreter to connect to, must be a DBAPI compliant interface
40 """
41 self.conn = conn
42 self.vars = {'ON_ERROR_STOP':None}
43
45 match = re.match (str, self.line)
46 if match is None:
47 ret = 0
48 else:
49 ret = 1
50 self.groups = match.groups ()
51 return ret
52
54 tmp = u"%s:%d: %s" % (self.filename, self.lineno-1, aMsg)
55 tmp = tmp.replace(u'\r', u'')
56
57 return tmp.replace(u'\n', u'')
58
59
60
61
62 - def run (self, filename):
63 """
64 filename: a file, containg semicolon-separated SQL commands
65 """
66 if re.match ("http://.*", filename) or re.match ("ftp://.*", filename) or re.match ("gopher://.*", filename):
67 try:
68 self.file = urllib2.urlopen (filename)
69 except URLError:
70 _log.error(u"cannot access %s" % filename)
71 return 1
72 else:
73 if os.access (filename, os.R_OK):
74 self.file = open(filename)
75 else:
76 _log.error(u"cannot open file [%s]" % filename)
77 return 1
78
79 self.lineno = 0
80 self.filename = filename
81 in_string = False
82 bracketlevel = 0
83 curr_cmd = ''
84 curs = self.conn.cursor ()
85
86 for self.line in self.file.readlines():
87 self.lineno += 1
88 if len(self.line.strip()) == 0:
89 continue
90
91
92 if self.match (r"^\\echo (.*)"):
93 _log.info(self.fmt_msg(shell(self.groups[0])))
94 continue
95
96 if self.match (r"^\\qecho (.*)"):
97 _log.info(self.fmt_msg(shell (self.groups[0])))
98 continue
99
100 if self.match (r"^\\q"):
101 _log.warning(self.fmt_msg(u"script terminated by \\q"))
102 return 0
103
104 if self.match (r"^\\set (\S+) (\S+)"):
105 self.vars[self.groups[0]] = shell (self.groups[1])
106 if self.groups[0] == 'ON_ERROR_STOP':
107 self.vars['ON_ERROR_STOP'] = int (self.vars['ON_ERROR_STOP'])
108 continue
109
110 if self.match (r"^\\unset (\S+)"):
111 self.vars[self.groups[0]] = None
112 continue
113
114 if self.match (r"^\\connect.*"):
115 _log.error(self.fmt_msg(u"\\connect not yet supported in scripts"))
116 continue
117
118 if self.match (r"^\\lo_import.*"):
119 _log.error(self.fmt_msg(u"\\lo_import not yet supported"))
120
121 return 1
122
123 if self.match (r"^\\copy .* to '(\S+)' .*"):
124 _log.error(self.fmt_msg(u"\\copy to not implemented"))
125 return 1
126
127 if self.match (r"^\\copy .* from '(\S+)' .*"):
128 copyfile = self.groups[0]
129 try:
130 copyfd = file (os.path.join (os.path.dirname (self.filename), copyfile))
131 except error:
132 _log.error(self.fmt_msg(error))
133 return 1
134 self.line = self.line[1:].strip()
135 self.line.replace ("'%s'" % copyfile, 'stdin')
136
137 copyline = 0
138 try:
139 curs = self.conn.cursor ()
140
141 curs.execute (self.line)
142
143 for i in copyfd.readlines ():
144 curs.execute (i)
145 copyline += 1
146 self.conn.commit ()
147 curs.close ()
148 except StandardError, error:
149 _log.error(u"%s: %d: %s" % (copyfile, copyline, error))
150 if self.vars['ON_ERROR_STOP']:
151 return 1
152 continue
153
154
155 if self.match (r"^\\i (\S+)"):
156
157 Psql(self.conn).run (os.path.join (os.path.dirname (self.filename), self.groups[0]))
158 continue
159
160
161 if self.match (r"^\\encoding.*"):
162 _log.error(self.fmt_msg(u"\\encoding not yet supported"))
163 continue
164
165
166 if self.match (r"^\\(.*)") and not in_string:
167
168
169 _log.warning(self.fmt_msg(u"psql command \"\\%s\" being ignored " % self.groups[0]))
170 continue
171
172
173 this_char = self.line[0]
174
175 for next_char in self.line[1:] + ' ':
176
177
178 if this_char == "'":
179 in_string = not in_string
180
181
182 if this_char == '-' and next_char == '-' and not in_string:
183 break
184
185
186 if this_char == '(' and not in_string:
187 bracketlevel += 1
188 if this_char == ')' and not in_string:
189 bracketlevel -= 1
190
191
192 if not (not in_string and (bracketlevel == 0) and (this_char == ';')):
193 curr_cmd += this_char
194 else:
195 try:
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214 if curr_cmd.strip() != '':
215 if curr_cmd.find('vacuum'):
216 self.conn.commit();
217 curs.close()
218 old_iso_level = self.conn.isolation_level
219 self.conn.set_isolation_level(0)
220 curs = self.conn.cursor()
221 curs.execute (curr_cmd)
222 self.conn.set_isolation_level(old_iso_level)
223 else:
224 curs.execute (curr_cmd)
225
226 except StandardError, error:
227 _log.debug(curr_cmd)
228 if re.match (r"^NOTICE:.*", str(error)):
229 _log.warning(self.fmt_msg(error))
230 else:
231 if self.vars['ON_ERROR_STOP']:
232 _log.error(self.fmt_msg(error))
233 return 1
234 else:
235 _log.debug(self.fmt_msg(error))
236
237 self.conn.commit()
238 curs.close()
239 curs = self.conn.cursor()
240 curr_cmd = ''
241
242 this_char = next_char
243
244
245
246
247 self.conn.commit()
248 curs.close()
249 return 0
250
251
252 if __name__ == '__main__':
253 from pyPgSQL import PgSQL
254 conn = PgSQL.connect (user='gm-dbo', database = 'gnumed')
255 psql = Psql (conn)
256 psql.run (sys.argv[1])
257 conn.close ()
258
259