# HG changeset patch # User Goffi # Date 1550265223 -3600 # Node ID 710de41da2f28cd789a0a319bc278dd7dc4bea95 # Parent d4a9a60bc650f34e36eb08df9b373ddef676420a jp (pubsub/node): new "import" command, to publish many nodes from an XML file diff -r d4a9a60bc650 -r 710de41da2f2 sat_frontends/jp/cmd_pubsub.py --- a/sat_frontends/jp/cmd_pubsub.py Fri Feb 15 22:13:43 2019 +0100 +++ b/sat_frontends/jp/cmd_pubsub.py Fri Feb 15 22:13:43 2019 +0100 @@ -315,6 +315,92 @@ ) +class NodeImport(base.CommandBase): + + def __init__(self, host): + super(NodeImport, self).__init__( + host, + "import", + use_pubsub=True, + pubsub_flags={C.NODE}, + help=_(u"import raw XML to a node"), + ) + self.need_loop = True + + def add_parser_options(self): + self.parser.add_argument( + "--admin", + action="store_true", + help=_(u"do a pubsub admin request, needed to change publisher"), + ) + self.parser.add_argument( + "import_file", + type=file, + help=_(u"path to the XML file with data to import. The file must contain " + u"whole XML of each item to import."), + ) + + def psItemsSendCb(self, item_ids): + self.disp(_(u'items published with id(s) {item_ids}').format( + item_ids=u', '.join(item_ids))) + self.host.quit() + + def start(self): + try: + element, etree = xml_tools.etreeParse(self, self.args.import_file, + reraise=True) + except Exception as e: + from lxml.etree import XMLSyntaxError + if isinstance(e, XMLSyntaxError) and e.code == 5: + # we have extra content, this probaby means that item are not wrapped + # so we wrap them here and try again + self.args.import_file.seek(0) + xml_buf = "" + self.args.import_file.read() + "" + element, etree = xml_tools.etreeParse(self, xml_buf) + + # we reverse element as we expect to have most recently published element first + # TODO: make this more explicit and add an option + element[:] = reversed(element) + + if not all([i.tag == '{http://jabber.org/protocol/pubsub}item' for i in element]): + self.disp( + _(u"You are not using list of pubsub items, we can't import this file"), + error=True) + self.host.quit(C.EXIT_DATA_ERROR) + + items = [etree.tostring(i, encoding="utf-8") for i in element] + if self.args.admin: + self.host.bridge.psAdminItemsSend( + self.args.service, + self.args.node, + items, + u"", + self.profile, + callback=partial(self.psItemsSendCb), + errback=partial( + self.errback, + msg=_(u"can't send item: {}"), + exit_code=C.EXIT_BRIDGE_ERRBACK, + ), + ) + else: + self.disp(_(u"Items are imported without using admin mode, publisher can't " + u"be changed")) + self.host.bridge.psItemsSend( + self.args.service, + self.args.node, + items, + u"", + self.profile, + callback=partial(self.psItemsSendCb), + errback=partial( + self.errback, + msg=_(u"can't send item: {}"), + exit_code=C.EXIT_BRIDGE_ERRBACK, + ), + ) + + class NodeAffiliationsGet(base.CommandBase): def __init__(self, host): base.CommandBase.__init__( @@ -696,6 +782,7 @@ NodePurge, NodeDelete, NodeSet, + NodeImport, NodeAffiliations, NodeSubscriptions, NodeSchema, diff -r d4a9a60bc650 -r 710de41da2f2 sat_frontends/jp/xml_tools.py --- a/sat_frontends/jp/xml_tools.py Fri Feb 15 22:13:43 2019 +0100 +++ b/sat_frontends/jp/xml_tools.py Fri Feb 15 22:13:43 2019 +0100 @@ -20,11 +20,13 @@ from sat.core.i18n import _ from sat_frontends.jp.constants import Const as C -def etreeParse(cmd, raw_xml): +def etreeParse(cmd, raw_xml, reraise=False): """Import lxml and parse raw XML @param cmd(CommandBase): current command instance @param raw_xml(file, str): an XML bytestring, string or file-like object + @param reraise(bool): if True, re raise exception on parse error instead of doing a + parser.error (which terminate the execution) @return (tuple(etree.Element, module): parsed element, etree module """ try: @@ -42,6 +44,8 @@ else: element = etree.parse(raw_xml).getroot() except Exception as e: + if reraise: + raise e cmd.parser.error( _(u"Can't parse the payload XML in input: {msg}").format(msg=e) )