comparison shelltools/query-pr/query.py @ 33:298c8a7f5181

begin hacking (not at all finished, won't work)
author David A. Holland
date Mon, 27 May 2013 23:16:42 -0400
parents c013fb703183
children 73e6dac29391
comparison
equal deleted inserted replaced
32:7458a278cb64 33:298c8a7f5181
1 #!@PYTHON@ 1 #!@PYTHON@
2
3 import argparse
4 import psycopg2
5
6 program_description = """
7 Search for and retrieve problem reports.
8 """
9 program_version = "@VERSION@"
10
11 ############################################################
12 # settings
13
14 outfile = sys.stdout
15 outmaterial = "headers"
16 outformat = "text"
17
18 ############################################################
19 # database
20
21 dblink = None
22
23 def opendb():
24 global dblink
25
26 host = "localhost"
27 user = "swallowtail"
28 database = "swallowtail"
29 dblink = psycopg2.connect("host=%s user=%s dbname=%s" %
30 (host, user, database))
31 # end opendb
32
33 def closedb():
34 global dblink
35
36 dblink.close()
37 dblink = None
38 # end closedb
39
40 def querydb(qtext, args):
41 print "Executing this query:"
42 print qtext
43 print "Args are:"
44 print args
45
46 cursor = dblink.cursor()
47 cursor.execute(qtext, args)
48 result = cursor.fetchall()
49 cursor.close()
50 return result
51 # end querydb
52
53 ############################################################
54 #
55
56 ############################################################
57 # query class for searches
58
59 class Query:
60 __init__(self):
61 self.selections = []
62 self.tables = []
63 self.constraints = []
64 self.args = []
65 prtables = ["PRs"]
66 prconstraints = []
67
68 def select(self, s):
69 self.selections.append(s)
70
71 def addtable(self, t):
72 assert(t not in self.tables)
73 self.tables.append(t)
74
75 def constrain(self, expr):
76 self.constraints.append(t)
77
78 def internval(self, val):
79 num = len(self.args)
80 self.args[num] = val
81 return "$%d" % num
82
83 def textify(self):
84 s = "SELECT %s\n" % ",".join(self.selections)
85 f = "FROM %s\n" % ",".join(self.tables)
86 w = "WHERE %s\n" % " AND ".join(self.constraints)
87 return s + f + w
88 # end class Query
89
90 def regexp_constraint(q, field, value):
91 cleanval = q.internval(value)
92 if not isregexp(value):
93 return "%s = %s" % (field, cleanval)
94 else:
95 # XXX what's the right operator again?
96 return "%s ~= %s" % (field, cleanval)
97 # end regexp_constraint
98
99 def intrange_constraint(q, field, value):
100 (lower, upper) = args.number
101 if lower is not None:
102 assert(typeof(lower) == int)
103 prq.constrain("%s >= %d" % (field, lower))
104 if upper is not None:
105 assert(typeof(upper) == int)
106 prq.constrain("%s <= %d" % (field, upper))
107 # end intrange_constraint
108
109 def daterange_constraint(q, field, value):
110 # XXX
111 assert(0)
112 # end daterange_constraint
113
114 ############################################################
115 # arg handling
116
117 def getargs(classification_schemes, classification_schemetypes):
118 global outmaterial
119 global outformat
120
121 p = argparse.ArgumentParser(program_description)
122
123 # note: -h/--help is built in by default
124 p.add_argument("-v", "--version",
125 action='version' version=program_version,
126 help="Print program version and exit")
127
128 p.add_argument("--short",
129 action='store_const', const="short",
130 dest='outmaterial',
131 help="Output in short form (one per line)")
132 p.add_argument("--headers",
133 action='store_const', const="headers",
134 dest='outmaterial',
135 help="Output in default form (headers only)")
136 p.add_argument("--full",
137 action='store_const', const="full",
138 dest='outmaterial',
139 help="Output in full form (all material)")
140 p.add_argument("--attach", nargs=1,
141 type=int,
142 action='store',
143 dest='attach',
144 help="Output specified attachment")
145 p.add_argument("--message", nargs=1,
146 type=int,
147 action='store',
148 dest='message',
149 help="Output specified message")
150
151 p.add_argument("--text",
152 action='store_const', const="text",
153 dest='outformat',
154 help="Output as text (default)")
155 p.add_argument("--csv",
156 action='store_const', const="csv",
157 dest='outformat',
158 help="Output as comma-separated values")
159 p.add_argument("--xml",
160 action='store_const', const="xml",
161 dest='outformat',
162 help="Output as XML")
163 p.add_argument("--json",
164 action='store_const', const="json",
165 dest='outformat',
166 help="Output as JSON")
167 p.add_argument("--rdf",
168 action='store_const', const="rdf",
169 dest='outformat',
170 help="Output as RDF")
171 p.add_argument("--rdflike",
172 action='store_const', const="rdflike",
173 dest='outformat',
174 help="Output as RDF-like text")
175
176 p.add_argument("--closed",
177 action='store_true',
178 dest='closed', default=False,
179 help="Search closed PRs as well as open")
180 p.add_argument("--public",
181 action='store_true',
182 dest='public', default=False,
183 help="Search only public information")
184
185 p.add_argument("--number", nargs=1,
186 type=intrange,
187 dest='number',
188 help="Restrict search to a range of PRs by number")
189 p.add_argument("--synopsis", nargs=1,
190 dest='synopsis',
191 help="Search PRs by their synopsis field")
192 p.add_argument("--confidential", nargs=1,
193 type=yesno, choices=["yes", "no"],
194 dest='confidential',
195 help="Search PRs by their confidentiality setting")
196 p.add_argument("--state", nargs=1,
197 dest='state',
198 help="Search PRs by their state")
199 p.add_argument("--locked", nargs=1,
200 type=yesno, choices=["yes", "no"],
201 dest='locked',
202 help="Search PRs by their locked setting")
203 p.add_argument("--arrival-schemaversion", nargs=1,
204 type=intrange,
205 dest='arrival_schemaversion',
206 help="Search PRs by their original schema version")
207 p.add_argument("--arrival-date", nargs=1,
208 type=daterange,
209 dest='arrival_date',
210 help="Search PRs by arrival date")
211 p.add_argument("--closed-date", nargs=1,
212 type=daterange,
213 dest='closed_date',
214 help="Search PRs by the date they were closed")
215 p.add_argument("--last-modified", nargs=1,
216 type=daterange,
217 dest='last_modified',
218 help="Search PRs by the date they were last modified")
219 p.add_argument("--release", nargs=1,
220 dest='release',
221 help="Search PRs by their release information")
222 p.add_argument("--environment", nargs=1,
223 dest='environment',
224 help="Search PRs by their environment information")
225
226 p.add_argument("--originator-name", nargs=1,
227 dest='originator_name',
228 help="Search PRs by the name of their originator")
229 p.add_argument("--originator-email", nargs=1,
230 dest='originator_email',
231 help="Search PRs by the email of their originator")
232 p.add_argument("--originator-id", nargs=1,
233 type=intrange,
234 dest='originator_id',
235 help="Search PRs by the database ID of their originator")
236
237
238 p.add_argument("--responsible", nargs=1,
239 dest='responsible',
240 help="Search PRs by who's responsible for them")
241 p.add_argument("--respondent", nargs=1,
242 dest='respondent',
243 help="Search PRs by who's a respondent")
244 p.add_argument("--subscribed", nargs=1,
245 dest='subscribed',
246 help="Search PRs by who's subscribed")
247
248 p.add_argument("--messages", nargs=1,
249 dest='messages',
250 help="Search PRs by text in the message log")
251 p.add_argument("--adminlog", nargs=1,
252 dest='adminlog',
253 help="Search PRs by text in the administrative log")
254 p.add_argument("--anytext", nargs=1,
255 dest='anytext',
256 help="Search PRs by text in various fields")
257
258 for scheme in classification_schemes:
259 p.add_argument("--%s" % scheme, nargs=1,
260 dest=scheme,
261 help="Search PRs by the %s classification scheme" %
262 scheme)
263
264 p.add_argument("prs", nargs='*', metavar="PR",
265 type=int,
266 action='append',
267 dest='prs',
268 help="Specific PRs to retrieve by number")
269
270 args = p.parse_args()
271
272 if args.outmaterial is not None:
273 outmaterial = args.outmaterial
274 if args.outformat is not None:
275 outformat = args.outformat
276
277 # If we're doing something other than a search, do it now
278 if args.attach is not None:
279 get_attachment(args.attach)
280 exit(0)
281 if args.message is not None:
282 get_message(args.message)
283 exit(0)
284
285 if args.prs is not None and len(args.prs) > 0:
286 show_prs(args.prs)
287 exit(0)
288
289 #
290 # Collect up the search constraints
291 #
292
293 # 1. Constraints on the PRs table
294 checkprtable = False
295 prq = Query()
296 prq.select("PRs.id as id")
297 prq.addtable("PRs")
298 if not args.closed:
299 checkprtable = True
300 prq.addtable("states")
301 prq.constrain("PRs.state = states.name")
302 prq.constrain("states.closed = FALSE")
303 if args.public:
304 checkprtable = True
305 prq.constrain("NOT PRs.confidential")
306 if args.number is not None:
307 checkprtable = True
308 intrange_constraint(prq, "PRs.id", args.number)
309 if args.synopsis is not None:
310 checkprtable = True
311 regexp_constraint(prq, "PRs.synopsis", args.synopsis)
312 if args.confidential is not None:
313 checkprtable = True
314 assert(typeof(args.confidential) == bool)
315 if args.confidential:
316 prq.constrain("PRs.confidential")
317 else:
318 prq.constrain("not PRs.confidential")
319 if args.state is not None:
320 checkprtable = True
321 regexp_constraint(prq, "PRs.state", args.state)
322 if args.locked is not None:
323 checkprtable = True
324 assert(typeof(args.locked) == bool)
325 if args.locked:
326 prq.constrain("PRs.locked")
327 else:
328 prq.constrain("not PRs.locked")
329 if args.arrival_schemaversion is not None:
330 checkprtable = True
331 intrange_constraint(prq, "PRs.arrival_schemaversion",
332 args.arrival_schemaversion)
333 if args.arrival_date is not None:
334 checkprtable = True
335 daterange_constraint(prq, "PRs.arrival_date",
336 args.arrival_date)
337 if args.closed_date is not None:
338 checkprtable = True
339 daterange_constraint(prq, "PRs.closed_date",
340 args.closed_date)
341 if args.last_modified is not None:
342 checkprtable = True
343 daterange_constraint(prq, "PRs.last_modified",
344 args.last_modified)
345 if args.release is not None:
346 checkprtable = True
347 regexp_constraint(prq, "PRs.release", args.release)
348 if args.environment is not None:
349 checkprtable = True
350 regexp_constraint(prq, "PRs.environment", args.environment)
351
352 if args.originator_name is not None or
353 args.originator_email is not None:
354 prq.addtable("usermail as originator")
355 prq.constrain("PRs.originator = originator.id")
356 if args.originator_name is not None:
357 checkprtable = True
358 regexp_constraint(prq, "originator.realname",
359 args.originator_name)
360 if args.originator_email is not None:
361 checkprtable = True
362 regexp_constraint(prq, "originator.email",
363 args.originator_name)
364 if args.originator_id is not None:
365 checkprtable = True
366 intrange_constraint(prq, "PRs.originator", args.originator_id)
367
368 queries = []
369 if checkprtable:
370 queries.append(prq)
371
372 if args.responsible is not None:
373 sq = Query()
374 sq.select("subscriptions.pr as id")
375 sq.addtable("subscriptions")
376 sq.addtable("users")
377 sq.constrain("subscriptions.userid = users.id")
378 regexp_constraint(sq, "users.realname", args.responsible)
379 sq.constrain("subscriptions.responsible")
380 queries.append(sq)
381 if args.respondent is not None:
382 sq = Query()
383 sq.select("subscriptions.pr as id")
384 sq.addtable("subscriptions")
385 sq.addtable("users as subscribed")
386 sq.constrain("subscriptions.userid = users.id")
387 regexp_constraint(sq, "users.realname", args.respondent)
388 sq.constrain("subscriptions.reporter")
389 queries.append(sq)
390 if args.subscribed is not None:
391 sq = Query()
392 sq.select("subscriptions.pr as id")
393 sq.addtable("subscriptions")
394 sq.addtable("users as subscribed")
395 sq.constrain("subscriptions.userid = users.id")
396 regexp_constraint(sq, "users.realname", args.subscribed)
397 queries.append(sq)
398
399 if args.messages is not None:
400 mq = Query()
401 mq.select("messages.pr as id")
402 mq.addtable("messages")
403 regexp_constraint(sq, "messages.text", args.messages)
404 queries.append(mq)
405
406 if args.adminlog is not None:
407 aq = Query()
408 aq.select("adminlog.pr as id")
409 aq.addtable("adminlog")
410 regexp_constraint(sq, "adminlog.change", args.adminlog)
411 regexp_constraint(sq, "adminlog.comment", args.adminlog)
412 assert(len(aq.constraints) == 2)
413 x = "%s OR %s" % (aq.constraints[0], aq.constraints[1])
414 aq.constraints = [x]
415 queries.append(aq)
416
417 if args.anytext is not None:
418 choke("--anytext isn't supported yet")
419
420 for scheme in classification_schemes:
421 if args[scheme] is not None:
422 schemetype = classification_schemetypes[scheme]
423 tbl = "%sclass_data" % schemetype
424 cq = Query()
425 cq.select("scheme.pr as id")
426 cq.addtable("%s as scheme" % schemetype)
427 cq.constrain("scheme.scheme = '%s'" % scheme)
428 regexp_constraint(cq, "scheme.value", args[scheme])
429 queries.append(cq)
430 # end loop
431
432 querytexts = [q.textify() for q in queries]
433 return "INTERSECT\n".join(querytexts)
434 # end getargs
435
436 ############################################################
437 # main
438
439 def main():
440 opendb()
441 (classification_schemes, classification_schemetypes) = getclassify()
442 query = getargs(classification_schemes, classification_schemetypes)
443 ids = querydb(query)
444 if len(ids) > 0:
445 show_prs(ids)
446 else:
447 sys.stderr.write("No PRs matched.\n")
448 exit(1)
449 closedb()
450 return 0
451 # end main
452
453 # real python hackers doubtless laugh at this
454 exit(main())