mirror of https://github.com/moparisthebest/xeps
tooling: refactor commonly used stuff into xeplib.py
parent
8d32a212a8
commit
18fbef73b4
@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
import xml.etree.ElementTree as etree
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from xeplib import load_xepinfos, Status
|
||||
|
||||
|
||||
def get_deferred(accepted):
|
||||
now = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
threshold = now.replace(year=now.year - 1)
|
||||
|
||||
for number, info in sorted(accepted.items()):
|
||||
if info["status"] == Status.EXPERIMENTAL and "last_revision" in info:
|
||||
last_update = info["last_revision"]["date"]
|
||||
if last_update <= threshold:
|
||||
yield info
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Show the XEPs which need to be changed to deferred."
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-l", "--xeplist",
|
||||
type=argparse.FileType("rb"),
|
||||
default=None,
|
||||
help="XEP list to use (defaults to ./build/xeplist.xml)"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-m", "--modify",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Modify the XEP files in-place."
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.xeplist is None:
|
||||
args.xeplist = open("./build/xeplist.xml", "rb")
|
||||
|
||||
with args.xeplist as f:
|
||||
tree = etree.parse(f)
|
||||
|
||||
accepted, _ = load_xepinfos(tree)
|
||||
deferred = list(get_deferred(accepted))
|
||||
|
||||
for deferred_info in deferred:
|
||||
print(deferred_info["number"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -0,0 +1,138 @@
|
||||
import enum
|
||||
|
||||
import xml.dom.minidom
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Status(enum.Enum):
|
||||
PROTO = 'ProtoXEP'
|
||||
EXPERIMENTAL = 'Experimental'
|
||||
PROPOSED = 'Proposed'
|
||||
DRAFT = 'Draft'
|
||||
ACTIVE = 'Active'
|
||||
FINAL = 'Final'
|
||||
RETRACTED = 'Retracted'
|
||||
OBSOLETE = 'Obsolete'
|
||||
DEFERRED = 'Deferred'
|
||||
REJECTED = 'Rejected'
|
||||
DEPRECATED = 'Deprecated'
|
||||
|
||||
@classmethod
|
||||
def fromstr(cls, s):
|
||||
if s == "Proto" or s.lower() == "protoxep":
|
||||
s = "ProtoXEP"
|
||||
return cls(s)
|
||||
|
||||
|
||||
class Action(enum.Enum):
|
||||
PROTO = "Proposed XMPP Extension"
|
||||
NEW = "NEW"
|
||||
DRAFT = "DRAFT"
|
||||
ACTIVE = "ACTIVE"
|
||||
FINAL = "FINAL"
|
||||
RETRACT = "RETRACTED"
|
||||
OBSOLETE = "OBSOLETED"
|
||||
DEFER = "DEFERRED"
|
||||
UPDATE = "UPDATED"
|
||||
|
||||
@classmethod
|
||||
def fromstatus(cls, status):
|
||||
return {
|
||||
Status.EXPERIMENTAL: cls.NEW,
|
||||
Status.DRAFT: cls.DRAFT,
|
||||
Status.ACTIVE: cls.ACTIVE,
|
||||
Status.FINAL: cls.FINAL,
|
||||
Status.RETRACTED: cls.RETRACT,
|
||||
Status.OBSOLETED: cls.OBSOLETE,
|
||||
Status.DEPRECATED: cls.DEPRECATE,
|
||||
Status.DEFERRED: cls.DEFERRED,
|
||||
}[status]
|
||||
|
||||
|
||||
def load_xepinfo(el):
|
||||
accepted = el.get("accepted").lower() == "true"
|
||||
|
||||
info = {
|
||||
"title": el.find("title").text,
|
||||
"abstract": el.find("abstract").text,
|
||||
"type": el.find("type").text,
|
||||
"status": Status.fromstr(el.find("status").text),
|
||||
"approver": el.find("approver").text,
|
||||
"accepted": accepted,
|
||||
}
|
||||
|
||||
last_revision_el = el.find("last-revision")
|
||||
if last_revision_el is not None:
|
||||
last_revision = {
|
||||
"version": last_revision_el.find("version").text,
|
||||
"date": datetime.strptime(
|
||||
last_revision_el.find("date").text,
|
||||
"%Y-%m-%d",
|
||||
),
|
||||
"initials": None,
|
||||
"remark": None,
|
||||
}
|
||||
|
||||
initials_el = last_revision_el.find("initials")
|
||||
if initials_el is not None:
|
||||
last_revision["initials"] = initials_el.text
|
||||
|
||||
remark_el = last_revision_el.find("remark")
|
||||
if remark_el is not None:
|
||||
last_revision["remark"] = remark_el.text
|
||||
|
||||
info["last_revision"] = last_revision
|
||||
|
||||
sig = el.find("sig")
|
||||
if sig is not None:
|
||||
info["sig"] = sig.text
|
||||
|
||||
if accepted:
|
||||
info["number"] = int(el.find("number").text)
|
||||
else:
|
||||
info["protoname"] = el.find("proto-name").text
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def load_xepinfos(tree):
|
||||
accepted, protos = {}, {}
|
||||
for info_el in tree.getroot():
|
||||
info = load_xepinfo(info_el)
|
||||
if info["accepted"]:
|
||||
accepted[info["number"]] = info
|
||||
else:
|
||||
protos[info["protoname"]] = info
|
||||
|
||||
return accepted, protos
|
||||
|
||||
|
||||
def minidom_find_child(elem, child_tag):
|
||||
for child in elem.childNodes:
|
||||
if hasattr(child, "tagName") and child.tagName == child_tag:
|
||||
return child
|
||||
return None
|
||||
|
||||
|
||||
def minidom_find_header(document):
|
||||
header = minidom_find_child(document.documentElement, "header")
|
||||
if header is None:
|
||||
raise ValueError("cannot find <header/>")
|
||||
return header
|
||||
|
||||
|
||||
def minidom_get_text(elem):
|
||||
return "".join(
|
||||
child.nodeValue
|
||||
for child in elem.childNodes
|
||||
if isinstance(child, (xml.dom.minidom.Text,
|
||||
xml.dom.minidom.CDATASection))
|
||||
)
|
||||
|
||||
|
||||
def minidom_children(elem):
|
||||
return [
|
||||
child for child in elem.childNodes
|
||||
if isinstance(child, (xml.dom.minidom.Element))
|
||||
]
|
Loading…
Reference in New Issue