comparison shelltools/query-pr/query.py @ 48:3d5adf5a59d0

Fix python2.7 syntax errors.
author David A. Holland
date Sat, 02 Apr 2022 18:05:27 -0400
parents bcd1d06838fd
children 4b7f0ee35994
comparison
equal deleted inserted replaced
47:bcd1d06838fd 48:3d5adf5a59d0
1 #!@PYTHON@ 1 #!@PYTHON@
2 2
3 import sys
3 import argparse 4 import argparse
4 import psycopg2 5 import psycopg2
5 6
6 program_description = """ 7 program_description = """
7 Search for and retrieve problem reports. 8 Search for and retrieve problem reports.
38 "release", "environment" 39 "release", "environment"
39 ] 40 ]
40 41
41 # these fields are aliases for others 42 # these fields are aliases for others
42 alias_fields = { 43 alias_fields = {
43 "number" : "id" 44 "number" : "id",
44 "date" : "arrival_date" 45 "date" : "arrival_date",
45 } 46 }
46 47
47 def __init__(self): 48 def __init__(self):
48 self.present = {} 49 self.present = {}
49 self.joined = {} 50 self.joined = {}
58 def makepresent(self, field, name): 59 def makepresent(self, field, name):
59 self.present[field] = name 60 self.present[field] = name
60 return name 61 return name
61 62
62 # add a join item (once only) (internal) 63 # add a join item (once only) (internal)
63 def addjoin(self, table, as = None): 64 def addjoin(self, table, as_ = None):
64 if as is not None: 65 if as_ is not None:
65 key = table + "-" + as 66 key = table + "-" + as_
66 val = table + " AS " + as 67 val = table + " AS " + as_
67 else: 68 else:
68 key = table 69 key = table
69 val = table 70 val = table
70 if key not in self.joined: 71 if key not in self.joined:
71 self.joined[key] = True 72 self.joined[key] = True
125 self.addwhere("patches.mimetype = " + 126 self.addwhere("patches.mimetype = " +
126 "'application/x-patch'") 127 "'application/x-patch'")
127 return self.makepresent(field, "patches.body") 128 return self.makepresent(field, "patches.body")
128 129
129 if field == "mimetype": 130 if field == "mimetype":
130 subquery = "((SELECT mtmessages1.pr as pr, " + 131 subquery = "((SELECT mtmessages1.pr as pr, " + \
131 "mtmessages1.mimetype as mimetype " + 132 "mtmessages1.mimetype as mimetype " + \
132 "FROM messages as mtmessages1) " + 133 "FROM messages as mtmessages1) " + \
133 "UNION " + 134 "UNION " + \
134 "(SELECT mtmessages2.pr as pr, " + 135 "(SELECT mtmessages2.pr as pr, " + \
135 "mtattach2.mimetype as mimetype " + 136 "mtattach2.mimetype as mimetype " + \
136 "FROM messages as mtmessages2, " + 137 "FROM messages as mtmessages2, " + \
137 " attachments as mtattach2 " + 138 " attachments as mtattach2 " + \
138 "WHERE mtmessages2.id = mtattach2.msgid))" 139 "WHERE mtmessages2.id = mtattach2.msgid))"
139 self.addjoin("PRs") 140 self.addjoin("PRs")
140 self.addjoin(subquery, "mimetypes") 141 self.addjoin(subquery, "mimetypes")
141 self.addwhere("PRs.id = mimetypes.pr") 142 self.addwhere("PRs.id = mimetypes.pr")
142 return self.makepresent(field, "mimetypes.mimetype") 143 return self.makepresent(field, "mimetypes.mimetype")
260 ############################################################ 261 ############################################################
261 # query class for searches 262 # query class for searches
262 # XXX: obsolete, remove 263 # XXX: obsolete, remove
263 264
264 class Query: 265 class Query:
265 __init__(self): 266 def __init__(self):
266 self.selections = [] 267 self.selections = []
267 self.tables = [] 268 self.tables = []
268 self.constraints = [] 269 self.constraints = []
269 self.args = [] 270 self.args = []
270 prtables = ["PRs"] 271 prtables = ["PRs"]
394 regexp_constraint(prq, "PRs.release", args.release) 395 regexp_constraint(prq, "PRs.release", args.release)
395 if args.environment is not None: 396 if args.environment is not None:
396 checkprtable = True 397 checkprtable = True
397 regexp_constraint(prq, "PRs.environment", args.environment) 398 regexp_constraint(prq, "PRs.environment", args.environment)
398 399
399 if args.originator_name is not None or 400 if args.originator_name is not None or \
400 args.originator_email is not None: 401 args.originator_email is not None:
401 prq.addtable("usermail as originator") 402 prq.addtable("usermail as originator")
402 prq.constrain("PRs.originator = originator.id") 403 prq.constrain("PRs.originator = originator.id")
403 if args.originator_name is not None: 404 if args.originator_name is not None:
404 checkprtable = True 405 checkprtable = True
485 class PrintText: 486 class PrintText:
486 def __init__(self, output): 487 def __init__(self, output):
487 self.lines = (output == "RAW" or output == "LIST") 488 self.lines = (output == "RAW" or output == "LIST")
488 def printheader(self, row): 489 def printheader(self, row):
489 # nothing 490 # nothing
491 pass
490 def printrow(self, row): 492 def printrow(self, row):
491 # XXX 493 # XXX
492 print row 494 print row
493 def printfooter(self, row): 495 def printfooter(self, row):
494 # nothing 496 # nothing
497 pass
495 # end class PrintText 498 # end class PrintText
496 499
497 class PrintCsv: 500 class PrintCsv:
498 def __init__(self, output): 501 def __init__(self, output):
499 # nothing 502 # nothing
503 pass
500 def printheader(self, row): 504 def printheader(self, row):
501 # XXX 505 # XXX
506 pass
502 def printrow(self, row): 507 def printrow(self, row):
503 # XXX 508 # XXX
509 pass
504 def printfooter(self, row): 510 def printfooter(self, row):
505 # nothing 511 # nothing
512 pass
506 # end class PrintCsv 513 # end class PrintCsv
507 514
508 class PrintXml: 515 class PrintXml:
509 def __init__(self, output): 516 def __init__(self, output):
510 # nothing 517 # nothing
518 pass
511 def printheader(self, row): 519 def printheader(self, row):
512 # XXX 520 # XXX
521 pass
513 def printrow(self, row): 522 def printrow(self, row):
514 # XXX 523 # XXX
524 pass
515 def printfooter(self, row): 525 def printfooter(self, row):
516 # XXX 526 # XXX
527 pass
517 # end class PrintXml 528 # end class PrintXml
518 529
519 class PrintJson: 530 class PrintJson:
520 def __init__(self, output): 531 def __init__(self, output):
521 # nothing 532 # nothing
533 pass
522 def printheader(self, row): 534 def printheader(self, row):
523 # XXX 535 # XXX
536 pass
524 def printrow(self, row): 537 def printrow(self, row):
525 # XXX 538 # XXX
539 pass
526 def printfooter(self, row): 540 def printfooter(self, row):
527 # XXX 541 # XXX
542 pass
528 # end class PrintJson 543 # end class PrintJson
529 544
530 class PrintRdf: 545 class PrintRdf:
531 def __init__(self, output): 546 def __init__(self, output):
532 # nothing 547 # nothing
548 pass
533 def printheader(self, row): 549 def printheader(self, row):
534 # XXX 550 # XXX
551 pass
535 def printrow(self, row): 552 def printrow(self, row):
536 # XXX 553 # XXX
554 pass
537 def printfooter(self, row): 555 def printfooter(self, row):
538 # XXX 556 # XXX
557 pass
539 # end class PrintRdf 558 # end class PrintRdf
540 559
541 class PrintRdflike: 560 class PrintRdflike:
542 def __init__(self, output): 561 def __init__(self, output):
543 # nothing 562 # nothing
563 pass
544 def printheader(self, row): 564 def printheader(self, row):
545 # XXX 565 # XXX
566 pass
546 def printrow(self, row): 567 def printrow(self, row):
547 # XXX 568 # XXX
569 pass
548 def printfooter(self, row): 570 def printfooter(self, row):
549 # XXX 571 # XXX
572 pass
550 # end class PrintRdflike 573 # end class PrintRdflike
551 574
552 def print_prs(ids): 575 def print_prs(ids):
553 if sel.outformat == "TEXT": 576 if sel.outformat == "TEXT":
554 mkprinter = PrintText 577 mkprinter = PrintText
575 printer.printfooter(ids[0]) 598 printer.printfooter(ids[0])
576 return 599 return
577 elif sel.output == "LIST": 600 elif sel.output == "LIST":
578 # XXX is there a clean way to do this passing the 601 # XXX is there a clean way to do this passing the
579 # whole list of ids at once? 602 # whole list of ids at once?
580 query = "SELECT id, synopsis\n" + 603 query = "SELECT id, synopsis\n" + \
581 "FROM PRs\n" + 604 "FROM PRs\n" + \
582 "WHERE id = $1" 605 "WHERE id = $1"
583 elif sel.output == "HEADERS": 606 elif sel.output == "HEADERS":
584 query = None # XXX 607 query = None # XXX
585 elif sel.output == "META": 608 elif sel.output == "META":
586 query = None # XXX 609 query = None # XXX
600 printer.printfooter(results[0]) 623 printer.printfooter(results[0])
601 # end print_prs 624 # end print_prs
602 625
603 # XXX if in public mode we need to check if the PR is public 626 # XXX if in public mode we need to check if the PR is public
604 def print_message(pr, msgnum): 627 def print_message(pr, msgnum):
605 query = "SELECT users.username AS username,\n" + 628 query = "SELECT users.username AS username,\n" + \
606 " users.realname AS realname,\n" + 629 " users.realname AS realname,\n" + \
607 " messages.id AS id, parent_id,\n" + 630 " messages.id AS id, parent_id,\n" + \
608 " posttime, mimetype, body\n" + 631 " posttime, mimetype, body\n" + \
609 "FROM messages, users\n" + 632 "FROM messages, users\n" + \
610 "WHERE messages.who = users.id\n" + 633 "WHERE messages.who = users.id\n" + \
611 " AND messages.pr = $1\n" + 634 " AND messages.pr = $1\n" + \
612 " AND messages.number_in_pr = $2\n" 635 " AND messages.number_in_pr = $2\n"
613 # Note that while pr is safe, msgnum came from the commandline 636 # Note that while pr is safe, msgnum came from the commandline
614 # and may not be. 637 # and may not be.
615 results = querydb(query, [pr, msgnum]) 638 results = querydb(query, [pr, msgnum])
616 [result] = results 639 [result] = results
626 sys.stdout.write(body) 649 sys.stdout.write(body)
627 # end print_message 650 # end print_message
628 651
629 # XXX if in public mode we need to check if the PR is public 652 # XXX if in public mode we need to check if the PR is public
630 def print_attachment(pr, attachnum): 653 def print_attachment(pr, attachnum):
631 query = "SELECT a.mimetype as mimetype, a.body as body\n" + 654 query = "SELECT a.mimetype as mimetype, a.body as body\n" + \
632 "FROM messages, attachments as a\n" + 655 "FROM messages, attachments as a\n" + \
633 "WHERE messages.pr = $1\n" + 656 "WHERE messages.pr = $1\n" + \
634 " AND messages.id = a.msgid\n" + 657 " AND messages.id = a.msgid\n" + \
635 " AND a.number_in_pr = $2\n" 658 " AND a.number_in_pr = $2\n"
636 # Note that while pr is safe, attachnum came from the 659 # Note that while pr is safe, attachnum came from the
637 # commandline and may not be. 660 # commandline and may not be.
638 results = querydb(query, [pr, msgnum]) 661 results = querydb(query, [pr, msgnum])
639 [result] = results 662 [result] = results
700 def dorevfield(field): 723 def dorevfield(field):
701 return Order(field, True) 724 return Order(field, True)
702 # end class Order 725 # end class Order
703 726
704 class Search: 727 class Search:
705 def __init__(self, qs, openonly, publiconly, os) 728 def __init__(self, qs, openonly, publiconly, os):
706 self.queries = qs 729 self.queries = qs
707 self.openonly = openonly 730 self.openonly = openonly
708 self.publiconly = publiconly 731 self.publiconly = publiconly
709 self.orders = os 732 self.orders = os
710 # end class Search 733 # end class Search
763 # end class Invocation 786 # end class Invocation
764 787
765 ############################################################ 788 ############################################################
766 # run (eval the SQL and print the results) 789 # run (eval the SQL and print the results)
767 790
768 def
769
770 def run_sel(sel, ids): 791 def run_sel(sel, ids):
771 if sel.type == S_PR: 792 if sel.type == S_PR:
772 if ids == []: 793 if ids == []:
773 sys.stderr.write("No PRs matched.\n") 794 sys.stderr.write("No PRs matched.\n")
774 exit(1) 795 exit(1)
815 # 836 #
816 # XXX this doesn't work, we need to keep the interned strings 837 # XXX this doesn't work, we need to keep the interned strings
817 # on return from compile_query. 838 # on return from compile_query.
818 # 839 #
819 840
841 def matches(s, rx):
842 # XXX
843 return True
844
820 def compile_query(q): 845 def compile_query(q):
821 if q.type == Q_QSTRING: 846 if q.type == Q_QSTRING:
822 # XXX should use a split that honors quotes 847 # XXX should use a split that honors quotes
823 terms = q.string.split() 848 terms = q.string.split()
824 terms = [dotstring(t) for t in terms] 849 terms = [dotstring(t) for t in terms]
825 return compile_query(doand(terms)) 850 return compile_query(doand(terms))
826 if q.type == Q_TSTRING: 851 if q.type == Q_TSTRING:
827 qb = QueryBuilder() 852 qb = QueryBuilder()
828 s = q.string 853 s = q.string
829 if s ~ "^[0-9]+$": 854 if matches(s, "^[0-9]+$"):
830 f = qb.getfield("number") 855 f = qb.getfield("number")
831 # Note: s is user-supplied but clean to insert directly 856 # Note: s is user-supplied but clean to insert directly
832 qb.addwhere("%s = %s" % (f, s)) 857 qb.addwhere("%s = %s" % (f, s))
833 elif s ~ "^[0-9]+-[0-9]+$": 858 elif matches(s, "^[0-9]+-[0-9]+$"):
834 f = qb.getfield("number") 859 f = qb.getfield("number")
835 ss = s.split("-") 860 ss = s.split("-")
836 # Note: ss[] is user-supplied but clean 861 # Note: ss[] is user-supplied but clean
837 qb.addwhere("%s >= %s" % (f, ss[0])) 862 qb.addwhere("%s >= %s" % (f, ss[0]))
838 qb.addwhere("%s <= %s" % (f, ss[1])) 863 qb.addwhere("%s <= %s" % (f, ss[1]))
839 elif s ~ "^[0-9]+-$": 864 elif matches(s, "^[0-9]+-$"):
840 f = qb.getfield("number") 865 f = qb.getfield("number")
841 ss = s.split("-") 866 ss = s.split("-")
842 # Note: ss[] is user-supplied but clean 867 # Note: ss[] is user-supplied but clean
843 qb.addwhere("%s >= %s" % (f, ss[0])) 868 qb.addwhere("%s >= %s" % (f, ss[0]))
844 elif s ~ "^-[0-9]+$": 869 elif matches(s, "^-[0-9]+$"):
845 f = qb.getfield("number") 870 f = qb.getfield("number")
846 ss = s.split("-") 871 ss = s.split("-")
847 # Note: ss[] is user-supplied but clean 872 # Note: ss[] is user-supplied but clean
848 qb.addwhere("%s <= %s" % (f, ss[1])) 873 qb.addwhere("%s <= %s" % (f, ss[1]))
849 elif s ~ "^[^:]+:[^:]+$": 874 elif matches(s, "^[^:]+:[^:]+$"):
850 # XXX honor quoted terms 875 # XXX honor quoted terms
851 # XXX = or LIKE? 876 # XXX = or LIKE?
852 ss = s.split(":") 877 ss = s.split(":")
853 # ss[0] is not clean but if it's crap it won't match 878 # ss[0] is not clean but if it's crap it won't match
854 f = qb.getfield(ss[0]) 879 f = qb.getfield(ss[0])
855 # ss[1] is not clean, so intern it for safety 880 # ss[1] is not clean, so intern it for safety
856 s = qb.intern(ss[1]) 881 s = qb.intern(ss[1])
857 qb.addwhere("%s = %s" % (f, s)) 882 qb.addwhere("%s = %s" % (f, s))
858 elif s ~ "^-[^:]+:[^:]+$" 883 elif matches(s, "^-[^:]+:[^:]+$"):
859 # XXX honor quoted terms 884 # XXX honor quoted terms
860 # XXX <> or NOT LIKE? 885 # XXX <> or NOT LIKE?
861 ss = s.split(":") 886 ss = s.split(":")
862 # ss[0] is not clean but if it's crap it won't match 887 # ss[0] is not clean but if it's crap it won't match
863 f = qb.getfield(ss[0]) 888 f = qb.getfield(ss[0])
864 # ss[1] is not clean, so intern it for safety 889 # ss[1] is not clean, so intern it for safety
865 s = qb.intern(ss[1]) 890 s = qb.intern(ss[1])
866 qb.addwhere("%s <> %s" % (f, s)) 891 qb.addwhere("%s <> %s" % (f, s))
867 elif s ~ "^-": 892 elif matches(s, "^-"):
868 # XXX <> or NOT LIKE? 893 # XXX <> or NOT LIKE?
869 f = qb.getfield("alltext") 894 f = qb.getfield("alltext")
870 # s is not clean, so intern it for safety 895 # s is not clean, so intern it for safety
871 s = qb.intern(s) 896 s = qb.intern(s)
872 qb.addwhere("%s <> %s" % (f, s)) 897 qb.addwhere("%s <> %s" % (f, s))
976 action='version', version=program_version, 1001 action='version', version=program_version,
977 help="Print program version and exit") 1002 help="Print program version and exit")
978 1003
979 p.add_argument("--show", nargs=1, 1004 p.add_argument("--show", nargs=1,
980 action=CtorAppend, dest='ops', 1005 action=CtorAppend, dest='ops',
981 const=Invocation.Op.doshow 1006 const=Invocation.Op.doshow,
982 help="Show description of field") 1007 help="Show description of field")
983 p.add_argument("--range", nargs=1, 1008 p.add_argument("--range", nargs=1,
984 action=CtorAppend, dest='ops', 1009 action=CtorAppend, dest='ops',
985 const=Invocation.Op.dorange 1010 const=Invocation.Op.dorange,
986 help="Show range of extant values for field") 1011 help="Show range of extant values for field")
987 1012
988 p.add_argument("--search", nargs=1, 1013 p.add_argument("--search", nargs=1,
989 action=CtorAppend, dest='queries', 1014 action=CtorAppend, dest='queries',
990 const=Invocation.Query.doqstring, 1015 const=Invocation.Query.doqstring,