Mercurial > ~dholland > hg > swallowtail > index.cgi
changeset 50:bb0ece71355e
Untabify.
author | David A. Holland |
---|---|
date | Sat, 02 Apr 2022 18:10:52 -0400 |
parents | 4b7f0ee35994 |
children | ef6d572c4e1e |
files | shelltools/query-pr/query.py |
diffstat | 1 files changed, 883 insertions(+), 883 deletions(-) [+] |
line wrap: on
line diff
--- a/shelltools/query-pr/query.py Sat Apr 02 18:10:30 2022 -0400 +++ b/shelltools/query-pr/query.py Sat Apr 02 18:10:52 2022 -0400 @@ -30,190 +30,190 @@ # class QueryBuilder: - # these fields are in the PRs table - prtable_fields = [ - "id", "synopsis", "confidential", "state", "locked", - "timeout_date", "timeout_state", - "arrival_schemaversion", "arrival_date", "modified_date", - "closed_date", - "release", "environment" - ] + # these fields are in the PRs table + prtable_fields = [ + "id", "synopsis", "confidential", "state", "locked", + "timeout_date", "timeout_state", + "arrival_schemaversion", "arrival_date", "modified_date", + "closed_date", + "release", "environment" + ] - # these fields are aliases for others - alias_fields = { - "number" : "id", - "date" : "arrival_date", - } + # these fields are aliases for others + alias_fields = { + "number" : "id", + "date" : "arrival_date", + } - def __init__(self): - self.present = {} - self.joined = {} - self.fromitems = [] - self.whereitems = [] - self.order = None + def __init__(self): + self.present = {} + self.joined = {} + self.fromitems = [] + self.whereitems = [] + self.order = None - def setorder(self, order): - self.order = order + def setorder(self, order): + self.order = order - # add to present{} and return the value for convenience (internal) - def makepresent(self, field, name): - self.present[field] = name - return name + # add to present{} and return the value for convenience (internal) + def makepresent(self, field, name): + self.present[field] = name + return name - # add a join item (once only) (internal) - def addjoin(self, table, as_ = None): - if as_ is not None: - key = table + "-" + as_ - val = table + " AS " + as_ - else: - key = table - val = table - if key not in self.joined: - self.joined[key] = True - self.fromitems.append(val) + # add a join item (once only) (internal) + def addjoin(self, table, as_ = None): + if as_ is not None: + key = table + "-" + as_ + val = table + " AS " + as_ + else: + key = table + val = table + if key not in self.joined: + self.joined[key] = True + self.fromitems.append(val) - # returns a sql expression for the field - def getfield(self, field): - # already-fetched fields - if field in self.present: - return self.present[field] + # returns a sql expression for the field + def getfield(self, field): + # already-fetched fields + if field in self.present: + return self.present[field] - # aliases for other fields - if field in alias_fields: - return self.getfield(alias_fields[field]) + # aliases for other fields + if field in alias_fields: + return self.getfield(alias_fields[field]) - # simple fields directly in the PRs table - if field in prtable_fields: - self.addjoin("PRs") - return self.makepresent(field, "PRs." + field) + # simple fields directly in the PRs table + if field in prtable_fields: + self.addjoin("PRs") + return self.makepresent(field, "PRs." + field) - # now it gets more interesting... - if field == "closed": - self.addjoin("PRs") - self.addjoin("states") - self.addwhere("PRs.state = states.name") - return self.makepresent(field, "states.closed") + # now it gets more interesting... + if field == "closed": + self.addjoin("PRs") + self.addjoin("states") + self.addwhere("PRs.state = states.name") + return self.makepresent(field, "states.closed") - # XXX let's pick one set of names and use them everywhere - # (e.g. change "posttime" in the schema to "message_date" - # or something) - if field == "comment_date" or field == "posttime": - self.addjoin("PRs") - self.addjoin("messages") - self.addwhere("PRs.id = messages.pr") - return self.makepresent(field, "messages.posttime") + # XXX let's pick one set of names and use them everywhere + # (e.g. change "posttime" in the schema to "message_date" + # or something) + if field == "comment_date" or field == "posttime": + self.addjoin("PRs") + self.addjoin("messages") + self.addwhere("PRs.id = messages.pr") + return self.makepresent(field, "messages.posttime") - if field == "comment" or field == "message" or field == "post": - self.addjoin("PRs") - self.addjoin("messages") - self.addwhere("PRs.id = messages.pr") - return self.makepresent(field, "messages.body") + if field == "comment" or field == "message" or field == "post": + self.addjoin("PRs") + self.addjoin("messages") + self.addwhere("PRs.id = messages.pr") + return self.makepresent(field, "messages.body") - if field == "attachment": - self.addjoin("PRs") - self.addjoin("messages") - self.addjoin("attachments") - self.addwhere("PRs.id = messages.pr") - self.addwhere("messages.id = attachments.msgid") - return self.makepresent(field, "attachments.body") + if field == "attachment": + self.addjoin("PRs") + self.addjoin("messages") + self.addjoin("attachments") + self.addwhere("PRs.id = messages.pr") + self.addwhere("messages.id = attachments.msgid") + return self.makepresent(field, "attachments.body") - if field == "patch": - self.addjoin("PRs") - self.addjoin("messages") - self.addjoin("attachments", "patches") - self.addwhere("PRs.id = messages.pr") - self.addwhere("messages.id = patches.msgid") - self.addwhere("patches.mimetype = " + - "'application/x-patch'") - return self.makepresent(field, "patches.body") + if field == "patch": + self.addjoin("PRs") + self.addjoin("messages") + self.addjoin("attachments", "patches") + self.addwhere("PRs.id = messages.pr") + self.addwhere("messages.id = patches.msgid") + self.addwhere("patches.mimetype = " + + "'application/x-patch'") + return self.makepresent(field, "patches.body") - if field == "mimetype": - subquery = "((SELECT mtmessages1.pr as pr, " + \ - "mtmessages1.mimetype as mimetype " + \ - "FROM messages as mtmessages1) " + \ - "UNION " + \ - "(SELECT mtmessages2.pr as pr, " + \ - "mtattach2.mimetype as mimetype " + \ - "FROM messages as mtmessages2, " + \ - " attachments as mtattach2 " + \ - "WHERE mtmessages2.id = mtattach2.msgid))" - self.addjoin("PRs") - self.addjoin(subquery, "mimetypes") - self.addwhere("PRs.id = mimetypes.pr") - return self.makepresent(field, "mimetypes.mimetype") + if field == "mimetype": + subquery = "((SELECT mtmessages1.pr as pr, " + \ + "mtmessages1.mimetype as mimetype " + \ + "FROM messages as mtmessages1) " + \ + "UNION " + \ + "(SELECT mtmessages2.pr as pr, " + \ + "mtattach2.mimetype as mimetype " + \ + "FROM messages as mtmessages2, " + \ + " attachments as mtattach2 " + \ + "WHERE mtmessages2.id = mtattach2.msgid))" + self.addjoin("PRs") + self.addjoin(subquery, "mimetypes") + self.addwhere("PRs.id = mimetypes.pr") + return self.makepresent(field, "mimetypes.mimetype") - # XXX: need view userstrings - # select (id, username as name) from users - # union select (id, realname as name) from users - # (allow searching emails? ugh) - if field == "originator" or field == "submitter": - self.addjoin("PRs") - self.addjoin("userstrings", "originators") - self.addwhere("PRs.originator = originators.id") - return self.makepresent(field, "originators.name") + # XXX: need view userstrings + # select (id, username as name) from users + # union select (id, realname as name) from users + # (allow searching emails? ugh) + if field == "originator" or field == "submitter": + self.addjoin("PRs") + self.addjoin("userstrings", "originators") + self.addwhere("PRs.originator = originators.id") + return self.makepresent(field, "originators.name") - if field == "reporter" or field == "respondent": - self.addjoin("PRs") - self.addjoin("subscriptions") - self.addjoin("userstrings", "reporters") - self.addwhere("subscriptions.userid = reporters.id") - self.addwhere("subscriptions.reporter") - return self.makepresent(field, "reporters.name") + if field == "reporter" or field == "respondent": + self.addjoin("PRs") + self.addjoin("subscriptions") + self.addjoin("userstrings", "reporters") + self.addwhere("subscriptions.userid = reporters.id") + self.addwhere("subscriptions.reporter") + return self.makepresent(field, "reporters.name") - if field == "responsible": - self.addjoin("PRs") - self.addjoin("subscriptions") - self.addjoin("userstrings", "responsibles") - self.addwhere("subscriptions.userid = responsibles.id") - self.addwhere("subscriptions.responsible") - return self.makepresent(field, "responsibles.name") + if field == "responsible": + self.addjoin("PRs") + self.addjoin("subscriptions") + self.addjoin("userstrings", "responsibles") + self.addwhere("subscriptions.userid = responsibles.id") + self.addwhere("subscriptions.responsible") + return self.makepresent(field, "responsibles.name") - if field in hierclasses: - col = field + "_data" - self.addjoin("PRs") - self.addjoin("hierclass_data", col) - self.addwhere("PRs.id = %s.pr" % col) - self.addwhere("%s.scheme = '%s'" % (col, field)) - return self.makepresent(field, "%s.value" % col) + if field in hierclasses: + col = field + "_data" + self.addjoin("PRs") + self.addjoin("hierclass_data", col) + self.addwhere("PRs.id = %s.pr" % col) + self.addwhere("%s.scheme = '%s'" % (col, field)) + return self.makepresent(field, "%s.value" % col) - if field in flatclasses: - col = field + "_data" - self.addjoin("PRs") - self.addjoin("flatclass_data", col) - self.addwhere("PRs.id = %s.pr" % col) - self.addwhere("%s.scheme = '%s'" % (col, field)) - return self.makepresent(field, "%s.value" % col) + if field in flatclasses: + col = field + "_data" + self.addjoin("PRs") + self.addjoin("flatclass_data", col) + self.addwhere("PRs.id = %s.pr" % col) + self.addwhere("%s.scheme = '%s'" % (col, field)) + return self.makepresent(field, "%s.value" % col) - if field in textclasses: - col = field + "_data" - self.addjoin("PRs") - self.addjoin("textclass_data", col) - self.addwhere("PRs.id = %s.pr" % col) - self.addwhere("%s.scheme = '%s'" % (col, field)) - return self.makepresent(field, "%s.value" % col) + if field in textclasses: + col = field + "_data" + self.addjoin("PRs") + self.addjoin("textclass_data", col) + self.addwhere("PRs.id = %s.pr" % col) + self.addwhere("%s.scheme = '%s'" % (col, field)) + return self.makepresent(field, "%s.value" % col) - if field in tagclasses: - col = field + "_data" - self.addjoin("PRs") - self.addjoin("tagclass_data", col) - self.addwhere("PRs.id = %s.pr" % col) - self.addwhere("%s.scheme = '%s'" % (col, field)) - return self.makepresent(field, "%s.value" % col) + if field in tagclasses: + col = field + "_data" + self.addjoin("PRs") + self.addjoin("tagclass_data", col) + self.addwhere("PRs.id = %s.pr" % col) + self.addwhere("%s.scheme = '%s'" % (col, field)) + return self.makepresent(field, "%s.value" % col) - sys.stderr.write("Unknown field %s" % field) - exit(1) - # end getfield + sys.stderr.write("Unknown field %s" % field) + exit(1) + # end getfield - # emit sql - def build(self, sels): - s = ", ".join(sels) - f = ", ".join(self.fromitems) - w = " and ".join(self.whereitems) - q = "SELECT %s\nFROM %s\nWHERE %s\n" % (s, f, w) - if self.order is not None: - q = q + "ORDER BY " + self.order + "\n" - return q - # endif + # emit sql + def build(self, sels): + s = ", ".join(sels) + f = ", ".join(self.fromitems) + w = " and ".join(self.whereitems) + q = "SELECT %s\nFROM %s\nWHERE %s\n" % (s, f, w) + if self.order is not None: + q = q + "ORDER BY " + self.order + "\n" + return q + # endif # end class QueryBuilder @@ -229,33 +229,33 @@ dblink = None def opendb(): - global dblink + global dblink - host = "localhost" - user = "swallowtail" - database = "swallowtail" - dblink = psycopg2.connect("host=%s user=%s dbname=%s" % - (host, user, database)) + host = "localhost" + user = "swallowtail" + database = "swallowtail" + dblink = psycopg2.connect("host=%s user=%s dbname=%s" % + (host, user, database)) # end opendb def closedb(): - global dblink + global dblink - dblink.close() - dblink = None + dblink.close() + dblink = None # end closedb def querydb(qtext, args): - print "Executing this query:" - print qtext - print "Args are:" - print args + print "Executing this query:" + print qtext + print "Args are:" + print args - cursor = dblink.cursor() - cursor.execute(qtext, args) - result = cursor.fetchall() - cursor.close() - return result + cursor = dblink.cursor() + cursor.execute(qtext, args) + result = cursor.fetchall() + cursor.close() + return result # end querydb ############################################################ @@ -263,58 +263,58 @@ # XXX: obsolete, remove class Query: - def __init__(self): - self.selections = [] - self.tables = [] - self.constraints = [] - self.args = [] - prtables = ["PRs"] - prconstraints = [] + def __init__(self): + self.selections = [] + self.tables = [] + self.constraints = [] + self.args = [] + prtables = ["PRs"] + prconstraints = [] - def select(self, s): - self.selections.append(s) + def select(self, s): + self.selections.append(s) - def addtable(self, t): - assert(t not in self.tables) - self.tables.append(t) + def addtable(self, t): + assert(t not in self.tables) + self.tables.append(t) - def constrain(self, expr): - self.constraints.append(t) + def constrain(self, expr): + self.constraints.append(t) - def internval(self, val): - num = len(self.args) - self.args[num] = val - return "$%d" % num + def internval(self, val): + num = len(self.args) + self.args[num] = val + return "$%d" % num - def textify(self): - s = "SELECT %s\n" % ",".join(self.selections) - f = "FROM %s\n" % ",".join(self.tables) - w = "WHERE %s\n" % " AND ".join(self.constraints) - return s + f + w + def textify(self): + s = "SELECT %s\n" % ",".join(self.selections) + f = "FROM %s\n" % ",".join(self.tables) + w = "WHERE %s\n" % " AND ".join(self.constraints) + return s + f + w # end class Query def regexp_constraint(q, field, value): - cleanval = q.internval(value) - if not isregexp(value): - return "%s = %s" % (field, cleanval) - else: - # XXX what's the right operator again? - return "%s ~= %s" % (field, cleanval) + cleanval = q.internval(value) + if not isregexp(value): + return "%s = %s" % (field, cleanval) + else: + # XXX what's the right operator again? + return "%s ~= %s" % (field, cleanval) # end regexp_constraint def intrange_constraint(q, field, value): - (lower, upper) = args.number - if lower is not None: - assert(typeof(lower) == int) - prq.constrain("%s >= %d" % (field, lower)) - if upper is not None: - assert(typeof(upper) == int) - prq.constrain("%s <= %d" % (field, upper)) + (lower, upper) = args.number + if lower is not None: + assert(typeof(lower) == int) + prq.constrain("%s >= %d" % (field, lower)) + if upper is not None: + assert(typeof(upper) == int) + prq.constrain("%s <= %d" % (field, upper)) # end intrange_constraint def daterange_constraint(q, field, value): - # XXX - assert(0) + # XXX + assert(0) # end daterange_constraint ############################################################ @@ -322,513 +322,513 @@ # this is old code that needs to be merged or deleted into the new stuff def oldstuff(): - # If we're doing something other than a search, do it now - if args.attach is not None: - get_attachment(args.attach) - exit(0) - if args.message is not None: - get_message(args.message) - exit(0) + # If we're doing something other than a search, do it now + if args.attach is not None: + get_attachment(args.attach) + exit(0) + if args.message is not None: + get_message(args.message) + exit(0) - if args.prs is not None and len(args.prs) > 0: - show_prs(args.prs) - exit(0) + if args.prs is not None and len(args.prs) > 0: + show_prs(args.prs) + exit(0) - # - # Collect up the search constraints - # - - # 1. Constraints on the PRs table - checkprtable = False - prq = Query() - prq.select("PRs.id as id") - prq.addtable("PRs") - if not args.closed: - checkprtable = True - prq.addtable("states") - prq.constrain("PRs.state = states.name") - prq.constrain("states.closed = FALSE") - if args.public: - checkprtable = True - prq.constrain("NOT PRs.confidential") - if args.number is not None: - checkprtable = True - intrange_constraint(prq, "PRs.id", args.number) - if args.synopsis is not None: - checkprtable = True - regexp_constraint(prq, "PRs.synopsis", args.synopsis) - if args.confidential is not None: - checkprtable = True - assert(typeof(args.confidential) == bool) - if args.confidential: - prq.constrain("PRs.confidential") - else: - prq.constrain("not PRs.confidential") - if args.state is not None: - checkprtable = True - regexp_constraint(prq, "PRs.state", args.state) - if args.locked is not None: - checkprtable = True - assert(typeof(args.locked) == bool) - if args.locked: - prq.constrain("PRs.locked") - else: - prq.constrain("not PRs.locked") - if args.arrival_schemaversion is not None: - checkprtable = True - intrange_constraint(prq, "PRs.arrival_schemaversion", - args.arrival_schemaversion) - if args.arrival_date is not None: - checkprtable = True - daterange_constraint(prq, "PRs.arrival_date", - args.arrival_date) - if args.closed_date is not None: - checkprtable = True - daterange_constraint(prq, "PRs.closed_date", - args.closed_date) - if args.last_modified is not None: - checkprtable = True - daterange_constraint(prq, "PRs.last_modified", - args.last_modified) - if args.release is not None: - checkprtable = True - regexp_constraint(prq, "PRs.release", args.release) - if args.environment is not None: - checkprtable = True - regexp_constraint(prq, "PRs.environment", args.environment) + # + # Collect up the search constraints + # + + # 1. Constraints on the PRs table + checkprtable = False + prq = Query() + prq.select("PRs.id as id") + prq.addtable("PRs") + if not args.closed: + checkprtable = True + prq.addtable("states") + prq.constrain("PRs.state = states.name") + prq.constrain("states.closed = FALSE") + if args.public: + checkprtable = True + prq.constrain("NOT PRs.confidential") + if args.number is not None: + checkprtable = True + intrange_constraint(prq, "PRs.id", args.number) + if args.synopsis is not None: + checkprtable = True + regexp_constraint(prq, "PRs.synopsis", args.synopsis) + if args.confidential is not None: + checkprtable = True + assert(typeof(args.confidential) == bool) + if args.confidential: + prq.constrain("PRs.confidential") + else: + prq.constrain("not PRs.confidential") + if args.state is not None: + checkprtable = True + regexp_constraint(prq, "PRs.state", args.state) + if args.locked is not None: + checkprtable = True + assert(typeof(args.locked) == bool) + if args.locked: + prq.constrain("PRs.locked") + else: + prq.constrain("not PRs.locked") + if args.arrival_schemaversion is not None: + checkprtable = True + intrange_constraint(prq, "PRs.arrival_schemaversion", + args.arrival_schemaversion) + if args.arrival_date is not None: + checkprtable = True + daterange_constraint(prq, "PRs.arrival_date", + args.arrival_date) + if args.closed_date is not None: + checkprtable = True + daterange_constraint(prq, "PRs.closed_date", + args.closed_date) + if args.last_modified is not None: + checkprtable = True + daterange_constraint(prq, "PRs.last_modified", + args.last_modified) + if args.release is not None: + checkprtable = True + regexp_constraint(prq, "PRs.release", args.release) + if args.environment is not None: + checkprtable = True + regexp_constraint(prq, "PRs.environment", args.environment) - if args.originator_name is not None or \ - args.originator_email is not None: - prq.addtable("usermail as originator") - prq.constrain("PRs.originator = originator.id") - if args.originator_name is not None: - checkprtable = True - regexp_constraint(prq, "originator.realname", - args.originator_name) - if args.originator_email is not None: - checkprtable = True - regexp_constraint(prq, "originator.email", - args.originator_name) - if args.originator_id is not None: - checkprtable = True - intrange_constraint(prq, "PRs.originator", args.originator_id) + if args.originator_name is not None or \ + args.originator_email is not None: + prq.addtable("usermail as originator") + prq.constrain("PRs.originator = originator.id") + if args.originator_name is not None: + checkprtable = True + regexp_constraint(prq, "originator.realname", + args.originator_name) + if args.originator_email is not None: + checkprtable = True + regexp_constraint(prq, "originator.email", + args.originator_name) + if args.originator_id is not None: + checkprtable = True + intrange_constraint(prq, "PRs.originator", args.originator_id) - queries = [] - if checkprtable: - queries.append(prq) + queries = [] + if checkprtable: + queries.append(prq) - if args.responsible is not None: - sq = Query() - sq.select("subscriptions.pr as id") - sq.addtable("subscriptions") - sq.addtable("users") - sq.constrain("subscriptions.userid = users.id") - regexp_constraint(sq, "users.realname", args.responsible) - sq.constrain("subscriptions.responsible") - queries.append(sq) - if args.respondent is not None: - sq = Query() - sq.select("subscriptions.pr as id") - sq.addtable("subscriptions") - sq.addtable("users as subscribed") - sq.constrain("subscriptions.userid = users.id") - regexp_constraint(sq, "users.realname", args.respondent) - sq.constrain("subscriptions.reporter") - queries.append(sq) - if args.subscribed is not None: - sq = Query() - sq.select("subscriptions.pr as id") - sq.addtable("subscriptions") - sq.addtable("users as subscribed") - sq.constrain("subscriptions.userid = users.id") - regexp_constraint(sq, "users.realname", args.subscribed) - queries.append(sq) + if args.responsible is not None: + sq = Query() + sq.select("subscriptions.pr as id") + sq.addtable("subscriptions") + sq.addtable("users") + sq.constrain("subscriptions.userid = users.id") + regexp_constraint(sq, "users.realname", args.responsible) + sq.constrain("subscriptions.responsible") + queries.append(sq) + if args.respondent is not None: + sq = Query() + sq.select("subscriptions.pr as id") + sq.addtable("subscriptions") + sq.addtable("users as subscribed") + sq.constrain("subscriptions.userid = users.id") + regexp_constraint(sq, "users.realname", args.respondent) + sq.constrain("subscriptions.reporter") + queries.append(sq) + if args.subscribed is not None: + sq = Query() + sq.select("subscriptions.pr as id") + sq.addtable("subscriptions") + sq.addtable("users as subscribed") + sq.constrain("subscriptions.userid = users.id") + regexp_constraint(sq, "users.realname", args.subscribed) + queries.append(sq) - if args.messages is not None: - mq = Query() - mq.select("messages.pr as id") - mq.addtable("messages") - regexp_constraint(sq, "messages.text", args.messages) - queries.append(mq) + if args.messages is not None: + mq = Query() + mq.select("messages.pr as id") + mq.addtable("messages") + regexp_constraint(sq, "messages.text", args.messages) + queries.append(mq) - if args.adminlog is not None: - aq = Query() - aq.select("adminlog.pr as id") - aq.addtable("adminlog") - regexp_constraint(sq, "adminlog.change", args.adminlog) - regexp_constraint(sq, "adminlog.comment", args.adminlog) - assert(len(aq.constraints) == 2) - x = "%s OR %s" % (aq.constraints[0], aq.constraints[1]) - aq.constraints = [x] - queries.append(aq) + if args.adminlog is not None: + aq = Query() + aq.select("adminlog.pr as id") + aq.addtable("adminlog") + regexp_constraint(sq, "adminlog.change", args.adminlog) + regexp_constraint(sq, "adminlog.comment", args.adminlog) + assert(len(aq.constraints) == 2) + x = "%s OR %s" % (aq.constraints[0], aq.constraints[1]) + aq.constraints = [x] + queries.append(aq) - if args.anytext is not None: - choke("--anytext isn't supported yet") + if args.anytext is not None: + choke("--anytext isn't supported yet") - for scheme in classification_schemes: - if args[scheme] is not None: - schemetype = classification_schemetypes[scheme] - tbl = "%sclass_data" % schemetype - cq = Query() - cq.select("scheme.pr as id") - cq.addtable("%s as scheme" % schemetype) - cq.constrain("scheme.scheme = '%s'" % scheme) - regexp_constraint(cq, "scheme.value", args[scheme]) - queries.append(cq) - # end loop + for scheme in classification_schemes: + if args[scheme] is not None: + schemetype = classification_schemetypes[scheme] + tbl = "%sclass_data" % schemetype + cq = Query() + cq.select("scheme.pr as id") + cq.addtable("%s as scheme" % schemetype) + cq.constrain("scheme.scheme = '%s'" % scheme) + regexp_constraint(cq, "scheme.value", args[scheme]) + queries.append(cq) + # end loop - querytexts = [q.textify() for q in queries] - return "INTERSECT\n".join(querytexts) + querytexts = [q.textify() for q in queries] + return "INTERSECT\n".join(querytexts) ############################################################ # printing class PrintText: - def __init__(self, output): - self.lines = (output == "RAW" or output == "LIST") - def printheader(self, row): - # nothing + def __init__(self, output): + self.lines = (output == "RAW" or output == "LIST") + def printheader(self, row): + # nothing pass - def printrow(self, row): - # XXX - print row - def printfooter(self, row): - # nothing + def printrow(self, row): + # XXX + print row + def printfooter(self, row): + # nothing pass # end class PrintText class PrintCsv: - def __init__(self, output): - # nothing + def __init__(self, output): + # nothing pass - def printheader(self, row): - # XXX + def printheader(self, row): + # XXX pass - def printrow(self, row): - # XXX + def printrow(self, row): + # XXX pass - def printfooter(self, row): - # nothing + def printfooter(self, row): + # nothing pass # end class PrintCsv class PrintXml: - def __init__(self, output): - # nothing + def __init__(self, output): + # nothing pass - def printheader(self, row): - # XXX + def printheader(self, row): + # XXX pass - def printrow(self, row): - # XXX + def printrow(self, row): + # XXX pass - def printfooter(self, row): - # XXX + def printfooter(self, row): + # XXX pass # end class PrintXml class PrintJson: - def __init__(self, output): - # nothing + def __init__(self, output): + # nothing pass - def printheader(self, row): - # XXX + def printheader(self, row): + # XXX pass - def printrow(self, row): - # XXX + def printrow(self, row): + # XXX pass - def printfooter(self, row): - # XXX + def printfooter(self, row): + # XXX pass # end class PrintJson class PrintRdf: - def __init__(self, output): - # nothing + def __init__(self, output): + # nothing pass - def printheader(self, row): - # XXX + def printheader(self, row): + # XXX pass - def printrow(self, row): - # XXX + def printrow(self, row): + # XXX pass - def printfooter(self, row): - # XXX + def printfooter(self, row): + # XXX pass # end class PrintRdf class PrintRdflike: - def __init__(self, output): - # nothing + def __init__(self, output): + # nothing pass - def printheader(self, row): - # XXX + def printheader(self, row): + # XXX pass - def printrow(self, row): - # XXX + def printrow(self, row): + # XXX pass - def printfooter(self, row): - # XXX + def printfooter(self, row): + # XXX pass # end class PrintRdflike def print_prs(ids): - if sel.outformat == "TEXT": - mkprinter = PrintText - elif sel.outformat == "CSV": - mkprinter = PrintCsv - elif sel.outformat == "XML": - mkprinter = PrintXml - elif sel.outformat == "JSON": - mkprinter = PrintJson - elif sel.outformat == "RDF": - mkprinter = PrintRdf - elif sel.outformat == "RDFLIKE": - mkprinter = PrintRdflike - else: - assert(False) + if sel.outformat == "TEXT": + mkprinter = PrintText + elif sel.outformat == "CSV": + mkprinter = PrintCsv + elif sel.outformat == "XML": + mkprinter = PrintXml + elif sel.outformat == "JSON": + mkprinter = PrintJson + elif sel.outformat == "RDF": + mkprinter = PrintRdf + elif sel.outformat == "RDFLIKE": + mkprinter = PrintRdflike + else: + assert(False) - # reset the printer - printer = mkprinter(sel.output) + # reset the printer + printer = mkprinter(sel.output) - if sel.output == "RAW": - printer.printheader(ids[0]) - for id in ids: - printer(id) - printer.printfooter(ids[0]) - return - elif sel.output == "LIST": - # XXX is there a clean way to do this passing the - # whole list of ids at once? - query = "SELECT id, synopsis\n" + \ - "FROM PRs\n" + \ - "WHERE id = $1" - elif sel.output == "HEADERS": - query = None # XXX - elif sel.output == "META": - query = None # XXX - elif sel.output == "FULL": - query = None # XXX - else: - assert(False) + if sel.output == "RAW": + printer.printheader(ids[0]) + for id in ids: + printer(id) + printer.printfooter(ids[0]) + return + elif sel.output == "LIST": + # XXX is there a clean way to do this passing the + # whole list of ids at once? + query = "SELECT id, synopsis\n" + \ + "FROM PRs\n" + \ + "WHERE id = $1" + elif sel.output == "HEADERS": + query = None # XXX + elif sel.output == "META": + query = None # XXX + elif sel.output == "FULL": + query = None # XXX + else: + assert(False) - first = True - for id in ids: - results = querydb(query, [id]) - if first: - printer.printheader(results[0]) - first = False - for r in results: - printer.printrow(r) - printer.printfooter(results[0]) + first = True + for id in ids: + results = querydb(query, [id]) + if first: + printer.printheader(results[0]) + first = False + for r in results: + printer.printrow(r) + printer.printfooter(results[0]) # end print_prs # XXX if in public mode we need to check if the PR is public def print_message(pr, msgnum): - query = "SELECT users.username AS username,\n" + \ - " users.realname AS realname,\n" + \ - " messages.id AS id, parent_id,\n" + \ - " posttime, mimetype, body\n" + \ - "FROM messages, users\n" + \ - "WHERE messages.who = users.id\n" + \ - " AND messages.pr = $1\n" + \ - " AND messages.number_in_pr = $2\n" - # Note that while pr is safe, msgnum came from the commandline - # and may not be. - results = querydb(query, [pr, msgnum]) - [result] = results - (username, realname, id, parent_id, posttime, mimetype, body) = result - # XXX honor mimetype - # XXX honor output format (e.g. html) - sys.stdout.write("From swallowtail@%s %s\n" % (organization,posttime)) - sys.stdout.write("From: %s (%s)\n" % (username, realname)) - sys.stdout.write("References: %s\n" % parent_id) - sys.stdout.write("Date: %s\n" % posttime) - sys.stdout.write("Content-Type: %s\n" % mimetype) - sys.stdout.write("\n") - sys.stdout.write(body) + query = "SELECT users.username AS username,\n" + \ + " users.realname AS realname,\n" + \ + " messages.id AS id, parent_id,\n" + \ + " posttime, mimetype, body\n" + \ + "FROM messages, users\n" + \ + "WHERE messages.who = users.id\n" + \ + " AND messages.pr = $1\n" + \ + " AND messages.number_in_pr = $2\n" + # Note that while pr is safe, msgnum came from the commandline + # and may not be. + results = querydb(query, [pr, msgnum]) + [result] = results + (username, realname, id, parent_id, posttime, mimetype, body) = result + # XXX honor mimetype + # XXX honor output format (e.g. html) + sys.stdout.write("From swallowtail@%s %s\n" % (organization,posttime)) + sys.stdout.write("From: %s (%s)\n" % (username, realname)) + sys.stdout.write("References: %s\n" % parent_id) + sys.stdout.write("Date: %s\n" % posttime) + sys.stdout.write("Content-Type: %s\n" % mimetype) + sys.stdout.write("\n") + sys.stdout.write(body) # end print_message # XXX if in public mode we need to check if the PR is public def print_attachment(pr, attachnum): - query = "SELECT a.mimetype as mimetype, a.body as body\n" + \ - "FROM messages, attachments as a\n" + \ - "WHERE messages.pr = $1\n" + \ - " AND messages.id = a.msgid\n" + \ - " AND a.number_in_pr = $2\n" - # Note that while pr is safe, attachnum came from the - # commandline and may not be. - results = querydb(query, [pr, msgnum]) - [result] = results - (mimetype, body) = result - # XXX honor mimetype - # XXX need an http output mode so we can send the mimetype! - sys.stdout.write(body) + query = "SELECT a.mimetype as mimetype, a.body as body\n" + \ + "FROM messages, attachments as a\n" + \ + "WHERE messages.pr = $1\n" + \ + " AND messages.id = a.msgid\n" + \ + " AND a.number_in_pr = $2\n" + # Note that while pr is safe, attachnum came from the + # commandline and may not be. + results = querydb(query, [pr, msgnum]) + [result] = results + (mimetype, body) = result + # XXX honor mimetype + # XXX need an http output mode so we can send the mimetype! + sys.stdout.write(body) # end print_attachment ############################################################ # AST for query class Invocation: - class Query: - Q_TERM = 1 # XXX unused so far - Q_SQL = 2 - Q_AND = 3 - Q_OR = 4 - Q_TSTRING = 5 - Q_QSTRING = 6 + class Query: + Q_TERM = 1 # XXX unused so far + Q_SQL = 2 + Q_AND = 3 + Q_OR = 4 + Q_TSTRING = 5 + Q_QSTRING = 6 - def __init__(self, type): - self.type = type - def doterm(term): - self = Query(Q_TERM) - self.term = term - return self - def dosql(s): - self = Query(Q_SQL) - self.sql = s - return self - def doand(qs): - self = Query(Q_AND) - self.args = qs - return self - def door(qs): - self = Query(Q_OR) - self.args = qs - return self - # query term string - def dotstring(q): - self = Query(Q_TSTRING) - self.string = q - return self - # whole query string - def doqstring(q): - self = Query(Q_QSTRING) - self.string = q - return self - # end class Query + def __init__(self, type): + self.type = type + def doterm(term): + self = Query(Q_TERM) + self.term = term + return self + def dosql(s): + self = Query(Q_SQL) + self.sql = s + return self + def doand(qs): + self = Query(Q_AND) + self.args = qs + return self + def door(qs): + self = Query(Q_OR) + self.args = qs + return self + # query term string + def dotstring(q): + self = Query(Q_TSTRING) + self.string = q + return self + # whole query string + def doqstring(q): + self = Query(Q_QSTRING) + self.string = q + return self + # end class Query - class Order: - def __init__(self, field, rev = False): - self.field = field - self.rev = rev - def dooldest(ign): - return Order("number") - def donewest(ign): - return Order("number", True) - def dostaleness(ign): - return Order("modified_date", True) - def dofield(field): - return Order(field) - def dorevfield(field): - return Order(field, True) - # end class Order + class Order: + def __init__(self, field, rev = False): + self.field = field + self.rev = rev + def dooldest(ign): + return Order("number") + def donewest(ign): + return Order("number", True) + def dostaleness(ign): + return Order("modified_date", True) + def dofield(field): + return Order(field) + def dorevfield(field): + return Order(field, True) + # end class Order - class Search: - def __init__(self, qs, openonly, publiconly, os): - self.queries = qs - self.openonly = openonly - self.publiconly = publiconly - self.orders = os - # end class Search + class Search: + def __init__(self, qs, openonly, publiconly, os): + self.queries = qs + self.openonly = openonly + self.publiconly = publiconly + self.orders = os + # end class Search - class Selection: - S_PR = 1 - S_MESSAGE = 2 - S_ATTACHMENT = 3 + class Selection: + S_PR = 1 + S_MESSAGE = 2 + S_ATTACHMENT = 3 - def __init__(self, type): - self.type = type - def dopr(output, outformat): - self = Selection(S_PR) - self.output = output - self.outformat = outformat - return self - def domessage(arg): - self = Selection(S_MESSAGE) - self.message = arg - return self - def doattachment(arg): - self = Selection(S_ATTACHMENT) - self.attachment = arg - return self - # end class Selection + def __init__(self, type): + self.type = type + def dopr(output, outformat): + self = Selection(S_PR) + self.output = output + self.outformat = outformat + return self + def domessage(arg): + self = Selection(S_MESSAGE) + self.message = arg + return self + def doattachment(arg): + self = Selection(S_ATTACHMENT) + self.attachment = arg + return self + # end class Selection - class Op: - # operation codes - OP_FIELDS = 1 - OP_SHOW = 2 - OP_RANGE = 3 - OP_SEARCH = 4 + class Op: + # operation codes + OP_FIELDS = 1 + OP_SHOW = 2 + OP_RANGE = 3 + OP_SEARCH = 4 - def __init__(self, type): - self.type = type + def __init__(self, type): + self.type = type - def dofields(): - return Op(OP_FIELDS) - def doshow(field): - self = Op(OP_SHOW) - self.field = field - return self - def dorange(field): - self = Op(OP_RANGE) - self.field = field - return self - def dosearch(s, sels): - self = Op(OP_SEARCH) - self.search = s - self.sels = sels - return self - # end class Op + def dofields(): + return Op(OP_FIELDS) + def doshow(field): + self = Op(OP_SHOW) + self.field = field + return self + def dorange(field): + self = Op(OP_RANGE) + self.field = field + return self + def dosearch(s, sels): + self = Op(OP_SEARCH) + self.search = s + self.sels = sels + return self + # end class Op - def __init__(self, ops): - self.ops = ops + def __init__(self, ops): + self.ops = ops # end class Invocation ############################################################ # run (eval the SQL and print the results) def run_sel(sel, ids): - if sel.type == S_PR: - if ids == []: - sys.stderr.write("No PRs matched.\n") - exit(1) + if sel.type == S_PR: + if ids == []: + sys.stderr.write("No PRs matched.\n") + exit(1) - print_prs(ids) - elif sel.type == S_MESSAGE: - if len(ids) != 1: - sys.stderr.write("Cannot retrieve messages " + - "from multiple PRs.") - exit(1) - print_message(ids[0], sel.message) - elif sel.type == S_ATTACHMENT: - if len(ids) != 1: - sys.stderr.write("Cannot retrieve attachments " + - "from multiple PRs.") - exit(1) - print_message(ids[0], sel.attachment) - else: - assert(False) + print_prs(ids) + elif sel.type == S_MESSAGE: + if len(ids) != 1: + sys.stderr.write("Cannot retrieve messages " + + "from multiple PRs.") + exit(1) + print_message(ids[0], sel.message) + elif sel.type == S_ATTACHMENT: + if len(ids) != 1: + sys.stderr.write("Cannot retrieve attachments " + + "from multiple PRs.") + exit(1) + print_message(ids[0], sel.attachment) + else: + assert(False) def run_op(op): - if op.type == OP_FIELDS: - list_fields() - elif op.type == OP_SHOW: - describe_field(op.field) - elif op.type == OP_RANGE: - print_field_range(op.field) - elif op.type == OP_SEARCH: - sql = op.search - args = op.args # XXX not there! - ids = querydb(op.search, args) - for s in op.sels: - run_sel(s, ids) - else: - assert(False) + if op.type == OP_FIELDS: + list_fields() + elif op.type == OP_SHOW: + describe_field(op.field) + elif op.type == OP_RANGE: + print_field_range(op.field) + elif op.type == OP_SEARCH: + sql = op.search + args = op.args # XXX not there! + ids = querydb(op.search, args) + for s in op.sels: + run_sel(s, ids) + else: + assert(False) def run(ast): - for op in ast.ops: - run_op(op) + for op in ast.ops: + run_op(op) ############################################################ # compile (convert the AST so the searches are pure SQL) @@ -843,127 +843,127 @@ return True def compile_query(q): - if q.type == Q_QSTRING: - # XXX should use a split that honors quotes - terms = q.string.split() - terms = [dotstring(t) for t in terms] - return compile_query(doand(terms)) - if q.type == Q_TSTRING: - qb = QueryBuilder() - s = q.string - if matches(s, "^[0-9]+$"): - f = qb.getfield("number") - # Note: s is user-supplied but clean to insert directly - qb.addwhere("%s = %s" % (f, s)) - elif matches(s, "^[0-9]+-[0-9]+$"): - f = qb.getfield("number") - ss = s.split("-") - # Note: ss[] is user-supplied but clean - qb.addwhere("%s >= %s" % (f, ss[0])) - qb.addwhere("%s <= %s" % (f, ss[1])) - elif matches(s, "^[0-9]+-$"): - f = qb.getfield("number") - ss = s.split("-") - # Note: ss[] is user-supplied but clean - qb.addwhere("%s >= %s" % (f, ss[0])) - elif matches(s, "^-[0-9]+$"): - f = qb.getfield("number") - ss = s.split("-") - # Note: ss[] is user-supplied but clean - qb.addwhere("%s <= %s" % (f, ss[1])) - elif matches(s, "^[^:]+:[^:]+$"): - # XXX honor quoted terms - # XXX = or LIKE? - ss = s.split(":") - # ss[0] is not clean but if it's crap it won't match - f = qb.getfield(ss[0]) - # ss[1] is not clean, so intern it for safety - s = qb.intern(ss[1]) - qb.addwhere("%s = %s" % (f, s)) - elif matches(s, "^-[^:]+:[^:]+$"): - # XXX honor quoted terms - # XXX <> or NOT LIKE? - ss = s.split(":") - # ss[0] is not clean but if it's crap it won't match - f = qb.getfield(ss[0]) - # ss[1] is not clean, so intern it for safety - s = qb.intern(ss[1]) - qb.addwhere("%s <> %s" % (f, s)) - elif matches(s, "^-"): - # XXX <> or NOT LIKE? - f = qb.getfield("alltext") - # s is not clean, so intern it for safety - s = qb.intern(s) - qb.addwhere("%s <> %s" % (f, s)) - else: - # XXX = or LIKE? - f = qb.getfield("alltext") - # s is not clean, so intern it for safety - s = qb.intern(s) - qb.addwhere("%s = %s" % (f, s)) + if q.type == Q_QSTRING: + # XXX should use a split that honors quotes + terms = q.string.split() + terms = [dotstring(t) for t in terms] + return compile_query(doand(terms)) + if q.type == Q_TSTRING: + qb = QueryBuilder() + s = q.string + if matches(s, "^[0-9]+$"): + f = qb.getfield("number") + # Note: s is user-supplied but clean to insert directly + qb.addwhere("%s = %s" % (f, s)) + elif matches(s, "^[0-9]+-[0-9]+$"): + f = qb.getfield("number") + ss = s.split("-") + # Note: ss[] is user-supplied but clean + qb.addwhere("%s >= %s" % (f, ss[0])) + qb.addwhere("%s <= %s" % (f, ss[1])) + elif matches(s, "^[0-9]+-$"): + f = qb.getfield("number") + ss = s.split("-") + # Note: ss[] is user-supplied but clean + qb.addwhere("%s >= %s" % (f, ss[0])) + elif matches(s, "^-[0-9]+$"): + f = qb.getfield("number") + ss = s.split("-") + # Note: ss[] is user-supplied but clean + qb.addwhere("%s <= %s" % (f, ss[1])) + elif matches(s, "^[^:]+:[^:]+$"): + # XXX honor quoted terms + # XXX = or LIKE? + ss = s.split(":") + # ss[0] is not clean but if it's crap it won't match + f = qb.getfield(ss[0]) + # ss[1] is not clean, so intern it for safety + s = qb.intern(ss[1]) + qb.addwhere("%s = %s" % (f, s)) + elif matches(s, "^-[^:]+:[^:]+$"): + # XXX honor quoted terms + # XXX <> or NOT LIKE? + ss = s.split(":") + # ss[0] is not clean but if it's crap it won't match + f = qb.getfield(ss[0]) + # ss[1] is not clean, so intern it for safety + s = qb.intern(ss[1]) + qb.addwhere("%s <> %s" % (f, s)) + elif matches(s, "^-"): + # XXX <> or NOT LIKE? + f = qb.getfield("alltext") + # s is not clean, so intern it for safety + s = qb.intern(s) + qb.addwhere("%s <> %s" % (f, s)) + else: + # XXX = or LIKE? + f = qb.getfield("alltext") + # s is not clean, so intern it for safety + s = qb.intern(s) + qb.addwhere("%s = %s" % (f, s)) - # XXX also does not handle: - # - # field: with no string (supposed to use a default - # search string) - # - # generated search fields that parse dates: - # {arrived,closed,modified,etc.}-{before,after}:date - # - # stale:time + # XXX also does not handle: + # + # field: with no string (supposed to use a default + # search string) + # + # generated search fields that parse dates: + # {arrived,closed,modified,etc.}-{before,after}:date + # + # stale:time - return qb.build("PRs.id") - # end Q_TSTRING case - if q.type == Q_OR: - subqueries = ["(" + compile_query(sq) + ")" for sq in q.args] - return " UNION ".join(subqueries) - if q.type == Q_AND: - subqueries = ["(" + compile_query(sq) + ")" for sq in q.args] - return " INTERSECT ".join(subqueries) - if q.type == Q_SQL: - return q.sql - assert(False) + return qb.build("PRs.id") + # end Q_TSTRING case + if q.type == Q_OR: + subqueries = ["(" + compile_query(sq) + ")" for sq in q.args] + return " UNION ".join(subqueries) + if q.type == Q_AND: + subqueries = ["(" + compile_query(sq) + ")" for sq in q.args] + return " INTERSECT ".join(subqueries) + if q.type == Q_SQL: + return q.sql + assert(False) # end compile_query def compile_order(qb, o): - str = qb.getfield(o.field) - if o.rev: - str = str + " DESCENDING" - return str + str = qb.getfield(o.field) + if o.rev: + str = str + " DESCENDING" + return str def compile_search(s): - qb2 = QueryBuilder() + qb2 = QueryBuilder() - # multiple query strings are treated as OR - query = door(s.queries) - query = compile_query(q) + # multiple query strings are treated as OR + query = door(s.queries) + query = compile_query(q) - if s.openonly: - qb2.addwhere("not %s" % qb.getfield("closed")) - if s.publiconly: - qb2.addwhere("not %s" % qb.getfield("confidential")) + if s.openonly: + qb2.addwhere("not %s" % qb.getfield("closed")) + if s.publiconly: + qb2.addwhere("not %s" % qb.getfield("confidential")) - orders = [compile_order(qb2, o) for o in s.orders] - order = ", ".join(orders) - if order != "": - qb2.setorder(order) + orders = [compile_order(qb2, o) for o in s.orders] + order = ", ".join(orders) + if order != "": + qb2.setorder(order) - if qb2.nonempty(): - qb2.addjoin(query, "search") - qb2.addjoin("PRs") - qb2.addwhere("search = PRs.id") - query = qb2.build(["search"]) + if qb2.nonempty(): + qb2.addjoin(query, "search") + qb2.addjoin("PRs") + qb2.addwhere("search = PRs.id") + query = qb2.build(["search"]) - return query + return query # end compile_search def compile_op(op): - if op.type == OP_SEARCH: - op.search = compile_search(op.search) - return op + if op.type == OP_SEARCH: + op.search = compile_search(op.search) + return op def compile(ast): - ast.ops = [compile_op(op) for op in ast.ops] + ast.ops = [compile_op(op) for op in ast.ops] ############################################################ # arg handling @@ -987,167 +987,167 @@ # ctor you want to use, which seems completely insane. # class CtorAppend(argparse.Action): - def __call__(self, parser, namespace, values, option_string=None): - items = getattr(namespace, self.dest) - item = self.const(values) - items.append(item) - setattr(namespace, self.dest, items) + def __call__(self, parser, namespace, values, option_string=None): + items = getattr(namespace, self.dest) + item = self.const(values) + items.append(item) + setattr(namespace, self.dest, items) def getargs(): - p = argparse.ArgumentParser(program_description) + p = argparse.ArgumentParser(program_description) - # note: -h/--help is built in by default - p.add_argument("-v", "--version", - action='version', version=program_version, - help="Print program version and exit") + # note: -h/--help is built in by default + p.add_argument("-v", "--version", + action='version', version=program_version, + help="Print program version and exit") - p.add_argument("--show", nargs=1, - action=CtorAppend, dest='ops', - const=Invocation.Op.doshow, - help="Show description of field") - p.add_argument("--range", nargs=1, - action=CtorAppend, dest='ops', - const=Invocation.Op.dorange, - help="Show range of extant values for field") + p.add_argument("--show", nargs=1, + action=CtorAppend, dest='ops', + const=Invocation.Op.doshow, + help="Show description of field") + p.add_argument("--range", nargs=1, + action=CtorAppend, dest='ops', + const=Invocation.Op.dorange, + help="Show range of extant values for field") - p.add_argument("--search", nargs=1, - action=CtorAppend, dest='queries', - const=Invocation.Query.doqstring, - help="Force string to be read as a search string") - p.add_argument("-s", "--sql", nargs=1, - action=CtorAppend, dest='queries', - const=Invocation.Query.dosql, - help="Supply explicit sql query as search") + p.add_argument("--search", nargs=1, + action=CtorAppend, dest='queries', + const=Invocation.Query.doqstring, + help="Force string to be read as a search string") + p.add_argument("-s", "--sql", nargs=1, + action=CtorAppend, dest='queries', + const=Invocation.Query.dosql, + help="Supply explicit sql query as search") - p.add_argument("--open", - action='store_const', dest='openonly', const="True", - help="Exclude closed PRs (default)") - p.add_argument("--closed", - action='store_const', dest='openonly', const="False", - help="Include closed PRs in search") - p.add_argument("--public", - action='store_const', dest='publiconly', const="True", - help="Exclude confidential PRs") - p.add_argument("--privileged", - action='store_const', dest='publiconly', const="False", - help="Allow confidential PRs (default)") + p.add_argument("--open", + action='store_const', dest='openonly', const="True", + help="Exclude closed PRs (default)") + p.add_argument("--closed", + action='store_const', dest='openonly', const="False", + help="Include closed PRs in search") + p.add_argument("--public", + action='store_const', dest='publiconly', const="True", + help="Exclude confidential PRs") + p.add_argument("--privileged", + action='store_const', dest='publiconly', const="False", + help="Allow confidential PRs (default)") - p.add_argument("--oldest", - action=CtorAppend, dest='orders', - const=Invocation.Order.dooldest, - help="Sort output with oldest PRs first") - p.add_argument("--newest", - action=CtorAppend, dest='orders', - const=Invocation.Order.donewest, - help="Sort output with newest PRs first") - p.add_argument("--staleness", - action=CtorAppend, dest='orders', - const=Invocation.Order.dostaleness, - help="Sort output by time since last modification") - p.add_argument("--orderby", nargs=1, - action=CtorAppend, dest='orders', - const=Invocation.Order.dofield, - help="Sort output by specific field") - p.add_argument("--revorderby", nargs=1, - action=CtorAppend, dest='orders', - const=Invocation.Order.dorevfield, - help="Sort output by specific field, reversed") + p.add_argument("--oldest", + action=CtorAppend, dest='orders', + const=Invocation.Order.dooldest, + help="Sort output with oldest PRs first") + p.add_argument("--newest", + action=CtorAppend, dest='orders', + const=Invocation.Order.donewest, + help="Sort output with newest PRs first") + p.add_argument("--staleness", + action=CtorAppend, dest='orders', + const=Invocation.Order.dostaleness, + help="Sort output by time since last modification") + p.add_argument("--orderby", nargs=1, + action=CtorAppend, dest='orders', + const=Invocation.Order.dofield, + help="Sort output by specific field") + p.add_argument("--revorderby", nargs=1, + action=CtorAppend, dest='orders', + const=Invocation.Order.dorevfield, + help="Sort output by specific field, reversed") - p.add_argument("-m", "--message", nargs=1, - action=CtorAppend, dest='selections', - const=Invocation.Selection.domessage, - help="Print selected message (single PR only)") - p.add_argument("-a", "--attachment", nargs=1, - action=CtorAppend, dest='selections', - const=Invocation.Selection.doattachment, - help="Print selected attachment (single PR only)") + p.add_argument("-m", "--message", nargs=1, + action=CtorAppend, dest='selections', + const=Invocation.Selection.domessage, + help="Print selected message (single PR only)") + p.add_argument("-a", "--attachment", nargs=1, + action=CtorAppend, dest='selections', + const=Invocation.Selection.doattachment, + help="Print selected attachment (single PR only)") - p.add_argument("-r", "--raw", - action = 'store_const', const="RAW", - dest = 'output', - help="Print exactly what the database returns") - p.add_argument("-l", "--list", - action = 'store_const', const="LIST", - dest = 'output', - help="Print in list form (default)") - p.add_argument("--headers", - action = 'store_const', const="HEADERS", - dest = 'output', - help="Print header information only") - p.add_argument("--meta", - action = 'store_const', const="META", - dest = 'output', - help="Print all metadata") - p.add_argument("--metadata", - action = 'store_const', const="META", - dest = 'output') - p.add_argument("-f", "--full", - action = 'store_const', const="FULL", - dest = 'output', - help="Print everything") + p.add_argument("-r", "--raw", + action = 'store_const', const="RAW", + dest = 'output', + help="Print exactly what the database returns") + p.add_argument("-l", "--list", + action = 'store_const', const="LIST", + dest = 'output', + help="Print in list form (default)") + p.add_argument("--headers", + action = 'store_const', const="HEADERS", + dest = 'output', + help="Print header information only") + p.add_argument("--meta", + action = 'store_const', const="META", + dest = 'output', + help="Print all metadata") + p.add_argument("--metadata", + action = 'store_const', const="META", + dest = 'output') + p.add_argument("-f", "--full", + action = 'store_const', const="FULL", + dest = 'output', + help="Print everything") - p.add_argument("--text", - action = 'store_const', const="TEXT", - dest = 'outformat', - help="Print in text format (default)") - p.add_argument("--csv", - action = 'store_const', const="CSV", - dest = 'outformat', - help="Print a CSV file") - p.add_argument("--xml", - action = 'store_const', const="XML", - dest = 'outformat', - help="Print in XML") - p.add_argument("--json", - action = 'store_const', const="JSON", - dest = 'outformat', - help="Print in JSON") - p.add_argument("--rdf", - action = 'store_const', const="RDF", - dest = 'outbformat', - help="Print in RDF") - p.add_argument("--rdflike", - action = 'store_const', const="RDFLIKE", - dest = 'outformat', - help="Print RDF-like text") + p.add_argument("--text", + action = 'store_const', const="TEXT", + dest = 'outformat', + help="Print in text format (default)") + p.add_argument("--csv", + action = 'store_const', const="CSV", + dest = 'outformat', + help="Print a CSV file") + p.add_argument("--xml", + action = 'store_const', const="XML", + dest = 'outformat', + help="Print in XML") + p.add_argument("--json", + action = 'store_const', const="JSON", + dest = 'outformat', + help="Print in JSON") + p.add_argument("--rdf", + action = 'store_const', const="RDF", + dest = 'outbformat', + help="Print in RDF") + p.add_argument("--rdflike", + action = 'store_const', const="RDFLIKE", + dest = 'outformat', + help="Print RDF-like text") - p.add_argument("TERM", nargs='*', - action=CtorAppend, dest='queries', - const=Invocation.Query.doqstring, - help="Search term") + p.add_argument("TERM", nargs='*', + action=CtorAppend, dest='queries', + const=Invocation.Query.doqstring, + help="Search term") - args = p.parse_args() + args = p.parse_args() - ops = args.ops - if ops is None: - ops = [] - queries = args.queries - if queries is not None: - openonly = args.openonly - if openonly is None: - openonly = True - publiconly = args.publiconly - if publiconly is None: - publiconly = False - orders = args.orders - if orders is None: - orders = [Invocation.Order.dooldest(None)] - output = args.output - if output is None: - output = "LIST" - outformat = args.outformat - if outformat is None: - outformat = "TEXT" - selections = args.selections - if selections is None: - sel = Invocation.Selection.dopr(output, outformat) - selections = [sel] - search = Search(queries, openonly, publiconly, orders) - op = dosearch(search, selections) - ops.append(op) - # endif + ops = args.ops + if ops is None: + ops = [] + queries = args.queries + if queries is not None: + openonly = args.openonly + if openonly is None: + openonly = True + publiconly = args.publiconly + if publiconly is None: + publiconly = False + orders = args.orders + if orders is None: + orders = [Invocation.Order.dooldest(None)] + output = args.output + if output is None: + output = "LIST" + outformat = args.outformat + if outformat is None: + outformat = "TEXT" + selections = args.selections + if selections is None: + sel = Invocation.Selection.dopr(output, outformat) + selections = [sel] + search = Search(queries, openonly, publiconly, orders) + op = dosearch(search, selections) + ops.append(op) + # endif - return Invocation(ops) + return Invocation(ops) # end getargs ############################################################